1------------------------------------------------------------------------------ 2-- -- 3-- GNAT RUN-TIME COMPONENTS -- 4-- -- 5-- A D A . C A L E N D A R -- 6-- -- 7-- S p e c -- 8-- -- 9-- Copyright (C) 1992-2021, Free Software Foundation, Inc. -- 10-- -- 11-- This specification is derived from the Ada Reference Manual for use with -- 12-- GNAT. The copyright notice above, and the license provisions that follow -- 13-- apply solely to the contents of the part following the private keyword. -- 14-- -- 15-- GNAT is free software; you can redistribute it and/or modify it under -- 16-- terms of the GNU General Public License as published by the Free Soft- -- 17-- ware Foundation; either version 3, or (at your option) any later ver- -- 18-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- 19-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- 20-- or FITNESS FOR A PARTICULAR PURPOSE. -- 21-- -- 22-- As a special exception under Section 7 of GPL version 3, you are granted -- 23-- additional permissions described in the GCC Runtime Library Exception, -- 24-- version 3.1, as published by the Free Software Foundation. -- 25-- -- 26-- You should have received a copy of the GNU General Public License and -- 27-- a copy of the GCC Runtime Library Exception along with this program; -- 28-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- 29-- <http://www.gnu.org/licenses/>. -- 30-- -- 31-- GNAT was originally developed by the GNAT team at New York University. -- 32-- Extensive contributions were provided by Ada Core Technologies Inc. -- 33-- -- 34------------------------------------------------------------------------------ 35 36package Ada.Calendar with 37 SPARK_Mode, 38 Abstract_State => (Clock_Time with Synchronous), 39 Initializes => Clock_Time 40is 41 42 type Time is private; 43 44 -- Declarations representing limits of allowed local time values. Note that 45 -- these do NOT constrain the possible stored values of time which may well 46 -- permit a larger range of times (this is explicitly allowed in Ada 95). 47 48 subtype Year_Number is Integer range 1901 .. 2399; 49 subtype Month_Number is Integer range 1 .. 12; 50 subtype Day_Number is Integer range 1 .. 31; 51 52 -- A Day_Duration value of 86_400.0 designates a new day 53 54 subtype Day_Duration is Duration range 0.0 .. 86_400.0; 55 56 function Clock return Time with 57 Volatile_Function, 58 Global => Clock_Time; 59 -- The returned time value is the number of nanoseconds since the start 60 -- of Ada time (1901-01-01 00:00:00.0 UTC). If leap seconds are enabled, 61 -- the result will contain all elapsed leap seconds since the start of 62 -- Ada time until now. 63 64 function Year (Date : Time) return Year_Number; 65 function Month (Date : Time) return Month_Number; 66 function Day (Date : Time) return Day_Number; 67 function Seconds (Date : Time) return Day_Duration; 68 -- SPARK Note: These routines, just like Split and Time_Of below, might use 69 -- the OS-specific timezone database that is typically stored in a file. 70 -- This side effect needs to be modeled, so there is no Global => null. 71 72 procedure Split 73 (Date : Time; 74 Year : out Year_Number; 75 Month : out Month_Number; 76 Day : out Day_Number; 77 Seconds : out Day_Duration); 78 -- Break down a time value into its date components set in the current 79 -- time zone. If Split is called on a time value created using Ada 2005 80 -- Time_Of in some arbitrary time zone, the input value will always be 81 -- interpreted as relative to the local time zone. 82 83 function Time_Of 84 (Year : Year_Number; 85 Month : Month_Number; 86 Day : Day_Number; 87 Seconds : Day_Duration := 0.0) return Time; 88 -- GNAT Note: Normally when procedure Split is called on a Time value 89 -- result of a call to function Time_Of, the out parameters of procedure 90 -- Split are identical to the in parameters of function Time_Of. However, 91 -- when a non-existent time of day is specified, the values for Seconds 92 -- may or may not be different. This may happen when Daylight Saving Time 93 -- (DST) is in effect, on the day when switching to DST, if Seconds 94 -- specifies a time of day in the hour that does not exist. For example, 95 -- in New York: 96 -- 97 -- Time_Of (Year => 1998, Month => 4, Day => 5, Seconds => 10740.0) 98 -- 99 -- will return a Time value T. If Split is called on T, the resulting 100 -- Seconds may be 14340.0 (3:59:00) instead of 10740.0 (2:59:00 being 101 -- a time that not exist). 102 103 function "+" (Left : Time; Right : Duration) return Time 104 with 105 Global => null; 106 function "+" (Left : Duration; Right : Time) return Time 107 with 108 Global => null; 109 function "-" (Left : Time; Right : Duration) return Time 110 with 111 Global => null; 112 function "-" (Left : Time; Right : Time) return Duration 113 with 114 Global => null; 115 -- The first three functions will raise Time_Error if the resulting time 116 -- value is less than the start of Ada time in UTC or greater than the 117 -- end of Ada time in UTC. The last function will raise Time_Error if the 118 -- resulting difference cannot fit into a duration value. 119 120 function "<" (Left, Right : Time) return Boolean with Global => null; 121 function "<=" (Left, Right : Time) return Boolean with Global => null; 122 function ">" (Left, Right : Time) return Boolean with Global => null; 123 function ">=" (Left, Right : Time) return Boolean with Global => null; 124 125 Time_Error : exception; 126 127private 128 -- Mark the private part as SPARK_Mode Off to avoid accounting for variable 129 -- Invalid_Time_Zone_Offset in abstract state. 130 131 pragma SPARK_Mode (Off); 132 133 pragma Inline (Clock); 134 135 pragma Inline (Year); 136 pragma Inline (Month); 137 pragma Inline (Day); 138 139 pragma Inline ("+"); 140 pragma Inline ("-"); 141 142 pragma Inline ("<"); 143 pragma Inline ("<="); 144 pragma Inline (">"); 145 pragma Inline (">="); 146 147 -- The units used in this version of Ada.Calendar are nanoseconds. The 148 -- following constants provide values used in conversions of seconds or 149 -- days to the underlying units. 150 151 Nano : constant := 1_000_000_000; 152 Nano_F : constant := 1_000_000_000.0; 153 Nanos_In_Day : constant := 86_400_000_000_000; 154 Secs_In_Day : constant := 86_400; 155 156 ---------------------------- 157 -- Implementation of Time -- 158 ---------------------------- 159 160 -- Time is represented as a signed 64 bit signed integer count of 161 -- nanoseconds since the "epoch" 2150-01-01 00:00:00 UTC. Thus a value of 0 162 -- represents the epoch. As of this writing, the epoch is in the future, 163 -- so Time values returned by Clock will be negative. 164 -- 165 -- Time values produced by Time_Of are internally normalized to UTC 166 -- regardless of their local time zone. This representation ensures correct 167 -- handling of leap seconds as well as performing arithmetic. In Ada 95, 168 -- Split and Time_Of will treat a time value as being in the local time 169 -- zone, in Ada 2005, Split and Time_Of will treat a time value as being in 170 -- the designated time zone by the formal parameter or in UTC by 171 -- default. The size of the type is large enough to cover the Ada 172 -- range of time (1901-01-01T00:00:00.0 UTC - 2399-12-31T23:59:59.999999999 173 -- UTC). 174 175 ------------------ 176 -- Leap Seconds -- 177 ------------------ 178 179 -- Due to Earth's slowdown, the astronomical time is not as precise as the 180 -- International Atomic Time. To compensate for this inaccuracy, a single 181 -- leap second is added after the last day of June or December. The count 182 -- of seconds during those occurrences becomes: 183 184 -- ... 58, 59, leap second 60, 0, 1, 2 ... 185 186 -- Unlike leap days, leap seconds occur simultaneously around the world. 187 -- In other words, if a leap second occurs at 23:59:60 UTC, it also occurs 188 -- on 18:59:60 -5 the same day or 2:59:60 +2 on the next day. 189 190 -- Leap seconds do not follow a formula. The International Earth Rotation 191 -- and Reference System Service decides when to add one. Leap seconds are 192 -- included in the representation of time in Ada 95 mode. As a result, 193 -- the following two time values will differ by two seconds: 194 195 -- 1972-06-30 23:59:59.0 196 -- 1972-07-01 00:00:00.0 197 198 -- When a new leap second is introduced, the following steps must be 199 -- carried out: 200 201 -- 1) Increment Leap_Seconds_Count in a-calend.adb by one 202 -- 2) Increment LS_Count in xleaps.adb by one 203 -- 3) Add the new date to the aggregate of array LS_Dates in 204 -- xleaps.adb 205 -- 4) Compile and execute xleaps 206 -- 5) Replace the values of Leap_Second_Times in a-calend.adb with the 207 -- aggregate generated by xleaps 208 209 -- The algorithms that build the actual leap second values and discover 210 -- how many leap seconds have occurred between two dates do not need any 211 -- modification. 212 213 ------------------------------ 214 -- Non-leap Centennial Years -- 215 ------------------------------ 216 217 -- Over the range of Ada time, centennial years 2100, 2200 and 2300 are 218 -- non-leap. As a consequence, seven non-leap years occur over the period 219 -- of year - 4 to year + 4. Internally, routines Split and Time_Of add or 220 -- subtract a "fake" February 29 to facilitate the arithmetic involved. 221 222 ------------------------ 223 -- Local Declarations -- 224 ------------------------ 225 226 type Time_Rep is new Long_Long_Integer; 227 type Time is new Time_Rep; 228 -- The underlying type of Time has been chosen to be a 64 bit signed 229 -- integer number since it allows for easier processing of sub-seconds 230 -- and arithmetic. We use Long_Long_Integer to allow this unit to compile 231 -- when using custom target configuration files where the max integer is 232 -- 32 bits. This is useful for static analysis tools such as SPARK or 233 -- CodePeer. 234 -- 235 -- Note: the reason we have two separate types here is to avoid problems 236 -- with overloading ambiguities in the body if we tried to use Time as an 237 -- internal computational type. 238 239 function Epoch_Offset return Time_Rep; 240 pragma Inline (Epoch_Offset); 241 -- Return the difference between our epoch and 1970-1-1 UTC (the Unix 242 -- epoch) expressed in nanoseconds. Note that year 2100 is non-leap. 243 244 Days_In_Month : constant array (Month_Number) of Day_Number := 245 [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; 246 -- Days in month for non-leap year, leap year case is adjusted in code 247 248 Invalid_Time_Zone_Offset : Long_Integer; 249 pragma Import (C, Invalid_Time_Zone_Offset, "__gnat_invalid_tzoff"); 250 251 function Is_Leap (Year : Year_Number) return Boolean; 252 -- Determine whether a given year is leap 253 254 ---------------------------------------------------------- 255 -- Target-Independent Interface to Children of Calendar -- 256 ---------------------------------------------------------- 257 258 -- The following packages provide a target-independent interface to the 259 -- children of Calendar - Arithmetic, Conversions, Delays, Formatting and 260 -- Time_Zones. 261 262 --------------------------- 263 -- Arithmetic_Operations -- 264 --------------------------- 265 266 package Arithmetic_Operations is 267 268 function Add (Date : Time; Days : Long_Integer) return Time; 269 -- Add a certain number of days to a time value 270 271 procedure Difference 272 (Left : Time; 273 Right : Time; 274 Days : out Long_Integer; 275 Seconds : out Duration; 276 Leap_Seconds : out Integer); 277 -- Calculate the difference between two time values in terms of days, 278 -- seconds and leap seconds elapsed. The leap seconds are not included 279 -- in the seconds returned. If Left is greater than Right, the returned 280 -- values are positive, negative otherwise. 281 282 function Subtract (Date : Time; Days : Long_Integer) return Time; 283 -- Subtract a certain number of days from a time value 284 285 end Arithmetic_Operations; 286 287 --------------------------- 288 -- Conversion_Operations -- 289 --------------------------- 290 291 package Conversion_Operations is 292 293 function To_Ada_Time (Unix_Time : Long_Integer) return Time; 294 -- Unix to Ada Epoch conversion 295 296 function To_Ada_Time 297 (tm_year : Integer; 298 tm_mon : Integer; 299 tm_day : Integer; 300 tm_hour : Integer; 301 tm_min : Integer; 302 tm_sec : Integer; 303 tm_isdst : Integer) return Time; 304 -- Struct tm to Ada Epoch conversion 305 306 function To_Duration 307 (tv_sec : Long_Integer; 308 tv_nsec : Long_Integer) return Duration; 309 -- Struct timespec to Duration conversion 310 311 procedure To_Struct_Timespec 312 (D : Duration; 313 tv_sec : out Long_Integer; 314 tv_nsec : out Long_Integer); 315 -- Duration to struct timespec conversion 316 317 procedure To_Struct_Tm 318 (T : Time; 319 tm_year : out Integer; 320 tm_mon : out Integer; 321 tm_day : out Integer; 322 tm_hour : out Integer; 323 tm_min : out Integer; 324 tm_sec : out Integer); 325 -- Time to struct tm conversion 326 327 function To_Unix_Time (Ada_Time : Time) return Long_Integer; 328 -- Ada to Unix Epoch conversion 329 330 end Conversion_Operations; 331 332 ---------------------- 333 -- Delay_Operations -- 334 ---------------------- 335 336 package Delay_Operations is 337 338 function To_Duration (Date : Time) return Duration; 339 -- Given a time value in nanoseconds since 1901, convert it into a 340 -- duration value giving the number of nanoseconds since the Unix Epoch. 341 342 end Delay_Operations; 343 344 --------------------------- 345 -- Formatting_Operations -- 346 --------------------------- 347 348 package Formatting_Operations is 349 350 function Day_Of_Week (Date : Time) return Integer; 351 -- Determine which day of week Date falls on. The returned values are 352 -- within the range of 0 .. 6 (Monday .. Sunday). 353 354 procedure Split 355 (Date : Time; 356 Year : out Year_Number; 357 Month : out Month_Number; 358 Day : out Day_Number; 359 Day_Secs : out Day_Duration; 360 Hour : out Integer; 361 Minute : out Integer; 362 Second : out Integer; 363 Sub_Sec : out Duration; 364 Leap_Sec : out Boolean; 365 Use_TZ : Boolean; 366 Is_Historic : Boolean; 367 Time_Zone : Long_Integer); 368 pragma Export (Ada, Split, "__gnat_split"); 369 -- Split a time value into its components. If flag Is_Historic is set, 370 -- this routine would try to use to the best of the OS's abilities the 371 -- time zone offset that was or will be in effect on Date. Set Use_TZ 372 -- to use the local time zone (the value in Time_Zone is ignored) when 373 -- splitting a time value. 374 375 function Time_Of 376 (Year : Year_Number; 377 Month : Month_Number; 378 Day : Day_Number; 379 Day_Secs : Day_Duration; 380 Hour : Integer; 381 Minute : Integer; 382 Second : Integer; 383 Sub_Sec : Duration; 384 Leap_Sec : Boolean; 385 Use_Day_Secs : Boolean; 386 Use_TZ : Boolean; 387 Is_Historic : Boolean; 388 Time_Zone : Long_Integer) return Time; 389 pragma Export (Ada, Time_Of, "__gnat_time_of"); 390 -- Given all the components of a date, return the corresponding time 391 -- value. Set Use_Day_Secs to use the value in Day_Secs, otherwise the 392 -- day duration will be calculated from Hour, Minute, Second and Sub_ 393 -- Sec. If flag Is_Historic is set, this routine would try to use to the 394 -- best of the OS's abilities the time zone offset that was or will be 395 -- in effect on the input date. Set Use_TZ to use the local time zone 396 -- (the value in formal Time_Zone is ignored) when building a time value 397 -- and to verify the validity of a requested leap second. 398 399 end Formatting_Operations; 400 401 --------------------------- 402 -- Time_Zones_Operations -- 403 --------------------------- 404 405 package Time_Zones_Operations is 406 407 function UTC_Time_Offset (Date : Time) return Long_Integer; 408 -- Return (in seconds) the difference between the local time zone and 409 -- UTC time at a specific historic date. 410 411 end Time_Zones_Operations; 412 413end Ada.Calendar; 414