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);
165 if Right = Duration (0.0) then
169 Res_M := Left + To_Relative_Time (Right);
171 Check_Within_Time_Bounds (Res_M);
176 when Constraint_Error =>
180 function "+" (Left : Duration; Right : Time) return Time is
181 pragma Unsuppress (Overflow_Check);
185 when Constraint_Error =>
193 function "-" (Left : Time; Right : Duration) return Time is
194 pragma Unsuppress (Overflow_Check);
201 if Right = Duration (0.0) then
205 Res_M := Left - To_Relative_Time (Right);
207 Check_Within_Time_Bounds (Res_M);
212 when Constraint_Error =>
216 function "-" (Left : Time; Right : Time) return Duration is
217 pragma Unsuppress (Overflow_Check);
219 -- The bound of type Duration expressed as time
221 Dur_High : constant Time := To_Relative_Time (Duration'Last);
222 Dur_Low : constant Time := To_Relative_Time (Duration'First);
227 Res_M := Left - Right;
229 -- The result does not fit in a duration value
232 or else Res_M >= Dur_High
237 return To_Duration (Res_M);
239 when Constraint_Error =>
247 function "<" (Left, Right : Time) return Boolean is
249 return Long_Integer (Left) < Long_Integer (Right);
256 function "<=" (Left, Right : Time) return Boolean is
258 return Long_Integer (Left) <= Long_Integer (Right);
265 function ">" (Left, Right : Time) return Boolean is
267 return Long_Integer (Left) > Long_Integer (Right);
274 function ">=" (Left, Right : Time) return Boolean is
276 return Long_Integer (Left) >= Long_Integer (Right);
279 ------------------------------
280 -- Check_Within_Time_Bounds --
281 ------------------------------
283 procedure Check_Within_Time_Bounds (T : Time) is
286 if T < Ada_Low or else T > Ada_High_And_Leaps then
290 if T < Ada_Low or else T > Ada_High then
294 end Check_Within_Time_Bounds;
300 function Clock return Time is
301 Elapsed_Leaps : Natural;
303 Res_M : constant Time := Time (OSP.OS_Clock);
306 -- Note that on other targets a soft-link is used to get a different
307 -- clock depending whether tasking is used or not. On VMS this isn't
308 -- needed since all clock calls end up using SYS$GETTIM, so call the
309 -- OS_Primitives version for efficiency.
311 -- If the target supports leap seconds, determine the number of leap
312 -- seconds elapsed until this moment.
315 Cumulative_Leap_Seconds
316 (Start_Of_Time, Res_M, Elapsed_Leaps, Next_Leap_M);
318 -- The system clock may fall exactly on a leap second
320 if Res_M >= Next_Leap_M then
321 Elapsed_Leaps := Elapsed_Leaps + 1;
324 -- The target does not support leap seconds
330 return Res_M + Time (Elapsed_Leaps) * Mili;
333 -----------------------------
334 -- Cumulative_Leap_Seconds --
335 -----------------------------
337 procedure Cumulative_Leap_Seconds
340 Elapsed_Leaps : out Natural;
341 Next_Leap_Sec : out Time)
343 End_Index : Positive;
344 End_T : Time := End_Date;
345 Start_Index : Positive;
346 Start_T : Time := Start_Date;
349 pragma Assert (Leap_Support and then End_Date >= Start_Date);
351 Next_Leap_Sec := End_Of_Time;
353 -- Make sure that the end date does not excede the upper bound
356 if End_Date > Ada_High then
360 -- Remove the sub seconds from both dates
362 Start_T := Start_T - (Start_T mod Mili);
363 End_T := End_T - (End_T mod Mili);
365 -- Some trivial cases:
366 -- Leap 1 . . . Leap N
367 -- ---+========+------+############+-------+========+-----
368 -- Start_T End_T Start_T End_T
370 if End_T < Leap_Second_Times (1) then
372 Next_Leap_Sec := Leap_Second_Times (1);
375 elsif Start_T > Leap_Second_Times (Leap_Seconds_Count) then
377 Next_Leap_Sec := End_Of_Time;
381 -- Perform the calculations only if the start date is within the leap
382 -- second occurences table.
384 if Start_T <= Leap_Second_Times (Leap_Seconds_Count) then
387 -- +----+----+-- . . . --+-------+---+
388 -- | T1 | T2 | | N - 1 | N |
389 -- +----+----+-- . . . --+-------+---+
391 -- | Start_Index | End_Index
392 -- +-------------------+
395 -- The idea behind the algorithm is to iterate and find two closest
396 -- dates which are after Start_T and End_T. Their corresponding
397 -- index difference denotes the number of leap seconds elapsed.
401 exit when Leap_Second_Times (Start_Index) >= Start_T;
402 Start_Index := Start_Index + 1;
405 End_Index := Start_Index;
407 exit when End_Index > Leap_Seconds_Count
408 or else Leap_Second_Times (End_Index) >= End_T;
409 End_Index := End_Index + 1;
412 if End_Index <= Leap_Seconds_Count then
413 Next_Leap_Sec := Leap_Second_Times (End_Index);
416 Elapsed_Leaps := End_Index - Start_Index;
421 end Cumulative_Leap_Seconds;
427 function Day (Date : Time) return Day_Number is
433 Split (Date, Y, M, D, S);
441 function Is_Leap (Year : Year_Number) return Boolean is
443 -- Leap centenial years
445 if Year mod 400 = 0 then
448 -- Non-leap centenial years
450 elsif Year mod 100 = 0 then
456 return Year mod 4 = 0;
464 function Month (Date : Time) return Month_Number is
470 Split (Date, Y, M, D, S);
478 function Seconds (Date : Time) return Day_Duration is
484 Split (Date, Y, M, D, S);
494 Year : out Year_Number;
495 Month : out Month_Number;
496 Day : out Day_Number;
497 Seconds : out Day_Duration)
506 -- Use UTC as the local time zone on VMS, the status of flag Is_Ada_05
507 -- is irrelevant in this case.
509 Formatting_Operations.Split
526 or else not Month'Valid
527 or else not Day'Valid
528 or else not Seconds'Valid
540 Month : Month_Number;
542 Seconds : Day_Duration := 0.0) return Time
544 -- The values in the following constants are irrelevant, they are just
545 -- placeholders; the choice of constructing a Day_Duration value is
546 -- controlled by the Use_Day_Secs flag.
548 H : constant Integer := 1;
549 M : constant Integer := 1;
550 Se : constant Integer := 1;
551 Ss : constant Duration := 0.1;
555 or else not Month'Valid
556 or else not Day'Valid
557 or else not Seconds'Valid
562 -- Use UTC as the local time zone on VMS, the status of flag Is_Ada_05
563 -- is irrelevant in this case.
566 Formatting_Operations.Time_Of
576 Use_Day_Secs => True,
585 function To_Duration (T : Time) return Duration is
586 function Time_To_Duration is
587 new Ada.Unchecked_Conversion (Time, Duration);
589 return Time_To_Duration (T * 100);
592 ----------------------
593 -- To_Relative_Time --
594 ----------------------
596 function To_Relative_Time (D : Duration) return Time is
597 function Duration_To_Time is
598 new Ada.Unchecked_Conversion (Duration, Time);
600 return Duration_To_Time (D / 100.0);
601 end To_Relative_Time;
607 function Year (Date : Time) return Year_Number is
613 Split (Date, Y, M, D, S);
617 -- The following packages assume that Time is a Long_Integer, the units
618 -- are 100 nanoseconds and the starting point in the VMS Epoch.
620 ---------------------------
621 -- Arithmetic_Operations --
622 ---------------------------
624 package body Arithmetic_Operations is
630 function Add (Date : Time; Days : Long_Integer) return Time is
631 pragma Unsuppress (Overflow_Check);
642 Res_M := Date + Time (Days) * Milis_In_Day;
644 Check_Within_Time_Bounds (Res_M);
649 when Constraint_Error =>
660 Days : out Long_Integer;
661 Seconds : out Duration;
662 Leap_Seconds : out Integer)
664 Mili_F : constant Duration := 10_000_000.0;
669 Elapsed_Leaps : Natural;
671 Negate : Boolean := False;
673 Sub_Seconds : Duration;
676 -- This classification is necessary in order to avoid a Time_Error
677 -- being raised by the arithmetic operators in Ada.Calendar.
679 if Left >= Right then
688 -- If the target supports leap seconds, process them
691 Cumulative_Leap_Seconds
692 (Earlier, Later, Elapsed_Leaps, Next_Leap);
694 if Later >= Next_Leap then
695 Elapsed_Leaps := Elapsed_Leaps + 1;
698 -- The target does not support leap seconds
704 Diff_M := Later - Earlier - Time (Elapsed_Leaps) * Mili;
706 -- Sub second processing
708 Sub_Seconds := Duration (Diff_M mod Mili) / Mili_F;
710 -- Convert to seconds. Note that his action eliminates the sub
711 -- seconds automatically.
713 Diff_S := Diff_M / Mili;
715 Days := Long_Integer (Diff_S / Secs_In_Day);
716 Seconds := Duration (Diff_S mod Secs_In_Day) + Sub_Seconds;
717 Leap_Seconds := Integer (Elapsed_Leaps);
723 if Leap_Seconds /= 0 then
724 Leap_Seconds := -Leap_Seconds;
733 function Subtract (Date : Time; Days : Long_Integer) return Time is
734 pragma Unsuppress (Overflow_Check);
745 Res_M := Date - Time (Days) * Milis_In_Day;
747 Check_Within_Time_Bounds (Res_M);
751 when Constraint_Error =>
754 end Arithmetic_Operations;
756 ---------------------------
757 -- Formatting_Operations --
758 ---------------------------
760 package body Formatting_Operations is
766 function Day_Of_Week (Date : Time) return Integer is
772 Day_Count : Long_Integer;
773 Midday_Date_S : Time;
776 Split (Date, Y, M, D, S);
778 -- Build a time value in the middle of the same day and convert the
779 -- time value to seconds.
781 Midday_Date_S := Time_Of (Y, M, D, 43_200.0) / Mili;
783 -- Count the number of days since the start of VMS time. 1858-11-17
786 Day_Count := Long_Integer (Midday_Date_S / Secs_In_Day) + 2;
788 return Integer (Day_Count mod 7);
797 Year : out Year_Number;
798 Month : out Month_Number;
799 Day : out Day_Number;
800 Day_Secs : out Day_Duration;
802 Minute : out Integer;
803 Second : out Integer;
804 Sub_Sec : out Duration;
805 Leap_Sec : out Boolean;
807 Time_Zone : Long_Integer)
809 -- The flag Is_Ada_05 is present for interfacing purposes
811 pragma Unreferenced (Is_Ada_05);
814 (Status : out Unsigned_Longword;
815 Timbuf : out Unsigned_Word_Array;
818 pragma Interface (External, Numtim);
820 pragma Import_Valued_Procedure
821 (Numtim, "SYS$NUMTIM",
822 (Unsigned_Longword, Unsigned_Word_Array, Time),
823 (Value, Reference, Reference));
825 Status : Unsigned_Longword;
826 Timbuf : Unsigned_Word_Array (1 .. 7);
828 Ada_Min_Year : constant := 1901;
829 Ada_Max_Year : constant := 2399;
830 Mili_F : constant Duration := 10_000_000.0;
833 Elapsed_Leaps : Natural;
839 -- Step 1: Leap seconds processing
842 Cumulative_Leap_Seconds
843 (Start_Of_Time, Date, Elapsed_Leaps, Next_Leap_M);
845 Leap_Sec := Date_M >= Next_Leap_M;
848 Elapsed_Leaps := Elapsed_Leaps + 1;
851 -- The target does not support leap seconds
858 Date_M := Date_M - Time (Elapsed_Leaps) * Mili;
860 -- Step 2: Time zone processing
862 if Time_Zone /= 0 then
863 Date_M := Date_M + Time (Time_Zone) * 60 * Mili;
866 -- After the leap seconds and time zone have been accounted for,
867 -- the date should be within the bounds of Ada time.
870 or else Date_M > Ada_High
875 -- Step 3: Sub second processing
877 Sub_Sec := Duration (Date_M mod Mili) / Mili_F;
879 -- Drop the sub seconds
881 Date_M := Date_M - (Date_M mod Mili);
883 -- Step 4: VMS system call
885 Numtim (Status, Timbuf, Date_M);
888 or else Timbuf (1) not in Ada_Min_Year .. Ada_Max_Year
893 -- Step 5: Time components processing
895 Year := Year_Number (Timbuf (1));
896 Month := Month_Number (Timbuf (2));
897 Day := Day_Number (Timbuf (3));
898 Hour := Integer (Timbuf (4));
899 Minute := Integer (Timbuf (5));
900 Second := Integer (Timbuf (6));
902 Day_Secs := Day_Duration (Hour * 3_600) +
903 Day_Duration (Minute * 60) +
904 Day_Duration (Second) +
914 Month : Month_Number;
916 Day_Secs : Day_Duration;
922 Use_Day_Secs : Boolean;
924 Time_Zone : Long_Integer) return Time
927 (Status : out Unsigned_Longword;
928 Input_Time : Unsigned_Word_Array;
929 Resultant_Time : out Time);
931 pragma Interface (External, Cvt_Vectim);
933 pragma Import_Valued_Procedure
934 (Cvt_Vectim, "LIB$CVT_VECTIM",
935 (Unsigned_Longword, Unsigned_Word_Array, Time),
936 (Value, Reference, Reference));
938 Status : Unsigned_Longword;
939 Timbuf : Unsigned_Word_Array (1 .. 7);
941 Mili_F : constant := 10_000_000.0;
943 Y : Year_Number := Year;
944 Mo : Month_Number := Month;
945 D : Day_Number := Day;
947 Mi : Integer := Minute;
948 Se : Integer := Second;
949 Su : Duration := Sub_Sec;
951 Elapsed_Leaps : Natural;
952 Int_Day_Secs : Integer;
955 Rounded_Res_M : Time;
958 -- No validity checks are performed on the input values since it is
959 -- assumed that the called has already performed them.
961 -- Step 1: Hour, minute, second and sub second processing
965 -- A day seconds value of 86_400 designates a new day
967 if Day_Secs = 86_400.0 then
969 Adj_Year : Year_Number := Year;
970 Adj_Month : Month_Number := Month;
971 Adj_Day : Day_Number := Day;
974 if Day < Days_In_Month (Month)
976 and then Is_Leap (Year))
980 -- The day adjustment moves the date to a new month
986 Adj_Month := Month + 1;
988 -- The month adjustment moves the date to a new year
992 Adj_Year := Year + 1;
1005 -- Normal case (not exactly one day)
1008 -- Sub second extraction
1010 if Day_Secs > 0.0 then
1011 Int_Day_Secs := Integer (Day_Secs - 0.5);
1013 Int_Day_Secs := Integer (Day_Secs);
1016 H := Int_Day_Secs / 3_600;
1017 Mi := (Int_Day_Secs / 60) mod 60;
1018 Se := Int_Day_Secs mod 60;
1019 Su := Day_Secs - Duration (Int_Day_Secs);
1023 -- Step 2: System call to VMS
1025 Timbuf (1) := Unsigned_Word (Y);
1026 Timbuf (2) := Unsigned_Word (Mo);
1027 Timbuf (3) := Unsigned_Word (D);
1028 Timbuf (4) := Unsigned_Word (H);
1029 Timbuf (5) := Unsigned_Word (Mi);
1030 Timbuf (6) := Unsigned_Word (Se);
1033 Cvt_Vectim (Status, Timbuf, Res_M);
1035 if Status mod 2 /= 1 then
1039 -- Step 3: Sub second adjustment
1041 Res_M := Res_M + Time (Su * Mili_F);
1043 -- Step 4: Bounds check
1045 Check_Within_Time_Bounds (Res_M);
1047 -- Step 5: Time zone processing
1049 if Time_Zone /= 0 then
1050 Res_M := Res_M - Time (Time_Zone) * 60 * Mili;
1053 -- Step 6: Leap seconds processing
1055 if Leap_Support then
1056 Cumulative_Leap_Seconds
1057 (Start_Of_Time, Res_M, Elapsed_Leaps, Next_Leap_M);
1059 Res_M := Res_M + Time (Elapsed_Leaps) * Mili;
1061 -- An Ada 2005 caller requesting an explicit leap second or an
1062 -- Ada 95 caller accounting for an invisible leap second.
1065 or else Res_M >= Next_Leap_M
1067 Res_M := Res_M + Time (1) * Mili;
1070 -- Leap second validity check
1072 Rounded_Res_M := Res_M - (Res_M mod Mili);
1076 and then Rounded_Res_M /= Next_Leap_M
1084 end Formatting_Operations;
1086 ---------------------------
1087 -- Time_Zones_Operations --
1088 ---------------------------
1090 package body Time_Zones_Operations is
1092 ---------------------
1093 -- UTC_Time_Offset --
1094 ---------------------
1096 function UTC_Time_Offset (Date : Time) return Long_Integer is
1097 -- Formal parameter Date is here for interfacing, but is never
1100 pragma Unreferenced (Date);
1102 function get_gmtoff return Long_Integer;
1103 pragma Import (C, get_gmtoff, "get_gmtoff");
1106 -- VMS is not capable of determining the time zone in some past or
1107 -- future point in time denoted by Date, thus the current time zone
1111 end UTC_Time_Offset;
1112 end Time_Zones_Operations;
1114 -- Start of elaboration code for Ada.Calendar
1117 -- Population of the leap seconds table
1119 if Leap_Support then
1121 type Leap_Second_Date is record
1123 Month : Month_Number;
1128 constant array (1 .. Leap_Seconds_Count) of Leap_Second_Date :=
1129 ((1972, 6, 30), (1972, 12, 31), (1973, 12, 31), (1974, 12, 31),
1130 (1975, 12, 31), (1976, 12, 31), (1977, 12, 31), (1978, 12, 31),
1131 (1979, 12, 31), (1981, 6, 30), (1982, 6, 30), (1983, 6, 30),
1132 (1985, 6, 30), (1987, 12, 31), (1989, 12, 31), (1990, 12, 31),
1133 (1992, 6, 30), (1993, 6, 30), (1994, 6, 30), (1995, 12, 31),
1134 (1997, 6, 30), (1998, 12, 31), (2005, 12, 31));
1136 Ada_Min_Year : constant Year_Number := Year_Number'First;
1137 Days_In_Four_Years : constant := 365 * 3 + 366;
1138 VMS_Days : constant := 10 * 366 + 32 * 365 + 45;
1141 Leap : Leap_Second_Date;
1145 for Index in 1 .. Leap_Seconds_Count loop
1146 Leap := Leap_Second_Dates (Index);
1148 -- Calculate the number of days from the start of Ada time until
1149 -- the current leap second occurence. Non-leap centenial years
1150 -- are not accounted for in these calculations since there are
1151 -- no leap seconds after 2100 yet.
1153 Years := Leap.Year - Ada_Min_Year;
1154 Days := (Years / 4) * Days_In_Four_Years;
1155 Years := Years mod 4;
1160 elsif Years = 2 then
1161 Days := Days + 365 * 2;
1163 elsif Years = 3 then
1164 Days := Days + 365 * 3;
1167 Days := Days + Cumulative_Days_Before_Month (Leap.Month);
1169 if Is_Leap (Leap.Year)
1170 and then Leap.Month > 2
1175 -- Add the number of days since the start of VMS time till the
1176 -- start of Ada time.
1178 Days := Days + Leap.Day + VMS_Days;
1180 -- Index - 1 previous leap seconds are added to Time (Index)
1182 Leap_Second_Times (Index) :=
1183 (Time (Days) * Secs_In_Day + Time (Index - 1)) * Mili;