1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- A D A . C A L E N D A R --
9 -- Copyright (C) 1992-2007, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
34 -- This is the Alpha/VMS version
36 with System.Aux_DEC; use System.Aux_DEC;
38 with Ada.Unchecked_Conversion;
40 package body Ada.Calendar is
42 --------------------------
43 -- Implementation Notes --
44 --------------------------
46 -- Variables of type Ada.Calendar.Time have suffix _S or _M to denote
47 -- units of seconds or milis.
49 -- Because time is measured in different units and from different origins
50 -- on various targets, a system independent model is incorporated into
51 -- Ada.Calendar. The idea behing the design is to encapsulate all target
52 -- dependent machinery in a single package, thus providing a uniform
53 -- interface to all existing and any potential children.
55 -- package Ada.Calendar
56 -- procedure Split (5 parameters) -------+
57 -- | Call from local routine
59 -- package Formatting_Operations |
60 -- procedure Split (11 parameters) <--+
61 -- end Formatting_Operations |
64 -- package Ada.Calendar.Formatting | Call from child routine
65 -- procedure Split (9 or 10 parameters) -+
66 -- end Ada.Calendar.Formatting
68 -- The behaviour of the interfacing routines is controlled via various
69 -- flags. All new Ada 2005 types from children of Ada.Calendar are
70 -- emulated by a similar type. For instance, type Day_Number is replaced
71 -- by Integer in various routines. One ramification of this model is that
72 -- the caller site must perform validity checks on returned results.
73 -- The end result of this model is the lack of target specific files per
74 -- child of Ada.Calendar (a-calfor, a-calfor-vms, a-calfor-vxwors, etc).
76 -----------------------
77 -- Local Subprograms --
78 -----------------------
80 procedure Check_Within_Time_Bounds (T : Time);
81 -- Ensure that a time representation value falls withing the bounds of Ada
82 -- time. Leap seconds support is taken into account.
84 procedure Cumulative_Leap_Seconds
87 Elapsed_Leaps : out Natural;
88 Next_Leap_Sec : out Time);
89 -- Elapsed_Leaps is the sum of the leap seconds that have occured on or
90 -- after Start_Date and before (strictly before) End_Date. Next_Leap_Sec
91 -- represents the next leap second occurence on or after End_Date. If
92 -- there are no leaps seconds after End_Date, End_Of_Time is returned.
93 -- End_Of_Time can be used as End_Date to count all the leap seconds that
94 -- have occured on or after Start_Date.
96 -- Note: Any sub seconds of Start_Date and End_Date are discarded before
97 -- the calculations are done. For instance: if 113 seconds is a leap
98 -- second (it isn't) and 113.5 is input as an End_Date, the leap second
99 -- at 113 will not be counted in Leaps_Between, but it will be returned
100 -- as Next_Leap_Sec. Thus, if the caller wants to know if the End_Date is
101 -- a leap second, the comparison should be:
103 -- End_Date >= Next_Leap_Sec;
105 -- After_Last_Leap is designed so that this comparison works without
106 -- having to first check if Next_Leap_Sec is a valid leap second.
108 function To_Duration (T : Time) return Duration;
109 function To_Relative_Time (D : Duration) return Time;
110 -- It is important to note that duration's fractional part denotes nano
111 -- seconds while the units of Time are 100 nanoseconds. If a regular
112 -- Unchecked_Conversion was employed, the resulting values would be off
115 ---------------------
116 -- Local Constants --
117 ---------------------
119 -- Currently none of the GNAT targets support leap seconds. At some point
120 -- it might be necessary to query a C function to determine if the target
121 -- supports leap seconds, but for now this is deemed unnecessary.
123 Leap_Support : constant Boolean := False;
124 Leap_Seconds_Count : constant Natural := 23;
126 -- The range of Ada time expressed as milis since the VMS Epoch
128 Ada_Low : constant Time := (10 * 366 + 32 * 365 + 45) * Milis_In_Day;
129 Ada_High : constant Time := (131 * 366 + 410 * 365 + 45) * Milis_In_Day;
131 -- Even though the upper bound of time is 2399-12-31 23:59:59.9999999
132 -- UTC, it must be increased to include all leap seconds.
134 Ada_High_And_Leaps : constant Time :=
135 Ada_High + Time (Leap_Seconds_Count) * Mili;
137 -- Two constants used in the calculations of elapsed leap seconds.
138 -- End_Of_Time is later than Ada_High in time zone -28. Start_Of_Time
139 -- is earlier than Ada_Low in time zone +28.
141 End_Of_Time : constant Time := Ada_High + Time (3) * Milis_In_Day;
142 Start_Of_Time : constant Time := Ada_Low - Time (3) * Milis_In_Day;
144 Cumulative_Days_Before_Month :
145 constant array (Month_Number) of Natural :=
146 (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
148 Leap_Second_Times : array (1 .. Leap_Seconds_Count) of Time;
149 -- Each value represents a time value which is one second before a leap
150 -- second occurence. This table is populated during the elaboration of
157 function "+" (Left : Time; Right : Duration) return Time is
158 pragma Unsuppress (Overflow_Check);
160 return Left + To_Relative_Time (Right);
162 when Constraint_Error =>
166 function "+" (Left : Duration; Right : Time) return Time is
167 pragma Unsuppress (Overflow_Check);
171 when Constraint_Error =>
179 function "-" (Left : Time; Right : Duration) return Time is
180 pragma Unsuppress (Overflow_Check);
182 return Left - To_Relative_Time (Right);
184 when Constraint_Error =>
188 function "-" (Left : Time; Right : Time) return Duration is
189 pragma Unsuppress (Overflow_Check);
191 -- The bound of type Duration expressed as time
193 Dur_High : constant Time := To_Relative_Time (Duration'Last);
194 Dur_Low : constant Time := To_Relative_Time (Duration'First);
199 Res_M := Left - Right;
201 -- Due to the extended range of Ada time, "-" is capable of producing
202 -- results which may exceed the range of Duration. In order to prevent
203 -- the generation of bogus values by the Unchecked_Conversion, we apply
204 -- the following check.
207 or else Res_M >= Dur_High
211 -- Normal case, result fits
214 return To_Duration (Res_M);
218 when Constraint_Error =>
226 function "<" (Left, Right : Time) return Boolean is
228 return Long_Integer (Left) < Long_Integer (Right);
235 function "<=" (Left, Right : Time) return Boolean is
237 return Long_Integer (Left) <= Long_Integer (Right);
244 function ">" (Left, Right : Time) return Boolean is
246 return Long_Integer (Left) > Long_Integer (Right);
253 function ">=" (Left, Right : Time) return Boolean is
255 return Long_Integer (Left) >= Long_Integer (Right);
258 ------------------------------
259 -- Check_Within_Time_Bounds --
260 ------------------------------
262 procedure Check_Within_Time_Bounds (T : Time) is
265 if T < Ada_Low or else T > Ada_High_And_Leaps then
269 if T < Ada_Low or else T > Ada_High then
273 end Check_Within_Time_Bounds;
279 function Clock return Time is
280 Elapsed_Leaps : Natural;
282 Res_M : constant Time := Time (OSP.OS_Clock);
285 -- Note that on other targets a soft-link is used to get a different
286 -- clock depending whether tasking is used or not. On VMS this isn't
287 -- needed since all clock calls end up using SYS$GETTIM, so call the
288 -- OS_Primitives version for efficiency.
290 -- If the target supports leap seconds, determine the number of leap
291 -- seconds elapsed until this moment.
294 Cumulative_Leap_Seconds
295 (Start_Of_Time, Res_M, Elapsed_Leaps, Next_Leap_M);
297 -- The system clock may fall exactly on a leap second
299 if Res_M >= Next_Leap_M then
300 Elapsed_Leaps := Elapsed_Leaps + 1;
303 -- The target does not support leap seconds
309 return Res_M + Time (Elapsed_Leaps) * Mili;
312 -----------------------------
313 -- Cumulative_Leap_Seconds --
314 -----------------------------
316 procedure Cumulative_Leap_Seconds
319 Elapsed_Leaps : out Natural;
320 Next_Leap_Sec : out Time)
322 End_Index : Positive;
323 End_T : Time := End_Date;
324 Start_Index : Positive;
325 Start_T : Time := Start_Date;
328 pragma Assert (Leap_Support and then End_Date >= Start_Date);
330 Next_Leap_Sec := End_Of_Time;
332 -- Make sure that the end date does not excede the upper bound
335 if End_Date > Ada_High then
339 -- Remove the sub seconds from both dates
341 Start_T := Start_T - (Start_T mod Mili);
342 End_T := End_T - (End_T mod Mili);
344 -- Some trivial cases:
345 -- Leap 1 . . . Leap N
346 -- ---+========+------+############+-------+========+-----
347 -- Start_T End_T Start_T End_T
349 if End_T < Leap_Second_Times (1) then
351 Next_Leap_Sec := Leap_Second_Times (1);
354 elsif Start_T > Leap_Second_Times (Leap_Seconds_Count) then
356 Next_Leap_Sec := End_Of_Time;
360 -- Perform the calculations only if the start date is within the leap
361 -- second occurences table.
363 if Start_T <= Leap_Second_Times (Leap_Seconds_Count) then
366 -- +----+----+-- . . . --+-------+---+
367 -- | T1 | T2 | | N - 1 | N |
368 -- +----+----+-- . . . --+-------+---+
370 -- | Start_Index | End_Index
371 -- +-------------------+
374 -- The idea behind the algorithm is to iterate and find two closest
375 -- dates which are after Start_T and End_T. Their corresponding
376 -- index difference denotes the number of leap seconds elapsed.
380 exit when Leap_Second_Times (Start_Index) >= Start_T;
381 Start_Index := Start_Index + 1;
384 End_Index := Start_Index;
386 exit when End_Index > Leap_Seconds_Count
387 or else Leap_Second_Times (End_Index) >= End_T;
388 End_Index := End_Index + 1;
391 if End_Index <= Leap_Seconds_Count then
392 Next_Leap_Sec := Leap_Second_Times (End_Index);
395 Elapsed_Leaps := End_Index - Start_Index;
400 end Cumulative_Leap_Seconds;
406 function Day (Date : Time) return Day_Number is
412 Split (Date, Y, M, D, S);
420 function Is_Leap (Year : Year_Number) return Boolean is
422 -- Leap centenial years
424 if Year mod 400 = 0 then
427 -- Non-leap centenial years
429 elsif Year mod 100 = 0 then
435 return Year mod 4 = 0;
443 function Month (Date : Time) return Month_Number is
449 Split (Date, Y, M, D, S);
457 function Seconds (Date : Time) return Day_Duration is
463 Split (Date, Y, M, D, S);
473 Year : out Year_Number;
474 Month : out Month_Number;
475 Day : out Day_Number;
476 Seconds : out Day_Duration)
485 -- Use UTC as the local time zone on VMS, the status of flag Is_Ada_05
486 -- is irrelevant in this case.
488 Formatting_Operations.Split
505 or else not Month'Valid
506 or else not Day'Valid
507 or else not Seconds'Valid
519 Month : Month_Number;
521 Seconds : Day_Duration := 0.0) return Time
523 -- The values in the following constants are irrelevant, they are just
524 -- placeholders; the choice of constructing a Day_Duration value is
525 -- controlled by the Use_Day_Secs flag.
527 H : constant Integer := 1;
528 M : constant Integer := 1;
529 Se : constant Integer := 1;
530 Ss : constant Duration := 0.1;
534 or else not Month'Valid
535 or else not Day'Valid
536 or else not Seconds'Valid
541 -- Use UTC as the local time zone on VMS, the status of flag Is_Ada_05
542 -- is irrelevant in this case.
545 Formatting_Operations.Time_Of
555 Use_Day_Secs => True,
564 function To_Duration (T : Time) return Duration is
565 function Time_To_Duration is
566 new Ada.Unchecked_Conversion (Time, Duration);
568 return Time_To_Duration (T * 100);
571 ----------------------
572 -- To_Relative_Time --
573 ----------------------
575 function To_Relative_Time (D : Duration) return Time is
576 function Duration_To_Time is
577 new Ada.Unchecked_Conversion (Duration, Time);
579 return Duration_To_Time (D / 100.0);
580 end To_Relative_Time;
586 function Year (Date : Time) return Year_Number is
592 Split (Date, Y, M, D, S);
596 -- The following packages assume that Time is a Long_Integer, the units
597 -- are 100 nanoseconds and the starting point in the VMS Epoch.
599 ---------------------------
600 -- Arithmetic_Operations --
601 ---------------------------
603 package body Arithmetic_Operations is
609 function Add (Date : Time; Days : Long_Integer) return Time is
610 pragma Unsuppress (Overflow_Check);
612 return Date + Time (Days) * Milis_In_Day;
614 when Constraint_Error =>
625 Days : out Long_Integer;
626 Seconds : out Duration;
627 Leap_Seconds : out Integer)
629 Mili_F : constant Duration := 10_000_000.0;
634 Elapsed_Leaps : Natural;
636 Negate : Boolean := False;
638 Sub_Seconds : Duration;
641 -- This classification is necessary in order to avoid a Time_Error
642 -- being raised by the arithmetic operators in Ada.Calendar.
644 if Left >= Right then
653 -- If the target supports leap seconds, process them
656 Cumulative_Leap_Seconds
657 (Earlier, Later, Elapsed_Leaps, Next_Leap);
659 if Later >= Next_Leap then
660 Elapsed_Leaps := Elapsed_Leaps + 1;
663 -- The target does not support leap seconds
669 Diff_M := Later - Earlier - Time (Elapsed_Leaps) * Mili;
671 -- Sub second processing
673 Sub_Seconds := Duration (Diff_M mod Mili) / Mili_F;
675 -- Convert to seconds. Note that his action eliminates the sub
676 -- seconds automatically.
678 Diff_S := Diff_M / Mili;
680 Days := Long_Integer (Diff_S / Secs_In_Day);
681 Seconds := Duration (Diff_S mod Secs_In_Day) + Sub_Seconds;
682 Leap_Seconds := Integer (Elapsed_Leaps);
688 if Leap_Seconds /= 0 then
689 Leap_Seconds := -Leap_Seconds;
698 function Subtract (Date : Time; Days : Long_Integer) return Time is
699 pragma Unsuppress (Overflow_Check);
701 return Date - Time (Days) * Milis_In_Day;
703 when Constraint_Error =>
706 end Arithmetic_Operations;
708 ---------------------------
709 -- Formatting_Operations --
710 ---------------------------
712 package body Formatting_Operations is
718 function Day_Of_Week (Date : Time) return Integer is
724 Day_Count : Long_Integer;
725 Midday_Date_S : Time;
728 Split (Date, Y, M, D, S);
730 -- Build a time value in the middle of the same day and convert the
731 -- time value to seconds.
733 Midday_Date_S := Time_Of (Y, M, D, 43_200.0) / Mili;
735 -- Count the number of days since the start of VMS time. 1858-11-17
738 Day_Count := Long_Integer (Midday_Date_S / Secs_In_Day) + 2;
740 return Integer (Day_Count mod 7);
749 Year : out Year_Number;
750 Month : out Month_Number;
751 Day : out Day_Number;
752 Day_Secs : out Day_Duration;
754 Minute : out Integer;
755 Second : out Integer;
756 Sub_Sec : out Duration;
757 Leap_Sec : out Boolean;
759 Time_Zone : Long_Integer)
761 -- The flag Is_Ada_05 is present for interfacing purposes
763 pragma Unreferenced (Is_Ada_05);
766 (Status : out Unsigned_Longword;
767 Timbuf : out Unsigned_Word_Array;
770 pragma Interface (External, Numtim);
772 pragma Import_Valued_Procedure
773 (Numtim, "SYS$NUMTIM",
774 (Unsigned_Longword, Unsigned_Word_Array, Time),
775 (Value, Reference, Reference));
777 Status : Unsigned_Longword;
778 Timbuf : Unsigned_Word_Array (1 .. 7);
780 Ada_Min_Year : constant := 1901;
781 Ada_Max_Year : constant := 2399;
782 Mili_F : constant Duration := 10_000_000.0;
785 Elapsed_Leaps : Natural;
791 -- Step 1: Leap seconds processing
794 Cumulative_Leap_Seconds
795 (Start_Of_Time, Date, Elapsed_Leaps, Next_Leap_M);
797 Leap_Sec := Date_M >= Next_Leap_M;
800 Elapsed_Leaps := Elapsed_Leaps + 1;
803 -- The target does not support leap seconds
810 Date_M := Date_M - Time (Elapsed_Leaps) * Mili;
812 -- Step 2: Time zone processing
814 if Time_Zone /= 0 then
815 Date_M := Date_M + Time (Time_Zone) * 60 * Mili;
818 -- After the leap seconds and time zone have been accounted for,
819 -- the date should be within the bounds of Ada time.
822 or else Date_M > Ada_High
827 -- Step 3: Sub second processing
829 Sub_Sec := Duration (Date_M mod Mili) / Mili_F;
831 -- Drop the sub seconds
833 Date_M := Date_M - (Date_M mod Mili);
835 -- Step 4: VMS system call
837 Numtim (Status, Timbuf, Date_M);
840 or else Timbuf (1) not in Ada_Min_Year .. Ada_Max_Year
845 -- Step 5: Time components processing
847 Year := Year_Number (Timbuf (1));
848 Month := Month_Number (Timbuf (2));
849 Day := Day_Number (Timbuf (3));
850 Hour := Integer (Timbuf (4));
851 Minute := Integer (Timbuf (5));
852 Second := Integer (Timbuf (6));
854 Day_Secs := Day_Duration (Hour * 3_600) +
855 Day_Duration (Minute * 60) +
856 Day_Duration (Second) +
866 Month : Month_Number;
868 Day_Secs : Day_Duration;
874 Use_Day_Secs : Boolean;
876 Time_Zone : Long_Integer) return Time
879 (Status : out Unsigned_Longword;
880 Input_Time : Unsigned_Word_Array;
881 Resultant_Time : out Time);
883 pragma Interface (External, Cvt_Vectim);
885 pragma Import_Valued_Procedure
886 (Cvt_Vectim, "LIB$CVT_VECTIM",
887 (Unsigned_Longword, Unsigned_Word_Array, Time),
888 (Value, Reference, Reference));
890 Status : Unsigned_Longword;
891 Timbuf : Unsigned_Word_Array (1 .. 7);
893 Mili_F : constant := 10_000_000.0;
895 Y : Year_Number := Year;
896 Mo : Month_Number := Month;
897 D : Day_Number := Day;
899 Mi : Integer := Minute;
900 Se : Integer := Second;
901 Su : Duration := Sub_Sec;
903 Elapsed_Leaps : Natural;
904 Int_Day_Secs : Integer;
907 Rounded_Res_M : Time;
910 -- No validity checks are performed on the input values since it is
911 -- assumed that the called has already performed them.
913 -- Step 1: Hour, minute, second and sub second processing
917 -- A day seconds value of 86_400 designates a new day
919 if Day_Secs = 86_400.0 then
921 Adj_Year : Year_Number := Year;
922 Adj_Month : Month_Number := Month;
923 Adj_Day : Day_Number := Day;
926 if Day < Days_In_Month (Month)
928 and then Is_Leap (Year))
932 -- The day adjustment moves the date to a new month
938 Adj_Month := Month + 1;
940 -- The month adjustment moves the date to a new year
944 Adj_Year := Year + 1;
957 -- Normal case (not exactly one day)
960 -- Sub second extraction
962 if Day_Secs > 0.0 then
963 Int_Day_Secs := Integer (Day_Secs - 0.5);
965 Int_Day_Secs := Integer (Day_Secs);
968 H := Int_Day_Secs / 3_600;
969 Mi := (Int_Day_Secs / 60) mod 60;
970 Se := Int_Day_Secs mod 60;
971 Su := Day_Secs - Duration (Int_Day_Secs);
975 -- Step 2: System call to VMS
977 Timbuf (1) := Unsigned_Word (Y);
978 Timbuf (2) := Unsigned_Word (Mo);
979 Timbuf (3) := Unsigned_Word (D);
980 Timbuf (4) := Unsigned_Word (H);
981 Timbuf (5) := Unsigned_Word (Mi);
982 Timbuf (6) := Unsigned_Word (Se);
985 Cvt_Vectim (Status, Timbuf, Res_M);
987 if Status mod 2 /= 1 then
991 -- Step 3: Sub second adjustment
993 Res_M := Res_M + Time (Su * Mili_F);
995 -- Step 4: Bounds check
997 Check_Within_Time_Bounds (Res_M);
999 -- Step 5: Time zone processing
1001 if Time_Zone /= 0 then
1002 Res_M := Res_M - Time (Time_Zone) * 60 * Mili;
1005 -- Step 6: Leap seconds processing
1007 if Leap_Support then
1008 Cumulative_Leap_Seconds
1009 (Start_Of_Time, Res_M, Elapsed_Leaps, Next_Leap_M);
1011 Res_M := Res_M + Time (Elapsed_Leaps) * Mili;
1013 -- An Ada 2005 caller requesting an explicit leap second or an
1014 -- Ada 95 caller accounting for an invisible leap second.
1017 or else Res_M >= Next_Leap_M
1019 Res_M := Res_M + Time (1) * Mili;
1022 -- Leap second validity check
1024 Rounded_Res_M := Res_M - (Res_M mod Mili);
1028 and then Rounded_Res_M /= Next_Leap_M
1036 end Formatting_Operations;
1038 ---------------------------
1039 -- Time_Zones_Operations --
1040 ---------------------------
1042 package body Time_Zones_Operations is
1044 ---------------------
1045 -- UTC_Time_Offset --
1046 ---------------------
1048 function UTC_Time_Offset (Date : Time) return Long_Integer is
1049 -- Formal parameter Date is here for interfacing, but is never
1052 pragma Unreferenced (Date);
1054 function get_gmtoff return Long_Integer;
1055 pragma Import (C, get_gmtoff, "get_gmtoff");
1058 -- VMS is not capable of determining the time zone in some past or
1059 -- future point in time denoted by Date, thus the current time zone
1063 end UTC_Time_Offset;
1064 end Time_Zones_Operations;
1066 -- Start of elaboration code for Ada.Calendar
1069 -- Population of the leap seconds table
1071 if Leap_Support then
1073 type Leap_Second_Date is record
1075 Month : Month_Number;
1080 constant array (1 .. Leap_Seconds_Count) of Leap_Second_Date :=
1081 ((1972, 6, 30), (1972, 12, 31), (1973, 12, 31), (1974, 12, 31),
1082 (1975, 12, 31), (1976, 12, 31), (1977, 12, 31), (1978, 12, 31),
1083 (1979, 12, 31), (1981, 6, 30), (1982, 6, 30), (1983, 6, 30),
1084 (1985, 6, 30), (1987, 12, 31), (1989, 12, 31), (1990, 12, 31),
1085 (1992, 6, 30), (1993, 6, 30), (1994, 6, 30), (1995, 12, 31),
1086 (1997, 6, 30), (1998, 12, 31), (2005, 12, 31));
1088 Ada_Min_Year : constant Year_Number := Year_Number'First;
1089 Days_In_Four_Years : constant := 365 * 3 + 366;
1090 VMS_Days : constant := 10 * 366 + 32 * 365 + 45;
1093 Leap : Leap_Second_Date;
1097 for Index in 1 .. Leap_Seconds_Count loop
1098 Leap := Leap_Second_Dates (Index);
1100 -- Calculate the number of days from the start of Ada time until
1101 -- the current leap second occurence. Non-leap centenial years
1102 -- are not accounted for in these calculations since there are
1103 -- no leap seconds after 2100 yet.
1105 Years := Leap.Year - Ada_Min_Year;
1106 Days := (Years / 4) * Days_In_Four_Years;
1107 Years := Years mod 4;
1112 elsif Years = 2 then
1113 Days := Days + 365 * 2;
1115 elsif Years = 3 then
1116 Days := Days + 365 * 3;
1119 Days := Days + Cumulative_Days_Before_Month (Leap.Month);
1121 if Is_Leap (Leap.Year)
1122 and then Leap.Month > 2
1127 -- Add the number of days since the start of VMS time till the
1128 -- start of Ada time.
1130 Days := Days + Leap.Day + VMS_Days;
1132 -- Index - 1 previous leap seconds are added to Time (Index)
1134 Leap_Second_Times (Index) :=
1135 (Time (Days) * Secs_In_Day + Time (Index - 1)) * Mili;