Commit 984d7dd3 by Hristian Kirtchev Committed by Arnaud Charlet

2007-04-20 Hristian Kirtchev <kirtchev@adacore.com>

	* a-calend.ads, a-calend.adb, a-calend-vms.ads, a-calend-vms.adb ("-"
	(Time, Time)): Use To_Relative_Time rather than manual calculation to
	express the bounds of Duration as Time. Raise Time_Error when the
	result is greater or equal to the higher bound of Duration (on the
	margin case).
	("+" (Time, Duration)): Reorder code. Remove the declaration of constant
	Ada_High_And_Leaps.
	("-" (Time, Duration)): Reorder code. Remove the declaration of constant
	Ada_High_And_Leaps.
	("-" (Time, Time)): Reorder code.
	(All_Leap_Seconds): Removed.
	(Arithmetic_Operations.Add): Remove sign related kludge.
	(Arithmetic_Operations.Difference): Control the leaps seconds processing
	with flag Leap_Support.
	(Arithmetic_Operations.Subtract): Remove sign related kludge.
	(Check_Within_Time_Bounds): New procedure.
	(Clock): Control the leap seconds processing with flag Leap_Support.
	(Cumulative_Leap_Seconds): Assert that the target supports leap seconds.
	(Formatting_Operations.Split): Control the leap seconds processing with
	flag Leap_Support.
	(Formatting_Operations.Time_Of): Control the leaps seconds processing
	with flag Leap_Support. Adjust the year, month and day (if applicable)
	when the value of day seconds designates a new day.
	(Split): Use parameter associations for better readability. Integrate
	flag Is_Ada_05.
	(Time_Of): Use parameter associations for better readability. Integrate
	flag Is_Ada_05.

	* a-calfor.adb (Split): Use parameter associations for better
	readability. Integrate flag Is_Ada_05.
	(Time_Of): Remove flag Leap_Checks. Use parameter associations for
	better readability. Integrate flag Is_Ada_05.

From-SVN: r125363
parent f936abf3
......@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
-- Copyright (C) 1992-2006, Free Software Foundation, Inc. --
-- Copyright (C) 1992-2007, Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
......@@ -46,12 +46,40 @@ package body Ada.Calendar is
-- Variables of type Ada.Calendar.Time have suffix _S or _M to denote
-- units of seconds or milis.
-- Because time is measured in different units and from different origins
-- on various targets, a system independent model is incorporated into
-- Ada.Calendar. The idea behing the design is to encapsulate all target
-- dependent machinery in a single package, thus providing a uniform
-- interface to all existing and any potential children.
-- package Ada.Calendar
-- procedure Split (5 parameters) -------+
-- | Call from local routine
-- private |
-- package Formatting_Operations |
-- procedure Split (11 parameters) <--+
-- end Formatting_Operations |
-- end Ada.Calendar |
-- |
-- package Ada.Calendar.Formatting | Call from child routine
-- procedure Split (9 or 10 parameters) -+
-- end Ada.Calendar.Formatting
-- The behaviour of the interfacing routines is controlled via various
-- flags. All new Ada 2005 types from children of Ada.Calendar are
-- emulated by a similar type. For instance, type Day_Number is replaced
-- by Integer in various routines. One ramification of this model is that
-- the caller site must perform validity checks on returned results.
-- The end result of this model is the lack of target specific files per
-- child of Ada.Calendar (a-calfor, a-calfor-vms, a-calfor-vxwors, etc).
-----------------------
-- Local Subprograms --
-----------------------
function All_Leap_Seconds return Natural;
-- Return the number of all leap seconds allocated so far
procedure Check_Within_Time_Bounds (T : Time);
-- Ensure that a time representation value falls withing the bounds of Ada
-- time. Leap seconds support is taken into account.
procedure Cumulative_Leap_Seconds
(Start_Date : Time;
......@@ -60,10 +88,10 @@ package body Ada.Calendar is
Next_Leap_Sec : out Time);
-- Elapsed_Leaps is the sum of the leap seconds that have occured on or
-- after Start_Date and before (strictly before) End_Date. Next_Leap_Sec
-- represents the next leap second occurence on or after End_Date. If there
-- are no leaps seconds after End_Date, After_Last_Leap is returned.
-- After_Last_Leap can be used as End_Date to count all the leap seconds
-- that have occured on or after Start_Date.
-- represents the next leap second occurence on or after End_Date. If
-- there are no leaps seconds after End_Date, End_Of_Time is returned.
-- End_Of_Time can be used as End_Date to count all the leap seconds that
-- have occured on or after Start_Date.
--
-- Note: Any sub seconds of Start_Date and End_Date are discarded before
-- the calculations are done. For instance: if 113 seconds is a leap
......@@ -88,14 +116,36 @@ package body Ada.Calendar is
-- Local Constants --
---------------------
After_Last_Leap : constant Time := Time'Last;
N_Leap_Seconds : constant Natural := 23;
-- Currently none of the GNAT targets support leap seconds. At some point
-- it might be necessary to query a C function to determine if the target
-- supports leap seconds, but for now this is deemed unnecessary.
Leap_Support : constant Boolean := False;
Leap_Seconds_Count : constant Natural := 23;
-- The range of Ada time expressed as milis since the VMS Epoch
Ada_Low : constant Time := (10 * 366 + 32 * 365 + 45) * Milis_In_Day;
Ada_High : constant Time := (131 * 366 + 410 * 365 + 45) * Milis_In_Day;
-- Even though the upper bound of time is 2399-12-31 23:59:59.9999999
-- UTC, it must be increased to include all leap seconds.
Ada_High_And_Leaps : constant Time :=
Ada_High + Time (Leap_Seconds_Count) * Mili;
-- Two constants used in the calculations of elapsed leap seconds.
-- End_Of_Time is later than Ada_High in time zone -28. Start_Of_Time
-- is earlier than Ada_Low in time zone +28.
End_Of_Time : constant Time := Ada_High + Time (3) * Milis_In_Day;
Start_Of_Time : constant Time := Ada_Low - Time (3) * Milis_In_Day;
Cumulative_Days_Before_Month :
constant array (Month_Number) of Natural :=
(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
Leap_Second_Times : array (1 .. N_Leap_Seconds) of Time;
Leap_Second_Times : array (1 .. Leap_Seconds_Count) of Time;
-- Each value represents a time value which is one second before a leap
-- second occurence. This table is populated during the elaboration of
-- Ada.Calendar.
......@@ -107,18 +157,21 @@ package body Ada.Calendar is
function "+" (Left : Time; Right : Duration) return Time is
pragma Unsuppress (Overflow_Check);
Ada_High_And_Leaps : constant Time :=
Ada_High + Time (All_Leap_Seconds) * Mili;
Result : constant Time := Left + To_Relative_Time (Right);
Res_M : Time;
begin
if Result < Ada_Low
or else Result >= Ada_High_And_Leaps
then
raise Time_Error;
-- Trivial case
if Right = Duration (0.0) then
return Left;
end if;
return Result;
Res_M := Left + To_Relative_Time (Right);
Check_Within_Time_Bounds (Res_M);
return Res_M;
exception
when Constraint_Error =>
raise Time_Error;
......@@ -140,18 +193,20 @@ package body Ada.Calendar is
function "-" (Left : Time; Right : Duration) return Time is
pragma Unsuppress (Overflow_Check);
Ada_High_And_Leaps : constant Time :=
Ada_High + Time (All_Leap_Seconds) * Mili;
Result : constant Time := Left - To_Relative_Time (Right);
Res_M : Time;
begin
if Result < Ada_Low
or else Result >= Ada_High_And_Leaps
then
raise Time_Error;
-- Trivial case
if Right = Duration (0.0) then
return Left;
end if;
return Result;
Res_M := Left - To_Relative_Time (Right);
Check_Within_Time_Bounds (Res_M);
return Res_M;
exception
when Constraint_Error =>
......@@ -161,19 +216,25 @@ package body Ada.Calendar is
function "-" (Left : Time; Right : Time) return Duration is
pragma Unsuppress (Overflow_Check);
Diff : constant Time := Left - Right;
Dur_High : constant Time := Time (Duration'Last) * 100;
Dur_Low : constant Time := Time (Duration'First) * 100;
-- The bound of type Duration expressed as time
Dur_High : constant Time := To_Relative_Time (Duration'Last);
Dur_Low : constant Time := To_Relative_Time (Duration'First);
Res_M : Time;
begin
if Diff < Dur_Low
or else Diff > Dur_High
Res_M := Left - Right;
-- The result does not fit in a duration value
if Res_M < Dur_Low
or else Res_M >= Dur_High
then
raise Time_Error;
end if;
return To_Duration (Diff);
return To_Duration (Res_M);
exception
when Constraint_Error =>
raise Time_Error;
......@@ -215,14 +276,22 @@ package body Ada.Calendar is
return Long_Integer (Left) >= Long_Integer (Right);
end ">=";
----------------------
-- All_Leap_Seconds --
----------------------
------------------------------
-- Check_Within_Time_Bounds --
------------------------------
function All_Leap_Seconds return Natural is
procedure Check_Within_Time_Bounds (T : Time) is
begin
return N_Leap_Seconds;
end All_Leap_Seconds;
if Leap_Support then
if T < Ada_Low or else T > Ada_High_And_Leaps then
raise Time_Error;
end if;
else
if T < Ada_Low or else T > Ada_High then
raise Time_Error;
end if;
end if;
end Check_Within_Time_Bounds;
-----------
-- Clock --
......@@ -230,9 +299,8 @@ package body Ada.Calendar is
function Clock return Time is
Elapsed_Leaps : Natural;
Next_Leap : Time;
Now : constant Time := Time (OSP.OS_Clock);
Rounded_Now : constant Time := Now - (Now mod Mili);
Next_Leap_M : Time;
Res_M : constant Time := Time (OSP.OS_Clock);
begin
-- Note that on other targets a soft-link is used to get a different
......@@ -240,17 +308,26 @@ package body Ada.Calendar is
-- needed since all clock calls end up using SYS$GETTIM, so call the
-- OS_Primitives version for efficiency.
-- Determine the number of leap seconds elapsed until this moment
-- If the target supports leap seconds, determine the number of leap
-- seconds elapsed until this moment.
if Leap_Support then
Cumulative_Leap_Seconds
(Start_Of_Time, Res_M, Elapsed_Leaps, Next_Leap_M);
-- The system clock may fall exactly on a leap second
Cumulative_Leap_Seconds (Ada_Low, Now, Elapsed_Leaps, Next_Leap);
if Res_M >= Next_Leap_M then
Elapsed_Leaps := Elapsed_Leaps + 1;
end if;
-- It is possible that OS_Clock falls exactly on a leap second
-- The target does not support leap seconds
if Rounded_Now = Next_Leap then
return Now + Time (Elapsed_Leaps + 1) * Mili;
else
return Now + Time (Elapsed_Leaps) * Mili;
Elapsed_Leaps := 0;
end if;
return Res_M + Time (Elapsed_Leaps) * Mili;
end Clock;
-----------------------------
......@@ -269,9 +346,9 @@ package body Ada.Calendar is
Start_T : Time := Start_Date;
begin
pragma Assert (Start_Date >= End_Date);
pragma Assert (Leap_Support and then End_Date >= Start_Date);
Next_Leap_Sec := After_Last_Leap;
Next_Leap_Sec := End_Of_Time;
-- Make sure that the end date does not excede the upper bound
-- of Ada time.
......@@ -285,23 +362,26 @@ package body Ada.Calendar is
Start_T := Start_T - (Start_T mod Mili);
End_T := End_T - (End_T mod Mili);
-- Some trivial cases
-- Some trivial cases:
-- Leap 1 . . . Leap N
-- ---+========+------+############+-------+========+-----
-- Start_T End_T Start_T End_T
if End_T < Leap_Second_Times (1) then
Elapsed_Leaps := 0;
Next_Leap_Sec := Leap_Second_Times (1);
return;
elsif Start_T > Leap_Second_Times (N_Leap_Seconds) then
elsif Start_T > Leap_Second_Times (Leap_Seconds_Count) then
Elapsed_Leaps := 0;
Next_Leap_Sec := After_Last_Leap;
Next_Leap_Sec := End_Of_Time;
return;
end if;
-- Perform the calculations only if the start date is within the leap
-- second occurences table.
if Start_T <= Leap_Second_Times (N_Leap_Seconds) then
if Start_T <= Leap_Second_Times (Leap_Seconds_Count) then
-- 1 2 N - 1 N
-- +----+----+-- . . . --+-------+---+
......@@ -313,8 +393,8 @@ package body Ada.Calendar is
-- Leaps_Between
-- The idea behind the algorithm is to iterate and find two closest
-- dates which are after Start_T and End_T. Their corresponding index
-- difference denotes the number of leap seconds elapsed.
-- dates which are after Start_T and End_T. Their corresponding
-- index difference denotes the number of leap seconds elapsed.
Start_Index := 1;
loop
......@@ -324,12 +404,12 @@ package body Ada.Calendar is
End_Index := Start_Index;
loop
exit when End_Index > N_Leap_Seconds
exit when End_Index > Leap_Seconds_Count
or else Leap_Second_Times (End_Index) >= End_T;
End_Index := End_Index + 1;
end loop;
if End_Index <= N_Leap_Seconds then
if End_Index <= Leap_Seconds_Count then
Next_Leap_Sec := Leap_Second_Times (End_Index);
end if;
......@@ -423,8 +503,22 @@ package body Ada.Calendar is
Le : Boolean;
begin
-- Use UTC as the local time zone on VMS, the status of flag Is_Ada_05
-- is irrelevant in this case.
Formatting_Operations.Split
(Date, Year, Month, Day, Seconds, H, M, Se, Ss, Le, 0);
(Date => Date,
Year => Year,
Month => Month,
Day => Day,
Day_Secs => Seconds,
Hour => H,
Minute => M,
Second => Se,
Sub_Sec => Ss,
Leap_Sec => Le,
Is_Ada_05 => False,
Time_Zone => 0);
-- Validity checks
......@@ -465,12 +559,22 @@ package body Ada.Calendar is
raise Time_Error;
end if;
-- Use UTC as the local time zone on VMS, the status of flag Is_Ada_05
-- is irrelevant in this case.
return
Formatting_Operations.Time_Of
(Year, Month, Day, Seconds, H, M, Se, Ss,
(Year => Year,
Month => Month,
Day => Day,
Day_Secs => Seconds,
Hour => H,
Minute => M,
Second => Se,
Sub_Sec => Ss,
Leap_Sec => False,
Leap_Checks => False,
Use_Day_Secs => True,
Is_Ada_05 => False,
Time_Zone => 0);
end Time_Of;
......@@ -524,29 +628,22 @@ package body Ada.Calendar is
---------
function Add (Date : Time; Days : Long_Integer) return Time is
Ada_High_And_Leaps : constant Time :=
Ada_High + Time (All_Leap_Seconds) * Mili;
pragma Unsuppress (Overflow_Check);
Res_M : Time;
begin
-- Trivial case
if Days = 0 then
return Date;
end if;
elsif Days < 0 then
return Subtract (Date, abs (Days));
Res_M := Date + Time (Days) * Milis_In_Day;
else
declare
Result : constant Time := Date + Time (Days) * Milis_In_Day;
Check_Within_Time_Bounds (Res_M);
begin
-- The result excedes the upper bound of Ada time
if Result >= Ada_High_And_Leaps then
raise Time_Error;
end if;
return Result;
end;
end if;
return Res_M;
exception
when Constraint_Error =>
......@@ -571,7 +668,7 @@ package body Ada.Calendar is
Earlier : Time;
Elapsed_Leaps : Natural;
Later : Time;
Negate : Boolean;
Negate : Boolean := False;
Next_Leap : Time;
Sub_Seconds : Duration;
......@@ -582,19 +679,26 @@ package body Ada.Calendar is
if Left >= Right then
Later := Left;
Earlier := Right;
Negate := False;
else
Later := Right;
Earlier := Left;
Negate := True;
end if;
-- First process the leap seconds
-- If the target supports leap seconds, process them
Cumulative_Leap_Seconds (Earlier, Later, Elapsed_Leaps, Next_Leap);
if Leap_Support then
Cumulative_Leap_Seconds
(Earlier, Later, Elapsed_Leaps, Next_Leap);
if Later >= Next_Leap then
Elapsed_Leaps := Elapsed_Leaps + 1;
if Later >= Next_Leap then
Elapsed_Leaps := Elapsed_Leaps + 1;
end if;
-- The target does not support leap seconds
else
Elapsed_Leaps := 0;
end if;
Diff_M := Later - Earlier - Time (Elapsed_Leaps) * Mili;
......@@ -613,9 +717,12 @@ package body Ada.Calendar is
Leap_Seconds := Integer (Elapsed_Leaps);
if Negate then
Days := -Days;
Seconds := -Seconds;
Leap_Seconds := -Leap_Seconds;
Days := -Days;
Seconds := -Seconds;
if Leap_Seconds /= 0 then
Leap_Seconds := -Leap_Seconds;
end if;
end if;
end Difference;
......@@ -624,32 +731,22 @@ package body Ada.Calendar is
--------------
function Subtract (Date : Time; Days : Long_Integer) return Time is
pragma Unsuppress (Overflow_Check);
Res_M : Time;
begin
-- Trivial case
if Days = 0 then
return Date;
end if;
elsif Days < 0 then
return Add (Date, abs (Days));
Res_M := Date - Time (Days) * Milis_In_Day;
else
declare
Days_T : constant Time := Time (Days) * Milis_In_Day;
Result : constant Time := Date - Days_T;
begin
-- Subtracting a larger number of days from a smaller time
-- value will cause wrap around since time is a modular type.
-- Also the result may be lower than the start of Ada time.
if Date < Days_T
or Result < Ada_Low
then
raise Time_Error;
end if;
Check_Within_Time_Bounds (Res_M);
return Date - Days_T;
end;
end if;
return Res_M;
exception
when Constraint_Error =>
raise Time_Error;
......@@ -696,18 +793,23 @@ package body Ada.Calendar is
-----------
procedure Split
(Date : Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Day_Secs : out Day_Duration;
Hour : out Integer;
Minute : out Integer;
Second : out Integer;
Sub_Sec : out Duration;
Leap_Sec : out Boolean;
Time_Zone : Long_Integer)
(Date : Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Day_Secs : out Day_Duration;
Hour : out Integer;
Minute : out Integer;
Second : out Integer;
Sub_Sec : out Duration;
Leap_Sec : out Boolean;
Is_Ada_05 : Boolean;
Time_Zone : Long_Integer)
is
-- The flag Is_Ada_05 is present for interfacing purposes
pragma Unreferenced (Is_Ada_05);
procedure Numtim
(Status : out Unsigned_Longword;
Timbuf : out Unsigned_Word_Array;
......@@ -727,59 +829,60 @@ package body Ada.Calendar is
Ada_Max_Year : constant := 2399;
Mili_F : constant Duration := 10_000_000.0;
Abs_Time_Zone : Time;
Elapsed_Leaps : Natural;
Modified_Date_M : Time;
Next_Leap_M : Time;
Rounded_Date_M : Time;
Date_M : Time;
Elapsed_Leaps : Natural;
Next_Leap_M : Time;
begin
Modified_Date_M := Date;
Date_M := Date;
-- Step 1: Leap seconds processing
Cumulative_Leap_Seconds (Ada_Low, Date, Elapsed_Leaps, Next_Leap_M);
if Leap_Support then
Cumulative_Leap_Seconds
(Start_Of_Time, Date, Elapsed_Leaps, Next_Leap_M);
Leap_Sec := Date_M >= Next_Leap_M;
if Leap_Sec then
Elapsed_Leaps := Elapsed_Leaps + 1;
end if;
Rounded_Date_M := Modified_Date_M - (Modified_Date_M mod Mili);
Leap_Sec := Rounded_Date_M = Next_Leap_M;
Modified_Date_M := Modified_Date_M - Time (Elapsed_Leaps) * Mili;
-- The target does not support leap seconds
if Leap_Sec then
Modified_Date_M := Modified_Date_M - Time (1) * Mili;
else
Elapsed_Leaps := 0;
Leap_Sec := False;
end if;
Date_M := Date_M - Time (Elapsed_Leaps) * Mili;
-- Step 2: Time zone processing
if Time_Zone /= 0 then
Abs_Time_Zone := Time (abs (Time_Zone)) * 60 * Mili;
if Time_Zone < 0 then
Modified_Date_M := Modified_Date_M - Abs_Time_Zone;
else
Modified_Date_M := Modified_Date_M + Abs_Time_Zone;
end if;
Date_M := Date_M + Time (Time_Zone) * 60 * Mili;
end if;
-- After the leap seconds and time zone have been accounted for,
-- the date should be within the bounds of Ada time.
if Modified_Date_M < Ada_Low
or else Modified_Date_M >= Ada_High
if Date_M < Ada_Low
or else Date_M > Ada_High
then
raise Time_Error;
end if;
-- Step 3: Sub second processing
Sub_Sec := Duration (Modified_Date_M mod Mili) / Mili_F;
Sub_Sec := Duration (Date_M mod Mili) / Mili_F;
-- Drop the sub seconds
Modified_Date_M := Modified_Date_M - (Modified_Date_M mod Mili);
Date_M := Date_M - (Date_M mod Mili);
-- Step 4: VMS system call
Numtim (Status, Timbuf, Modified_Date_M);
Numtim (Status, Timbuf, Date_M);
if Status mod 2 /= 1
or else Timbuf (1) not in Ada_Min_Year .. Ada_Max_Year
......@@ -816,8 +919,8 @@ package body Ada.Calendar is
Second : Integer;
Sub_Sec : Duration;
Leap_Sec : Boolean;
Leap_Checks : Boolean;
Use_Day_Secs : Boolean;
Is_Ada_05 : Boolean;
Time_Zone : Long_Integer) return Time
is
procedure Cvt_Vectim
......@@ -837,21 +940,19 @@ package body Ada.Calendar is
Mili_F : constant := 10_000_000.0;
Ada_High_And_Leaps : constant Time :=
Ada_High + Time (All_Leap_Seconds) * Mili;
H : Integer := Hour;
Mi : Integer := Minute;
Se : Integer := Second;
Su : Duration := Sub_Sec;
Y : Year_Number := Year;
Mo : Month_Number := Month;
D : Day_Number := Day;
H : Integer := Hour;
Mi : Integer := Minute;
Se : Integer := Second;
Su : Duration := Sub_Sec;
Abs_Time_Zone : Time;
Adjust_Day : Boolean := False;
Elapsed_Leaps : Natural;
Int_Day_Secs : Integer;
Next_Leap_M : Time;
Result_M : Time;
Rounded_Result_M : Time;
Elapsed_Leaps : Natural;
Int_Day_Secs : Integer;
Next_Leap_M : Time;
Res_M : Time;
Rounded_Res_M : Time;
begin
-- No validity checks are performed on the input values since it is
......@@ -861,15 +962,47 @@ package body Ada.Calendar is
if Use_Day_Secs then
-- A day seconds value of 86_400 designates a new day. The time
-- components are reset to zero, but an additional day will be
-- added after the system call.
-- A day seconds value of 86_400 designates a new day
if Day_Secs = 86_400.0 then
Adjust_Day := True;
H := 0;
Mi := 0;
Se := 0;
declare
Adj_Year : Year_Number := Year;
Adj_Month : Month_Number := Month;
Adj_Day : Day_Number := Day;
begin
if Day < Days_In_Month (Month)
or else (Month = 2
and then Is_Leap (Year))
then
Adj_Day := Day + 1;
-- The day adjustment moves the date to a new month
else
Adj_Day := 1;
if Month < 12 then
Adj_Month := Month + 1;
-- The month adjustment moves the date to a new year
else
Adj_Month := 1;
Adj_Year := Year + 1;
end if;
end if;
Y := Adj_Year;
Mo := Adj_Month;
D := Adj_Day;
H := 0;
Mi := 0;
Se := 0;
Su := 0.0;
end;
-- Normal case (not exactly one day)
else
-- Sub second extraction
......@@ -889,81 +1022,64 @@ package body Ada.Calendar is
-- Step 2: System call to VMS
Timbuf (1) := Unsigned_Word (Year);
Timbuf (2) := Unsigned_Word (Month);
Timbuf (3) := Unsigned_Word (Day);
Timbuf (1) := Unsigned_Word (Y);
Timbuf (2) := Unsigned_Word (Mo);
Timbuf (3) := Unsigned_Word (D);
Timbuf (4) := Unsigned_Word (H);
Timbuf (5) := Unsigned_Word (Mi);
Timbuf (6) := Unsigned_Word (Se);
Timbuf (7) := 0;
Cvt_Vectim (Status, Timbuf, Result_M);
Cvt_Vectim (Status, Timbuf, Res_M);
if Status mod 2 /= 1 then
raise Time_Error;
end if;
-- Step 3: Potential day adjustment
-- Step 3: Sub second adjustment
if Use_Day_Secs
and then Adjust_Day
then
Result_M := Result_M + Milis_In_Day;
end if;
Res_M := Res_M + Time (Su * Mili_F);
-- Step 4: Sub second adjustment
-- Step 4: Bounds check
Result_M := Result_M + Time (Su * Mili_F);
Check_Within_Time_Bounds (Res_M);
-- Step 5: Time zone processing
if Time_Zone /= 0 then
Abs_Time_Zone := Time (abs (Time_Zone)) * 60 * Mili;
if Time_Zone < 0 then
Result_M := Result_M + Abs_Time_Zone;
else
Result_M := Result_M - Abs_Time_Zone;
end if;
Res_M := Res_M - Time (Time_Zone) * 60 * Mili;
end if;
-- Step 6: Leap seconds processing
Cumulative_Leap_Seconds
(Ada_Low, Result_M, Elapsed_Leaps, Next_Leap_M);
if Leap_Support then
Cumulative_Leap_Seconds
(Start_Of_Time, Res_M, Elapsed_Leaps, Next_Leap_M);
Result_M := Result_M + Time (Elapsed_Leaps) * Mili;
Res_M := Res_M + Time (Elapsed_Leaps) * Mili;
-- An Ada 2005 caller requesting an explicit leap second or an Ada
-- 95 caller accounting for an invisible leap second.
-- An Ada 2005 caller requesting an explicit leap second or an
-- Ada 95 caller accounting for an invisible leap second.
Rounded_Result_M := Result_M - (Result_M mod Mili);
if Leap_Sec
or else Res_M >= Next_Leap_M
then
Res_M := Res_M + Time (1) * Mili;
end if;
if Leap_Sec
or else Rounded_Result_M = Next_Leap_M
then
Result_M := Result_M + Time (1) * Mili;
Rounded_Result_M := Rounded_Result_M + Time (1) * Mili;
end if;
-- Leap second validity check
-- Leap second validity check
Rounded_Res_M := Res_M - (Res_M mod Mili);
if Leap_Checks
and then Leap_Sec
and then Rounded_Result_M /= Next_Leap_M
then
raise Time_Error;
end if;
-- Bounds check
if Result_M < Ada_Low
or else Result_M >= Ada_High_And_Leaps
then
raise Time_Error;
if Is_Ada_05
and then Leap_Sec
and then Rounded_Res_M /= Next_Leap_M
then
raise Time_Error;
end if;
end if;
return Result_M;
return Res_M;
end Time_Of;
end Formatting_Operations;
......@@ -1000,71 +1116,73 @@ package body Ada.Calendar is
begin
-- Population of the leap seconds table
declare
type Leap_Second_Date is record
Year : Year_Number;
Month : Month_Number;
Day : Day_Number;
end record;
Leap_Second_Dates :
constant array (1 .. N_Leap_Seconds) of Leap_Second_Date :=
((1972, 6, 30), (1972, 12, 31), (1973, 12, 31), (1974, 12, 31),
(1975, 12, 31), (1976, 12, 31), (1977, 12, 31), (1978, 12, 31),
(1979, 12, 31), (1981, 6, 30), (1982, 6, 30), (1983, 6, 30),
(1985, 6, 30), (1987, 12, 31), (1989, 12, 31), (1990, 12, 31),
(1992, 6, 30), (1993, 6, 30), (1994, 6, 30), (1995, 12, 31),
(1997, 6, 30), (1998, 12, 31), (2005, 12, 31));
Ada_Min_Year : constant Year_Number := Year_Number'First;
Days_In_Four_Years : constant := 365 * 3 + 366;
VMS_Days : constant := 10 * 366 + 32 * 365 + 45;
Days : Natural;
Leap : Leap_Second_Date;
Years : Natural;
if Leap_Support then
declare
type Leap_Second_Date is record
Year : Year_Number;
Month : Month_Number;
Day : Day_Number;
end record;
Leap_Second_Dates :
constant array (1 .. Leap_Seconds_Count) of Leap_Second_Date :=
((1972, 6, 30), (1972, 12, 31), (1973, 12, 31), (1974, 12, 31),
(1975, 12, 31), (1976, 12, 31), (1977, 12, 31), (1978, 12, 31),
(1979, 12, 31), (1981, 6, 30), (1982, 6, 30), (1983, 6, 30),
(1985, 6, 30), (1987, 12, 31), (1989, 12, 31), (1990, 12, 31),
(1992, 6, 30), (1993, 6, 30), (1994, 6, 30), (1995, 12, 31),
(1997, 6, 30), (1998, 12, 31), (2005, 12, 31));
Ada_Min_Year : constant Year_Number := Year_Number'First;
Days_In_Four_Years : constant := 365 * 3 + 366;
VMS_Days : constant := 10 * 366 + 32 * 365 + 45;
Days : Natural;
Leap : Leap_Second_Date;
Years : Natural;
begin
for Index in 1 .. N_Leap_Seconds loop
Leap := Leap_Second_Dates (Index);
begin
for Index in 1 .. Leap_Seconds_Count loop
Leap := Leap_Second_Dates (Index);
-- Calculate the number of days from the start of Ada time until
-- the current leap second occurence. Non-leap centenial years
-- are not accounted for in these calculations since there are
-- no leap seconds after 2100 yet.
-- Calculate the number of days from the start of Ada time until
-- the current leap second occurence. Non-leap centenial years
-- are not accounted for in these calculations since there are
-- no leap seconds after 2100 yet.
Years := Leap.Year - Ada_Min_Year;
Days := (Years / 4) * Days_In_Four_Years;
Years := Years mod 4;
Years := Leap.Year - Ada_Min_Year;
Days := (Years / 4) * Days_In_Four_Years;
Years := Years mod 4;
if Years = 1 then
Days := Days + 365;
if Years = 1 then
Days := Days + 365;
elsif Years = 2 then
Days := Days + 365 * 2;
elsif Years = 2 then
Days := Days + 365 * 2;
elsif Years = 3 then
Days := Days + 365 * 3;
end if;
elsif Years = 3 then
Days := Days + 365 * 3;
end if;
Days := Days + Cumulative_Days_Before_Month (Leap.Month);
Days := Days + Cumulative_Days_Before_Month (Leap.Month);
if Is_Leap (Leap.Year)
and then Leap.Month > 2
then
Days := Days + 1;
end if;
if Is_Leap (Leap.Year)
and then Leap.Month > 2
then
Days := Days + 1;
end if;
-- Add the number of days since the start of VMS time till the
-- start of Ada time.
-- Add the number of days since the start of VMS time till the
-- start of Ada time.
Days := Days + Leap.Day + VMS_Days;
Days := Days + Leap.Day + VMS_Days;
-- Index - 1 previous leap seconds are added to Time (Index)
-- Index - 1 previous leap seconds are added to Time (Index)
Leap_Second_Times (Index) :=
(Time (Days) * Secs_In_Day + Time (Index - 1)) * Mili;
end loop;
end;
Leap_Second_Times (Index) :=
(Time (Days) * Secs_In_Day + Time (Index - 1)) * Mili;
end loop;
end;
end if;
end Ada.Calendar;
......@@ -113,7 +113,7 @@ private
-- system base date and time 1858-11-17 0.0 (the Smithsonian base date and
-- time for the astronomic calendar).
-- The time value stored is typically a GMT value, as provided in standard
-- The time value stored is typically a UTC value, as provided in standard
-- Unix environments. If this is the case then Split and Time_Of perform
-- required conversions to and from local times.
......@@ -123,11 +123,6 @@ private
type Time is new OSP.OS_Time;
-- The range of Ada time expressed as milis since the VMS Epoch
Ada_Low : constant Time := (10 * 366 + 32 * 365 + 45) * Milis_In_Day;
Ada_High : constant Time := (131 * 366 + 410 * 365 + 45) * Milis_In_Day;
Days_In_Month : constant array (Month_Number) of Day_Number :=
(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
......@@ -145,7 +140,7 @@ private
package Arithmetic_Operations is
function Add (Date : Time; Days : Long_Integer) return Time;
-- Add X number of days to a time value
-- Add a certain number of days to a time value
procedure Difference
(Left : Time;
......@@ -159,7 +154,7 @@ private
-- values are positive, negative otherwise.
function Subtract (Date : Time; Days : Long_Integer) return Time;
-- Subtract X number of days from a time value
-- Subtract a certain number of days from a time value
end Arithmetic_Operations;
package Formatting_Operations is
......@@ -168,18 +163,21 @@ private
-- within the range of 0 .. 6 (Monday .. Sunday).
procedure Split
(Date : Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Day_Secs : out Day_Duration;
Hour : out Integer;
Minute : out Integer;
Second : out Integer;
Sub_Sec : out Duration;
Leap_Sec : out Boolean;
Time_Zone : Long_Integer);
-- Split a time value into its components
(Date : Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Day_Secs : out Day_Duration;
Hour : out Integer;
Minute : out Integer;
Second : out Integer;
Sub_Sec : out Duration;
Leap_Sec : out Boolean;
Is_Ada_05 : Boolean;
Time_Zone : Long_Integer);
-- Split a time value into its components. Set Is_Ada_05 to use the
-- local time zone (the value in Time_Zone is ignored) when splitting
-- a time value.
function Time_Of
(Year : Year_Number;
......@@ -191,18 +189,20 @@ private
Second : Integer;
Sub_Sec : Duration;
Leap_Sec : Boolean;
Leap_Checks : Boolean;
Use_Day_Secs : Boolean;
Is_Ada_05 : Boolean;
Time_Zone : Long_Integer) return Time;
-- Given all the components of a date, return the corresponding time
-- value. Set Use_Day_Secs to use the value in Day_Secs, otherwise the
-- day duration will be calculated from Hour, Minute, Second and Sub_
-- Sec. Set flag Leap_Checks to verify the validity of a leap second.
-- Sec. Set Is_Ada_05 to use the local time zone (the value in formal
-- Time_Zone is ignored) when building a time value and to verify the
-- validity of a requested leap second.
end Formatting_Operations;
package Time_Zones_Operations is
function UTC_Time_Offset (Date : Time) return Long_Integer;
-- Return the offset in seconds from GMT
-- Return the offset in seconds from UTC
end Time_Zones_Operations;
end Ada.Calendar;
......@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
-- Copyright (C) 1992-2006, Free Software Foundation, Inc. --
-- Copyright (C) 1992-2007, Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
......@@ -47,9 +47,9 @@ package body Ada.Calendar is
--
-- Because time is measured in different units and from different origins
-- on various targets, a system independent model is incorporated into
-- Ada.Calendar. The idea behing the design is to encapsulate all target
-- Ada.Calendar. The idea behind the design is to encapsulate all target
-- dependent machinery in a single package, thus providing a uniform
-- interface to any existing and potential children.
-- interface to all existing and any potential children.
-- package Ada.Calendar
-- procedure Split (5 parameters) -------+
......@@ -76,17 +76,21 @@ package body Ada.Calendar is
-- Local Subprograms --
-----------------------
procedure Check_Within_Time_Bounds (T : Time_Rep);
-- Ensure that a time representation value falls withing the bounds of Ada
-- time. Leap seconds support is taken into account.
procedure Cumulative_Leap_Seconds
(Start_Date : Time;
End_Date : Time;
(Start_Date : Time_Rep;
End_Date : Time_Rep;
Elapsed_Leaps : out Natural;
Next_Leap_Sec : out Time);
Next_Leap : out Time_Rep);
-- Elapsed_Leaps is the sum of the leap seconds that have occured on or
-- after Start_Date and before (strictly before) End_Date. Next_Leap_Sec
-- represents the next leap second occurence on or after End_Date. If
-- there are no leaps seconds after End_Date, After_Last_Leap is returned.
-- After_Last_Leap can be used as End_Date to count all the leap seconds
-- that have occured on or after Start_Date.
-- there are no leaps seconds after End_Date, End_Of_Time is returned.
-- End_Of_Time can be used as End_Date to count all the leap seconds that
-- have occured on or after Start_Date.
--
-- Note: Any sub seconds of Start_Date and End_Date are discarded before
-- the calculations are done. For instance: if 113 seconds is a leap
......@@ -100,46 +104,77 @@ package body Ada.Calendar is
-- After_Last_Leap is designed so that this comparison works without
-- having to first check if Next_Leap_Sec is a valid leap second.
function To_Abs_Duration (T : Time) return Duration;
-- Convert a time value into a duration value. Note that the returned
-- duration is always positive.
function Duration_To_Time_Rep is
new Ada.Unchecked_Conversion (Duration, Time_Rep);
-- Convert a duration value into a time representation value
function Time_Rep_To_Duration is
new Ada.Unchecked_Conversion (Time_Rep, Duration);
-- Convert a time representation value into a duration value
-----------------
-- Local Types --
-----------------
-- An integer time duration. The type is used whenever a positive elapsed
-- duration is needed, for instance when splitting a time value. Here is
-- how Time_Rep and Time_Dur are related:
-- 'First Ada_Low Ada_High 'Last
-- Time_Rep: +-------+------------------------+---------+
-- Time_Dur: +------------------------+---------+
-- 0 'Last
function To_Abs_Time (D : Duration) return Time;
-- Return the time equivalent of a duration value. Since time cannot be
-- negative, the absolute value of D is used. It is upto the called to
-- decide how to handle negative durations converted into time.
type Time_Dur is range 0 .. 2 ** 63 - 1;
---------------------
-- Local Constants --
---------------------
-- Currently none of the GNAT targets support leap seconds. At some point
-- it might be necessary to query a C function to determine if the target
-- supports leap seconds, but for now this is deemed unnecessary.
Leap_Support : constant Boolean := False;
Leap_Seconds_Count : constant Natural := 23;
Ada_Min_Year : constant Year_Number := Year_Number'First;
After_Last_Leap : constant Time := Time'Last;
Leap_Seconds_Count : constant Natural := 23;
Secs_In_Four_Years : constant := (3 * 365 + 366) * Secs_In_Day;
Secs_In_Non_Leap_Year : constant := 365 * Secs_In_Day;
Time_Zero : constant Time := Time'First;
-- Even though the upper bound of Ada time is 2399-12-31 86_399.999999999
-- GMT, it must be shifted to include all leap seconds.
-- Lower and upper bound of Ada time. The zero (0) value of type Time is
-- positioned at year 2150. Note that the lower and upper bound account
-- for the non-leap centenial years.
Ada_Low : constant Time_Rep := -(61 * 366 + 188 * 365) * Nanos_In_Day;
Ada_High : constant Time_Rep := (60 * 366 + 190 * 365) * Nanos_In_Day;
-- Even though the upper bound of time is 2399-12-31 23:59:59.999999999
-- UTC, it must be increased to include all leap seconds.
Ada_High_And_Leaps : constant Time :=
Ada_High + Time (Leap_Seconds_Count) * Nano;
Ada_High_And_Leaps : constant Time_Rep :=
Ada_High + Time_Rep (Leap_Seconds_Count) * Nano;
Hard_Ada_High_And_Leaps : constant Time :=
Hard_Ada_High +
Time (Leap_Seconds_Count) * Nano;
-- Two constants used in the calculations of elapsed leap seconds.
-- End_Of_Time is later than Ada_High in time zone -28. Start_Of_Time
-- is earlier than Ada_Low in time zone +28.
End_Of_Time : constant Time_Rep :=
Ada_High + Time_Rep (3) * Nanos_In_Day;
Start_Of_Time : constant Time_Rep :=
Ada_Low - Time_Rep (3) * Nanos_In_Day;
-- The Unix lower time bound expressed as nanoseconds since the
-- start of Ada time in GMT.
-- start of Ada time in UTC.
Unix_Min : constant Time := (17 * 366 + 52 * 365) * Nanos_In_Day;
Unix_Min : constant Time_Rep :=
Ada_Low + Time_Rep (17 * 366 + 52 * 365) * Nanos_In_Day;
Cumulative_Days_Before_Month :
constant array (Month_Number) of Natural :=
(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
Leap_Second_Times : array (1 .. Leap_Seconds_Count) of Time;
Leap_Second_Times : array (1 .. Leap_Seconds_Count) of Time_Rep;
-- Each value represents a time value which is one second before a leap
-- second occurence. This table is populated during the elaboration of
-- Ada.Calendar.
......@@ -151,46 +186,21 @@ package body Ada.Calendar is
function "+" (Left : Time; Right : Duration) return Time is
pragma Unsuppress (Overflow_Check);
begin
if Right = 0.0 then
return Left;
Left_N : constant Time_Rep := Time_Rep (Left);
Res_N : Time_Rep;
elsif Right < 0.0 then
-- Type Duration has one additional number in its negative subrange,
-- which is Duration'First. The subsequent invocation of "-" will
-- perform among other things an Unchecked_Conversion on that
-- particular value, causing overflow. If not properly handled,
-- the erroneous value will cause an infinite recursion between "+"
-- and "-". To properly handle this boundary case, we make a small
-- adjustment of one second to Duration'First.
if Right = Duration'First then
return Left - abs (Right + 1.0) - 1.0;
else
return Left - abs (Right);
end if;
else
declare
-- The input time value has been normalized to GMT
begin
-- Trivial case
Result : constant Time := Left + To_Abs_Time (Right);
if Right = Duration (0.0) then
return Left;
end if;
begin
-- The end result may excede the upper bound of Ada time. Note
-- that the comparison operator is ">=" rather than ">" since
-- the smallest increment of 0.000000001 to the legal end of
-- time (2399-12-31 86_399.999999999) will render the result
-- equal to Ada_High (2400-1-1 0.0).
Res_N := Left_N + Duration_To_Time_Rep (Right);
if Result >= Ada_High_And_Leaps then
raise Time_Error;
end if;
Check_Within_Time_Bounds (Res_N);
return Result;
end;
end if;
return Time (Res_N);
exception
when Constraint_Error =>
......@@ -209,38 +219,21 @@ package body Ada.Calendar is
function "-" (Left : Time; Right : Duration) return Time is
pragma Unsuppress (Overflow_Check);
begin
if Right = 0.0 then
return Left;
elsif Right < 0.0 then
return Left + abs (Right);
else
declare
Result : Time;
Right_T : constant Time := To_Abs_Time (Right);
Left_N : constant Time_Rep := Time_Rep (Left);
Res_N : Time_Rep;
begin
-- Subtracting a larger time value from a smaller time value
-- will cause a wrap around since Time is a modular type. Note
-- that the time value has been normalized to GMT.
begin
-- Trivial case
if Left < Right_T then
raise Time_Error;
end if;
if Right = Duration (0.0) then
return Left;
end if;
Result := Left - Right_T;
Res_N := Left_N - Duration_To_Time_Rep (Right);
if Result < Ada_Low
or else Result > Ada_High_And_Leaps
then
raise Time_Error;
end if;
Check_Within_Time_Bounds (Res_N);
return Result;
end;
end if;
return Time (Res_N);
exception
when Constraint_Error =>
......@@ -250,54 +243,25 @@ package body Ada.Calendar is
function "-" (Left : Time; Right : Time) return Duration is
pragma Unsuppress (Overflow_Check);
function To_Time is new Ada.Unchecked_Conversion (Duration, Time);
-- The bounds of type Duration expressed as time representations
-- Since the absolute values of the upper and lower bound of duration
-- are denoted by the same number, it is sufficend to use Duration'Last
-- when performing out of range checks.
Dur_Low : constant Time_Rep := Duration_To_Time_Rep (Duration'First);
Dur_High : constant Time_Rep := Duration_To_Time_Rep (Duration'Last);
Duration_Bound : constant Time := To_Time (Duration'Last);
Earlier : Time;
Later : Time;
Negate : Boolean := False;
Result : Time;
Result_D : Duration;
Res_N : Time_Rep;
begin
-- This routine becomes a little tricky since time cannot be negative,
-- but the subtraction of two time values can produce a negative value.
if Left > Right then
Later := Left;
Earlier := Right;
else
Later := Right;
Earlier := Left;
Negate := True;
end if;
Res_N := Time_Rep (Left) - Time_Rep (Right);
Result := Later - Earlier;
-- The result does not fit in a duration value
-- Check whether the resulting difference is within the range of type
-- Duration. The following two conditions are examined with the same
-- piece of code:
--
-- positive result > positive upper bound of duration
--
-- negative (negative result) > abs (negative bound of duration)
if Result > Duration_Bound then
if Res_N < Dur_Low
or else Res_N > Dur_High
then
raise Time_Error;
end if;
Result_D := To_Abs_Duration (Result);
if Negate then
Result_D := -Result_D;
end if;
return Result_D;
return Time_Rep_To_Duration (Res_N);
exception
when Constraint_Error =>
raise Time_Error;
......@@ -339,39 +303,62 @@ package body Ada.Calendar is
return Time_Rep (Left) >= Time_Rep (Right);
end ">=";
------------------------------
-- Check_Within_Time_Bounds --
------------------------------
procedure Check_Within_Time_Bounds (T : Time_Rep) is
begin
if Leap_Support then
if T < Ada_Low or else T > Ada_High_And_Leaps then
raise Time_Error;
end if;
else
if T < Ada_Low or else T > Ada_High then
raise Time_Error;
end if;
end if;
end Check_Within_Time_Bounds;
-----------
-- Clock --
-----------
function Clock return Time is
Elapsed_Leaps : Natural;
Next_Leap : Time;
-- The system clock returns the time in GMT since the Unix Epoch of
-- 1970-1-1 0.0. We perform an origin shift to the Ada Epoch by adding
-- the number of nanoseconds between the two origins.
Next_Leap_N : Time_Rep;
Now : Time := To_Abs_Time (System.OS_Primitives.Clock) + Unix_Min;
-- The system clock returns the time in UTC since the Unix Epoch of
-- 1970-01-01 00:00:00.0. We perform an origin shift to the Ada Epoch
-- by adding the number of nanoseconds between the two origins.
Rounded_Now : constant Time := Now - (Now mod Nano);
Res_N : Time_Rep :=
Duration_To_Time_Rep (System.OS_Primitives.Clock) +
Unix_Min;
begin
-- Determine how many leap seconds have elapsed until this moment
-- If the target supports leap seconds, determine the number of leap
-- seconds elapsed until this moment.
if Leap_Support then
Cumulative_Leap_Seconds
(Start_Of_Time, Res_N, Elapsed_Leaps, Next_Leap_N);
Cumulative_Leap_Seconds (Time_Zero, Now, Elapsed_Leaps, Next_Leap);
-- The system clock may fall exactly on a leap second
Now := Now + Time (Elapsed_Leaps) * Nano;
if Res_N >= Next_Leap_N then
Elapsed_Leaps := Elapsed_Leaps + 1;
end if;
-- The system clock may fall exactly on a leap second occurence
-- The target does not support leap seconds
if Rounded_Now = Next_Leap then
Now := Now + Time (1) * Nano;
else
Elapsed_Leaps := 0;
end if;
-- Add the buffer set aside for time zone processing since Split in
-- Ada.Calendar.Formatting_Operations expects it to be there.
Res_N := Res_N + Time_Rep (Elapsed_Leaps) * Nano;
return Now + Buffer_N;
return Time (Res_N);
end Clock;
-----------------------------
......@@ -379,23 +366,22 @@ package body Ada.Calendar is
-----------------------------
procedure Cumulative_Leap_Seconds
(Start_Date : Time;
End_Date : Time;
(Start_Date : Time_Rep;
End_Date : Time_Rep;
Elapsed_Leaps : out Natural;
Next_Leap_Sec : out Time)
Next_Leap : out Time_Rep)
is
End_Index : Positive;
End_T : Time := End_Date;
End_T : Time_Rep := End_Date;
Start_Index : Positive;
Start_T : Time := Start_Date;
Start_T : Time_Rep := Start_Date;
begin
-- Both input dates need to be normalized to GMT in order for this
-- routine to work properly.
-- Both input dates must be normalized to UTC
pragma Assert (End_Date >= Start_Date);
pragma Assert (Leap_Support and then End_Date >= Start_Date);
Next_Leap_Sec := After_Last_Leap;
Next_Leap := End_Of_Time;
-- Make sure that the end date does not excede the upper bound
-- of Ada time.
......@@ -416,12 +402,12 @@ package body Ada.Calendar is
if End_T < Leap_Second_Times (1) then
Elapsed_Leaps := 0;
Next_Leap_Sec := Leap_Second_Times (1);
Next_Leap := Leap_Second_Times (1);
return;
elsif Start_T > Leap_Second_Times (Leap_Seconds_Count) then
Elapsed_Leaps := 0;
Next_Leap_Sec := After_Last_Leap;
Next_Leap := End_Of_Time;
return;
end if;
......@@ -458,7 +444,7 @@ package body Ada.Calendar is
end loop;
if End_Index <= Leap_Seconds_Count then
Next_Leap_Sec := Leap_Second_Times (End_Index);
Next_Leap := Leap_Second_Times (End_Index);
end if;
Elapsed_Leaps := End_Index - Start_Index;
......@@ -549,12 +535,24 @@ package body Ada.Calendar is
Se : Integer;
Ss : Duration;
Le : Boolean;
Tz : constant Long_Integer :=
Time_Zones_Operations.UTC_Time_Offset (Date) / 60;
begin
-- Even though the input time zone is UTC (0), the flag Is_Ada_05 will
-- ensure that Split picks up the local time zone.
Formatting_Operations.Split
(Date, Year, Month, Day, Seconds, H, M, Se, Ss, Le, Tz);
(Date => Date,
Year => Year,
Month => Month,
Day => Day,
Day_Secs => Seconds,
Hour => H,
Minute => M,
Second => Se,
Sub_Sec => Ss,
Leap_Sec => Le,
Is_Ada_05 => False,
Time_Zone => 0);
-- Validity checks
......@@ -586,11 +584,9 @@ package body Ada.Calendar is
Se : constant Integer := 1;
Ss : constant Duration := 0.1;
Mid_Offset : Long_Integer;
Mid_Result : Time;
Offset : Long_Integer;
begin
-- Validity checks
if not Year'Valid
or else not Month'Valid
or else not Day'Valid
......@@ -599,96 +595,25 @@ package body Ada.Calendar is
raise Time_Error;
end if;
-- Building a time value in a local time zone is tricky since the
-- local time zone offset at the point of creation may not be the
-- same as the actual time zone offset designated by the input
-- values. The following example is relevant to New York, USA.
--
-- Creation date: 2006-10-10 0.0 Offset -240 mins (in DST)
-- Actual date : 1901-01-01 0.0 Offset -300 mins (no DST)
-- We first start by obtaining the current local time zone offset
-- using Ada.Calendar.Clock, then building an intermediate time
-- value using that offset.
Mid_Offset := Time_Zones_Operations.UTC_Time_Offset (Clock) / 60;
Mid_Result := Formatting_Operations.Time_Of
(Year, Month, Day, Seconds, H, M, Se, Ss,
Leap_Sec => False,
Leap_Checks => False,
Use_Day_Secs => True,
Time_Zone => Mid_Offset);
-- This is the true local time zone offset of the input time values
Offset := Time_Zones_Operations.UTC_Time_Offset (Mid_Result) / 60;
-- It is possible that at the point of invocation of Time_Of, both
-- the current local time zone offset and the one designated by the
-- input values are in the same DST mode.
if Offset = Mid_Offset then
return Mid_Result;
-- In this case we must calculate the new time with the new offset. It
-- is no sufficient to just take the relative difference between the
-- two offsets and adjust the intermediate result, because this does not
-- work around leap second times.
else
declare
Result : constant Time :=
Formatting_Operations.Time_Of
(Year, Month, Day, Seconds, H, M, Se, Ss,
Leap_Sec => False,
Leap_Checks => False,
Use_Day_Secs => True,
Time_Zone => Offset);
begin
return Result;
end;
end if;
-- Even though the input time zone is UTC (0), the flag Is_Ada_05 will
-- ensure that Split picks up the local time zone.
return
Formatting_Operations.Time_Of
(Year => Year,
Month => Month,
Day => Day,
Day_Secs => Seconds,
Hour => H,
Minute => M,
Second => Se,
Sub_Sec => Ss,
Leap_Sec => False,
Use_Day_Secs => True,
Is_Ada_05 => False,
Time_Zone => 0);
end Time_Of;
---------------------
-- To_Abs_Duration --
---------------------
function To_Abs_Duration (T : Time) return Duration is
pragma Unsuppress (Overflow_Check);
function To_Duration is new Ada.Unchecked_Conversion (Time, Duration);
begin
return To_Duration (T);
exception
when Constraint_Error =>
raise Time_Error;
end To_Abs_Duration;
-----------------
-- To_Abs_Time --
-----------------
function To_Abs_Time (D : Duration) return Time is
pragma Unsuppress (Overflow_Check);
function To_Time is new Ada.Unchecked_Conversion (Duration, Time);
begin
-- This operation assumes that D is positive
if D < 0.0 then
raise Constraint_Error;
end if;
return To_Time (D);
exception
when Constraint_Error =>
raise Time_Error;
end To_Abs_Time;
----------
-- Year --
----------
......@@ -703,9 +628,9 @@ package body Ada.Calendar is
return Y;
end Year;
-- The following packages assume that Time is a modular 64 bit integer
-- The following packages assume that Time is a signed 64 bit integer
-- type, the units are nanoseconds and the origin is the start of Ada
-- time (1901-1-1 0.0).
-- time (1901-01-01 00:00:00.0 UTC).
---------------------------
-- Arithmetic_Operations --
......@@ -718,27 +643,23 @@ package body Ada.Calendar is
---------
function Add (Date : Time; Days : Long_Integer) return Time is
pragma Unsuppress (Overflow_Check);
Date_N : constant Time_Rep := Time_Rep (Date);
Res_N : Time_Rep;
begin
-- Trivial case
if Days = 0 then
return Date;
end if;
elsif Days < 0 then
return Subtract (Date, abs (Days));
else
declare
Result : constant Time := Date + Time (Days) * Nanos_In_Day;
begin
-- The result excedes the upper bound of Ada time
Res_N := Date_N + Time_Rep (Days) * Nanos_In_Day;
if Result > Ada_High_And_Leaps then
raise Time_Error;
end if;
Check_Within_Time_Bounds (Res_N);
return Result;
end;
end if;
return Time (Res_N);
exception
when Constraint_Error =>
......@@ -756,54 +677,70 @@ package body Ada.Calendar is
Seconds : out Duration;
Leap_Seconds : out Integer)
is
Diff_N : Time;
Diff_S : Time;
Earlier : Time;
Res_Dur : Time_Dur;
Earlier : Time_Rep;
Earlier_Sub : Time_Rep;
Elapsed_Leaps : Natural;
Later : Time;
Later : Time_Rep;
Later_Sub : Time_Rep;
Negate : Boolean := False;
Next_Leap : Time;
Next_Leap_N : Time_Rep;
Sub_Seconds : Duration;
begin
-- Both input time values are assumed to be in GMT
-- Both input time values are assumed to be in UTC
if Left >= Right then
Later := Left;
Earlier := Right;
Later := Time_Rep (Left);
Earlier := Time_Rep (Right);
else
Later := Right;
Earlier := Left;
Later := Time_Rep (Right);
Earlier := Time_Rep (Left);
Negate := True;
end if;
-- First process the leap seconds
-- If the target supports leap seconds, process them
Cumulative_Leap_Seconds (Earlier, Later, Elapsed_Leaps, Next_Leap);
if Leap_Support then
Cumulative_Leap_Seconds
(Earlier, Later, Elapsed_Leaps, Next_Leap_N);
if Later >= Next_Leap then
Elapsed_Leaps := Elapsed_Leaps + 1;
if Later >= Next_Leap_N then
Elapsed_Leaps := Elapsed_Leaps + 1;
end if;
-- The target does not support leap seconds
else
Elapsed_Leaps := 0;
end if;
Diff_N := Later - Earlier - Time (Elapsed_Leaps) * Nano;
-- Sub seconds
-- Sub second processing
Earlier_Sub := Earlier mod Nano;
Later_Sub := Later mod Nano;
Sub_Seconds := Duration (Diff_N mod Nano) / Nano_F;
if Later_Sub < Earlier_Sub then
Later_Sub := Later_Sub + Time_Rep (1) * Nano;
Later := Later - Time_Rep (1) * Nano;
end if;
-- Convert to seconds. Note that his action eliminates the sub
-- seconds automatically.
Sub_Seconds := Duration (Later_Sub - Earlier_Sub) / Nano_F;
Diff_S := Diff_N / Nano;
Res_Dur := Time_Dur (Later / Nano - Earlier / Nano) -
Time_Dur (Elapsed_Leaps);
Days := Long_Integer (Diff_S / Secs_In_Day);
Seconds := Duration (Diff_S mod Secs_In_Day) + Sub_Seconds;
Days := Long_Integer (Res_Dur / Secs_In_Day);
Seconds := Duration (Res_Dur mod Secs_In_Day) + Sub_Seconds;
Leap_Seconds := Integer (Elapsed_Leaps);
if Negate then
Days := -Days;
Seconds := -Seconds;
Leap_Seconds := -Leap_Seconds;
Days := -Days;
Seconds := -Seconds;
if Leap_Seconds /= 0 then
Leap_Seconds := -Leap_Seconds;
end if;
end if;
end Difference;
......@@ -812,37 +749,23 @@ package body Ada.Calendar is
--------------
function Subtract (Date : Time; Days : Long_Integer) return Time is
begin
if Days = 0 then
return Date;
pragma Unsuppress (Overflow_Check);
elsif Days < 0 then
return Add (Date, abs (Days));
Date_N : constant Time_Rep := Time_Rep (Date);
Res_N : Time_Rep;
else
declare
Days_T : constant Time := Time (Days) * Nanos_In_Day;
Result : Time;
begin
-- Subtracting a larger number of days from a smaller time
-- value will cause wrap around since time is a modular type.
begin
-- Trivial case
if Date < Days_T then
raise Time_Error;
end if;
if Days = 0 then
return Date;
end if;
Result := Date - Days_T;
Res_N := Date_N - Time_Rep (Days) * Nanos_In_Day;
if Result < Ada_Low
or else Result > Ada_High_And_Leaps
then
raise Time_Error;
end if;
Check_Within_Time_Bounds (Res_N);
return Result;
end;
end if;
return Time (Res_N);
exception
when Constraint_Error =>
......@@ -860,37 +783,39 @@ package body Ada.Calendar is
-- To_Duration --
-----------------
function To_Duration (Ada_Time : Time) return Duration is
function To_Duration (Date : Time) return Duration is
Elapsed_Leaps : Natural;
Modified_Time : Time;
Next_Leap : Time;
Result : Duration;
Rounded_Time : Time;
Next_Leap_N : Time_Rep;
Res_N : Time_Rep;
begin
Modified_Time := Ada_Time;
Rounded_Time := Modified_Time - (Modified_Time mod Nano);
Res_N := Time_Rep (Date);
-- Remove all leap seconds
-- If the target supports leap seconds, remove any leap seconds
-- elapsed upto the input date.
Cumulative_Leap_Seconds
(Time_Zero, Modified_Time, Elapsed_Leaps, Next_Leap);
if Leap_Support then
Cumulative_Leap_Seconds
(Start_Of_Time, Res_N, Elapsed_Leaps, Next_Leap_N);
Modified_Time := Modified_Time - Time (Elapsed_Leaps) * Nano;
-- The input time value may fall on a leap second occurence
-- The input time value may fall on a leap second occurence
if Res_N >= Next_Leap_N then
Elapsed_Leaps := Elapsed_Leaps + 1;
end if;
if Rounded_Time = Next_Leap then
Modified_Time := Modified_Time - Time (1) * Nano;
end if;
-- The target does not support leap seconds
-- Perform a shift in origins
else
Elapsed_Leaps := 0;
end if;
Result := Modified_Time - Unix_Min;
Res_N := Res_N - Time_Rep (Elapsed_Leaps) * Nano;
-- Remove the buffer period used in time zone processing
-- Perform a shift in origins, note that enforcing type Time on
-- both operands will invoke Ada.Calendar."-".
return Result - Buffer_D;
return Time (Res_N) - Time (Unix_Min);
end To_Duration;
end Delays_Operations;
......@@ -908,34 +833,58 @@ package body Ada.Calendar is
Y : Year_Number;
Mo : Month_Number;
D : Day_Number;
Dd : Day_Duration;
Ds : Day_Duration;
H : Integer;
Mi : Integer;
Se : Integer;
Su : Duration;
Le : Boolean;
Day_Count : Long_Integer;
Midday_Date_S : Time;
Day_Count : Long_Integer;
Res_Dur : Time_Dur;
Res_N : Time_Rep;
begin
Formatting_Operations.Split
(Date, Y, Mo, D, Dd, H, Mi, Se, Su, Le, 0);
-- Build a time value in the middle of the same day, remove the
-- lower buffer and convert the time value to seconds.
Midday_Date_S := (Formatting_Operations.Time_Of
(Y, Mo, D, 0.0, 12, 0, 0, 0.0,
Leap_Sec => False,
Leap_Checks => False,
Use_Day_Secs => False,
Time_Zone => 0) - Buffer_N) / Nano;
(Date => Date,
Year => Y,
Month => Mo,
Day => D,
Day_Secs => Ds,
Hour => H,
Minute => Mi,
Second => Se,
Sub_Sec => Su,
Leap_Sec => Le,
Is_Ada_05 => True,
Time_Zone => 0);
-- Build a time value in the middle of the same day
Res_N :=
Time_Rep
(Formatting_Operations.Time_Of
(Year => Y,
Month => Mo,
Day => D,
Day_Secs => 0.0,
Hour => 12,
Minute => 0,
Second => 0,
Sub_Sec => 0.0,
Leap_Sec => False,
Use_Day_Secs => False,
Is_Ada_05 => True,
Time_Zone => 0));
-- Determine the elapsed seconds since the start of Ada time
Res_Dur := Time_Dur (Res_N / Nano - Ada_Low / Nano);
-- Count the number of days since the start of Ada time. 1901-1-1
-- GMT was a Tuesday.
Day_Count := Long_Integer (Midday_Date_S / Secs_In_Day) + 1;
Day_Count := Long_Integer (Res_Dur / Secs_In_Day) + 1;
return Integer (Day_Count mod 7);
end Day_Of_Week;
......@@ -945,180 +894,139 @@ package body Ada.Calendar is
-----------
procedure Split
(Date : Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Day_Secs : out Day_Duration;
Hour : out Integer;
Minute : out Integer;
Second : out Integer;
Sub_Sec : out Duration;
Leap_Sec : out Boolean;
Time_Zone : Long_Integer)
(Date : Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Day_Secs : out Day_Duration;
Hour : out Integer;
Minute : out Integer;
Second : out Integer;
Sub_Sec : out Duration;
Leap_Sec : out Boolean;
Is_Ada_05 : Boolean;
Time_Zone : Long_Integer)
is
-- The following constants represent the number of nanoseconds
-- elapsed since the start of Ada time to and including the non
-- leap centenial years.
Year_2101 : constant Time := (49 * 366 + 151 * 365) * Nanos_In_Day;
Year_2201 : constant Time := (73 * 366 + 227 * 365) * Nanos_In_Day;
Year_2301 : constant Time := (97 * 366 + 303 * 365) * Nanos_In_Day;
Abs_Time_Zone : Time;
Day_Seconds : Natural;
Elapsed_Leaps : Natural;
Four_Year_Segs : Natural;
Hour_Seconds : Natural;
Is_Leap_Year : Boolean;
Modified_Date_N : Time;
Modified_Date_S : Time;
Next_Leap_N : Time;
Rem_Years : Natural;
Rounded_Date_N : Time;
Year_Day : Natural;
Year_2101 : constant Time_Rep := Ada_Low +
Time_Rep (49 * 366 + 151 * 365) * Nanos_In_Day;
Year_2201 : constant Time_Rep := Ada_Low +
Time_Rep (73 * 366 + 227 * 365) * Nanos_In_Day;
Year_2301 : constant Time_Rep := Ada_Low +
Time_Rep (97 * 366 + 303 * 365) * Nanos_In_Day;
Date_Dur : Time_Dur;
Date_N : Time_Rep;
Day_Seconds : Natural;
Elapsed_Leaps : Natural;
Four_Year_Segs : Natural;
Hour_Seconds : Natural;
Is_Leap_Year : Boolean;
Next_Leap_N : Time_Rep;
Rem_Years : Natural;
Sub_Sec_N : Time_Rep;
Year_Day : Natural;
begin
Modified_Date_N := Date;
Date_N := Time_Rep (Date);
if Modified_Date_N < Hard_Ada_Low
or else Modified_Date_N > Hard_Ada_High_And_Leaps
then
raise Time_Error;
end if;
-- Step 1: Leap seconds processing in UTC
-- Step 1: Leap seconds processing in GMT
-- Day_Duration: 86_398 86_399 X (86_400) 0 (1) 1 (2)
-- Time : --+-------+-------+----------+------+-->
-- Seconds : 58 59 60 (Leap) 1 2
-- o Modified_Date_N falls between 86_399 and X (86_400)
-- Elapsed_Leaps = X - 1 leaps
-- Rounded_Date_N = 86_399
-- Next_Leap_N = X (86_400)
-- Leap_Sec = False
-- o Modified_Date_N falls exactly on X (86_400)
-- Elapsed_Leaps = X - 1 leaps
-- Rounded_Date_N = X (86_400)
-- Next_Leap_N = X (86_400)
-- Leap_Sec = True
-- An invisible leap second will be added.
-- o Modified_Date_N falls between X (86_400) and 0 (1)
-- Elapsed_Leaps = X - 1 leaps
-- Rounded_Date_N = X (86_400)
-- Next_Leap_N = X (86_400)
-- Leap_Sec = True
-- An invisible leap second will be added.
-- o Modified_Date_N falls on 0 (1)
-- Elapsed_Leaps = X
-- Rounded_Date_N = 0 (1)
-- Next_Leap_N = X + 1
-- Leap_Sec = False
-- The invisible leap second has already been accounted for in
-- Elapsed_Leaps.
if Leap_Support then
Cumulative_Leap_Seconds
(Start_Of_Time, Date_N, Elapsed_Leaps, Next_Leap_N);
Cumulative_Leap_Seconds
(Time_Zero, Modified_Date_N, Elapsed_Leaps, Next_Leap_N);
Leap_Sec := Date_N >= Next_Leap_N;
Rounded_Date_N := Modified_Date_N - (Modified_Date_N mod Nano);
Leap_Sec := Rounded_Date_N = Next_Leap_N;
Modified_Date_N := Modified_Date_N - Time (Elapsed_Leaps) * Nano;
if Leap_Sec then
Elapsed_Leaps := Elapsed_Leaps + 1;
end if;
-- The target does not support leap seconds
if Leap_Sec then
Modified_Date_N := Modified_Date_N - Time (1) * Nano;
else
Elapsed_Leaps := 0;
Leap_Sec := False;
end if;
Date_N := Date_N - Time_Rep (Elapsed_Leaps) * Nano;
-- Step 2: Time zone processing. This action converts the input date
-- from GMT to the requested time zone.
if Time_Zone /= 0 then
Abs_Time_Zone := Time (abs (Time_Zone)) * 60 * Nano;
if Time_Zone < 0 then
-- The following test is obsolete since the date already
-- contains the dedicated buffer for time zones, thus no
-- error will be raised. However it is a good idea to keep
-- it should the representation of time change.
Modified_Date_N := Modified_Date_N - Abs_Time_Zone;
else
Modified_Date_N := Modified_Date_N + Abs_Time_Zone;
if Is_Ada_05 then
if Time_Zone /= 0 then
Date_N := Date_N + Time_Rep (Time_Zone) * 60 * Nano;
end if;
end if;
-- After the elapsed leap seconds have been removed and the date
-- has been normalized, it should fall withing the soft bounds of
-- Ada time.
-- Ada 83 and 95
if Modified_Date_N < Ada_Low
or else Modified_Date_N > Ada_High
then
raise Time_Error;
else
declare
Off : constant Long_Integer :=
Time_Zones_Operations.UTC_Time_Offset (Time (Date_N));
begin
Date_N := Date_N + Time_Rep (Off) * Nano;
end;
end if;
-- Before any additional arithmetic is performed we must remove the
-- lower buffer period since it will be accounted as few additional
-- days.
Modified_Date_N := Modified_Date_N - Buffer_N;
-- Step 3: Non-leap centenial year adjustment in local time zone
-- In order for all divisions to work properly and to avoid more
-- complicated arithmetic, we add fake Febriary 29s to dates which
-- occur after a non-leap centenial year.
if Modified_Date_N >= Year_2301 then
Modified_Date_N := Modified_Date_N + Time (3) * Nanos_In_Day;
if Date_N >= Year_2301 then
Date_N := Date_N + Time_Rep (3) * Nanos_In_Day;
elsif Modified_Date_N >= Year_2201 then
Modified_Date_N := Modified_Date_N + Time (2) * Nanos_In_Day;
elsif Date_N >= Year_2201 then
Date_N := Date_N + Time_Rep (2) * Nanos_In_Day;
elsif Modified_Date_N >= Year_2101 then
Modified_Date_N := Modified_Date_N + Time (1) * Nanos_In_Day;
elsif Date_N >= Year_2101 then
Date_N := Date_N + Time_Rep (1) * Nanos_In_Day;
end if;
-- Step 4: Sub second processing in local time zone
Sub_Sec := Duration (Modified_Date_N mod Nano) / Nano_F;
Sub_Sec_N := Date_N mod Nano;
Sub_Sec := Duration (Sub_Sec_N) / Nano_F;
Date_N := Date_N - Sub_Sec_N;
-- Convert the date into seconds, the sub seconds are automatically
-- dropped.
-- Convert Date_N into a time duration value, changing the units
-- to seconds.
Modified_Date_S := Modified_Date_N / Nano;
Date_Dur := Time_Dur (Date_N / Nano - Ada_Low / Nano);
-- Step 5: Year processing in local time zone. Determine the number
-- of four year segments since the start of Ada time and the input
-- date.
Four_Year_Segs := Natural (Modified_Date_S / Secs_In_Four_Years);
Four_Year_Segs := Natural (Date_Dur / Secs_In_Four_Years);
if Four_Year_Segs > 0 then
Modified_Date_S := Modified_Date_S - Time (Four_Year_Segs) *
Secs_In_Four_Years;
Date_Dur := Date_Dur - Time_Dur (Four_Year_Segs) *
Secs_In_Four_Years;
end if;
-- Calculate the remaining non-leap years
Rem_Years := Natural (Modified_Date_S / Secs_In_Non_Leap_Year);
Rem_Years := Natural (Date_Dur / Secs_In_Non_Leap_Year);
if Rem_Years > 3 then
Rem_Years := 3;
end if;
Modified_Date_S := Modified_Date_S - Time (Rem_Years) *
Secs_In_Non_Leap_Year;
Date_Dur := Date_Dur - Time_Dur (Rem_Years) * Secs_In_Non_Leap_Year;
Year := Ada_Min_Year + Natural (4 * Four_Year_Segs + Rem_Years);
Is_Leap_Year := Is_Leap (Year);
-- Step 6: Month and day processing in local time zone
Year_Day := Natural (Modified_Date_S / Secs_In_Day) + 1;
Year_Day := Natural (Date_Dur / Secs_In_Day) + 1;
Month := 1;
......@@ -1131,8 +1039,7 @@ package body Ada.Calendar is
-- Processing for a new month or a leap February
if Year_Day > 28
and then (not Is_Leap_Year
or else Year_Day > 29)
and then (not Is_Leap_Year or else Year_Day > 29)
then
Month := 3;
Year_Day := Year_Day - 28;
......@@ -1154,7 +1061,7 @@ package body Ada.Calendar is
-- time zone.
Day := Day_Number (Year_Day);
Day_Seconds := Integer (Modified_Date_S mod Secs_In_Day);
Day_Seconds := Integer (Date_Dur mod Secs_In_Day);
Day_Secs := Duration (Day_Seconds) + Sub_Sec;
Hour := Day_Seconds / 3_600;
Hour_Seconds := Day_Seconds mod 3_600;
......@@ -1176,16 +1083,15 @@ package body Ada.Calendar is
Second : Integer;
Sub_Sec : Duration;
Leap_Sec : Boolean;
Leap_Checks : Boolean;
Use_Day_Secs : Boolean;
Is_Ada_05 : Boolean;
Time_Zone : Long_Integer) return Time
is
Abs_Time_Zone : Time;
Count : Integer;
Elapsed_Leaps : Natural;
Next_Leap_N : Time;
Result_N : Time;
Rounded_Result_N : Time;
Count : Integer;
Elapsed_Leaps : Natural;
Next_Leap_N : Time_Rep;
Res_N : Time_Rep;
Rounded_Res_N : Time_Rep;
begin
-- Step 1: Check whether the day, month and year form a valid date
......@@ -1196,37 +1102,35 @@ package body Ada.Calendar is
raise Time_Error;
end if;
-- Start accumulating nanoseconds from the low bound of Ada time.
-- Note: This starting point includes the lower buffer dedicated
-- to time zones.
-- Start accumulating nanoseconds from the low bound of Ada time
Result_N := Ada_Low;
Res_N := Ada_Low;
-- Step 2: Year processing and centenial year adjustment. Determine
-- the number of four year segments since the start of Ada time and
-- the input date.
Count := (Year - Year_Number'First) / 4;
Result_N := Result_N + Time (Count) * Secs_In_Four_Years * Nano;
Count := (Year - Year_Number'First) / 4;
Res_N := Res_N + Time_Rep (Count) * Secs_In_Four_Years * Nano;
-- Note that non-leap centenial years are automatically considered
-- leap in the operation above. An adjustment of several days is
-- required to compensate for this.
if Year > 2300 then
Result_N := Result_N - Time (3) * Nanos_In_Day;
Res_N := Res_N - Time_Rep (3) * Nanos_In_Day;
elsif Year > 2200 then
Result_N := Result_N - Time (2) * Nanos_In_Day;
Res_N := Res_N - Time_Rep (2) * Nanos_In_Day;
elsif Year > 2100 then
Result_N := Result_N - Time (1) * Nanos_In_Day;
Res_N := Res_N - Time_Rep (1) * Nanos_In_Day;
end if;
-- Add the remaining non-leap years
Count := (Year - Year_Number'First) mod 4;
Result_N := Result_N + Time (Count) * Secs_In_Non_Leap_Year * Nano;
Count := (Year - Year_Number'First) mod 4;
Res_N := Res_N + Time_Rep (Count) * Secs_In_Non_Leap_Year * Nano;
-- Step 3: Day of month processing. Determine the number of days
-- since the start of the current year. Do not add the current
......@@ -1242,92 +1146,87 @@ package body Ada.Calendar is
Count := Count + 1;
end if;
Result_N := Result_N + Time (Count) * Nanos_In_Day;
Res_N := Res_N + Time_Rep (Count) * Nanos_In_Day;
-- Step 4: Hour, minute, second and sub second processing
if Use_Day_Secs then
Result_N := Result_N + To_Abs_Time (Day_Secs);
Res_N := Res_N + Duration_To_Time_Rep (Day_Secs);
else
Result_N := Result_N +
Time (Hour * 3_600 + Minute * 60 + Second) * Nano;
Res_N := Res_N +
Time_Rep (Hour * 3_600 + Minute * 60 + Second) * Nano;
if Sub_Sec = 1.0 then
Result_N := Result_N + Time (1) * Nano;
Res_N := Res_N + Time_Rep (1) * Nano;
else
Result_N := Result_N + To_Abs_Time (Sub_Sec);
Res_N := Res_N + Duration_To_Time_Rep (Sub_Sec);
end if;
end if;
-- At this point, the generated time value should be withing the
-- bounds of Ada time.
Check_Within_Time_Bounds (Res_N);
-- Step 4: Time zone processing. At this point we have built an
-- arbitrary time value which is not related to any time zone.
-- For simplicity, the time value is normalized to GMT, producing
-- a uniform representation which can be treated by arithmetic
-- operations for instance without any additional corrections.
if Result_N < Ada_Low
or else Result_N > Ada_High
then
raise Time_Error;
end if;
if Time_Zone /= 0 then
Abs_Time_Zone := Time (abs (Time_Zone)) * 60 * Nano;
if Time_Zone < 0 then
Result_N := Result_N + Abs_Time_Zone;
else
-- The following test is obsolete since the result already
-- contains the dedicated buffer for time zones, thus no
-- error will be raised. However it is a good idea to keep
-- this comparison should the representation of time change.
if Is_Ada_05 then
if Time_Zone /= 0 then
Res_N := Res_N - Time_Rep (Time_Zone) * 60 * Nano;
end if;
if Result_N < Abs_Time_Zone then
raise Time_Error;
end if;
-- Ada 83 and 95
Result_N := Result_N - Abs_Time_Zone;
end if;
else
declare
Current_Off : constant Long_Integer :=
Time_Zones_Operations.UTC_Time_Offset
(Time (Res_N));
Current_Res_N : constant Time_Rep :=
Res_N - Time_Rep (Current_Off) * Nano;
Off : constant Long_Integer :=
Time_Zones_Operations.UTC_Time_Offset
(Time (Current_Res_N));
begin
Res_N := Res_N - Time_Rep (Off) * Nano;
end;
end if;
-- Step 5: Leap seconds processing in GMT
Cumulative_Leap_Seconds
(Time_Zero, Result_N, Elapsed_Leaps, Next_Leap_N);
Result_N := Result_N + Time (Elapsed_Leaps) * Nano;
if Leap_Support then
Cumulative_Leap_Seconds
(Start_Of_Time, Res_N, Elapsed_Leaps, Next_Leap_N);
-- An Ada 2005 caller requesting an explicit leap second or an Ada
-- 95 caller accounting for an invisible leap second.
Res_N := Res_N + Time_Rep (Elapsed_Leaps) * Nano;
Rounded_Result_N := Result_N - (Result_N mod Nano);
-- An Ada 2005 caller requesting an explicit leap second or an
-- Ada 95 caller accounting for an invisible leap second.
if Leap_Sec
or else Rounded_Result_N = Next_Leap_N
then
Result_N := Result_N + Time (1) * Nano;
Rounded_Result_N := Rounded_Result_N + Time (1) * Nano;
end if;
if Leap_Sec
or else Res_N >= Next_Leap_N
then
Res_N := Res_N + Time_Rep (1) * Nano;
end if;
-- Leap second validity check
-- Leap second validity check
if Leap_Checks
and then Leap_Sec
and then Rounded_Result_N /= Next_Leap_N
then
raise Time_Error;
end if;
-- Final bounds check
Rounded_Res_N := Res_N - (Res_N mod Nano);
if Result_N < Hard_Ada_Low
or else Result_N > Hard_Ada_High_And_Leaps
then
raise Time_Error;
if Is_Ada_05
and then Leap_Sec
and then Rounded_Res_N /= Next_Leap_N
then
raise Time_Error;
end if;
end if;
return Result_N;
return Time (Res_N);
end Time_Of;
end Formatting_Operations;
......@@ -1337,35 +1236,33 @@ package body Ada.Calendar is
package body Time_Zones_Operations is
-- The Unix time bounds in seconds: 1970/1/1 .. 2037/1/1
-- The Unix time bounds in nanoseconds: 1970/1/1 .. 2037/1/1
Unix_Min : constant Time :=
Time (17 * 366 + 52 * 365 + 2) * Secs_In_Day;
-- 1970/1/1
Unix_Min : constant Time_Rep := Ada_Low +
Time_Rep (17 * 366 + 52 * 365) * Nanos_In_Day;
Unix_Max : constant Time :=
Time (34 * 366 + 102 * 365 + 2) * Secs_In_Day +
Time (Leap_Seconds_Count);
-- 2037/1/1
Unix_Max : constant Time_Rep := Ada_Low +
Time_Rep (34 * 366 + 102 * 365) * Nanos_In_Day +
Time_Rep (Leap_Seconds_Count) * Nano;
-- The following constants denote February 28 during non-leap
-- centenial years, the units are nanoseconds.
T_2100_2_28 : constant Time :=
(Time (49 * 366 + 150 * 365 + 59 + 2) * Secs_In_Day +
Time (Leap_Seconds_Count)) * Nano;
T_2100_2_28 : constant Time_Rep := Ada_Low +
(Time_Rep (49 * 366 + 150 * 365 + 59) * Secs_In_Day +
Time_Rep (Leap_Seconds_Count)) * Nano;
T_2200_2_28 : constant Time :=
(Time (73 * 366 + 226 * 365 + 59 + 2) * Secs_In_Day +
Time (Leap_Seconds_Count)) * Nano;
T_2200_2_28 : constant Time_Rep := Ada_Low +
(Time_Rep (73 * 366 + 226 * 365 + 59) * Secs_In_Day +
Time_Rep (Leap_Seconds_Count)) * Nano;
T_2300_2_28 : constant Time :=
(Time (97 * 366 + 302 * 365 + 59 + 2) * Secs_In_Day +
Time (Leap_Seconds_Count)) * Nano;
T_2300_2_28 : constant Time_Rep := Ada_Low +
(Time_Rep (97 * 366 + 302 * 365 + 59) * Secs_In_Day +
Time_Rep (Leap_Seconds_Count)) * Nano;
-- 56 years (14 leap years + 42 non leap years) in seconds:
-- 56 years (14 leap years + 42 non leap years) in nanoseconds:
Secs_In_56_Years : constant := (14 * 366 + 42 * 365) * Secs_In_Day;
Nanos_In_56_Years : constant := (14 * 366 + 42 * 365) * Nanos_In_Day;
-- Base C types. There is no point dragging in Interfaces.C just for
-- these four types.
......@@ -1378,17 +1275,17 @@ package body Ada.Calendar is
-- The Ada equivalent of struct tm and type time_t
type tm is record
tm_sec : int; -- seconds after the minute (0 .. 60)
tm_min : int; -- minutes after the hour (0 .. 59)
tm_hour : int; -- hours since midnight (0 .. 24)
tm_mday : int; -- day of the month (1 .. 31)
tm_mon : int; -- months since January (0 .. 11)
tm_year : int; -- years since 1900
tm_wday : int; -- days since Sunday (0 .. 6)
tm_yday : int; -- days since January 1 (0 .. 365)
tm_isdst : int; -- Daylight Savings Time flag (-1 .. 1)
tm_gmtoff : long; -- offset from UTC in seconds
tm_zone : char_Pointer; -- timezone abbreviation
tm_sec : int; -- seconds after the minute (0 .. 60)
tm_min : int; -- minutes after the hour (0 .. 59)
tm_hour : int; -- hours since midnight (0 .. 24)
tm_mday : int; -- day of the month (1 .. 31)
tm_mon : int; -- months since January (0 .. 11)
tm_year : int; -- years since 1900
tm_wday : int; -- days since Sunday (0 .. 6)
tm_yday : int; -- days since January 1 (0 .. 365)
tm_isdst : int; -- Daylight Savings Time flag (-1 .. 1)
tm_gmtoff : long; -- offset from UTC in seconds
tm_zone : char_Pointer; -- timezone abbreviation
end record;
type tm_Pointer is access all tm;
......@@ -1411,24 +1308,22 @@ package body Ada.Calendar is
---------------------
function UTC_Time_Offset (Date : Time) return Long_Integer is
Adj_Cent : Integer := 0;
Adj_Date_N : Time;
Adj_Date_S : Time;
Offset : aliased long;
Secs_T : aliased time_t;
Secs_TM : aliased tm;
Adj_Cent : Integer := 0;
Date_N : Time_Rep;
Offset : aliased long;
Secs_T : aliased time_t;
Secs_TM : aliased tm;
begin
Adj_Date_N := Date;
Date_N := Time_Rep (Date);
-- Dates which are 56 years appart fall on the same day, day light
-- saving and so on. Non-leap centenial years violate this rule by
-- one day and as a consequence, special adjustment is needed.
if Adj_Date_N > T_2100_2_28 then
if Adj_Date_N > T_2200_2_28 then
if Adj_Date_N > T_2300_2_28 then
if Date_N > T_2100_2_28 then
if Date_N > T_2200_2_28 then
if Date_N > T_2300_2_28 then
Adj_Cent := 3;
else
Adj_Cent := 2;
......@@ -1440,25 +1335,26 @@ package body Ada.Calendar is
end if;
if Adj_Cent > 0 then
Adj_Date_N := Adj_Date_N - Time (Adj_Cent) * Nanos_In_Day;
Date_N := Date_N - Time_Rep (Adj_Cent) * Nanos_In_Day;
end if;
-- Convert to seconds and shift date within bounds of Unix time
-- Shift the date within bounds of Unix time
Adj_Date_S := Adj_Date_N / Nano;
while Adj_Date_S < Unix_Min loop
Adj_Date_S := Adj_Date_S + Secs_In_56_Years;
while Date_N < Unix_Min loop
Date_N := Date_N + Nanos_In_56_Years;
end loop;
while Adj_Date_S >= Unix_Max loop
Adj_Date_S := Adj_Date_S - Secs_In_56_Years;
while Date_N >= Unix_Max loop
Date_N := Date_N - Nanos_In_56_Years;
end loop;
-- Perform a shift in origins from Ada to Unix
Adj_Date_S := Adj_Date_S - Unix_Min;
Date_N := Date_N - Unix_Min;
-- Convert the date into seconds
Secs_T := time_t (Adj_Date_S);
Secs_T := time_t (Date_N / Nano);
localtime_tzoff
(Secs_T'Unchecked_Access,
......@@ -1476,67 +1372,69 @@ begin
-- Population of the leap seconds table
declare
type Leap_Second_Date is record
Year : Year_Number;
Month : Month_Number;
Day : Day_Number;
end record;
Leap_Second_Dates :
constant array (1 .. Leap_Seconds_Count) of Leap_Second_Date :=
((1972, 6, 30), (1972, 12, 31), (1973, 12, 31), (1974, 12, 31),
(1975, 12, 31), (1976, 12, 31), (1977, 12, 31), (1978, 12, 31),
(1979, 12, 31), (1981, 6, 30), (1982, 6, 30), (1983, 6, 30),
(1985, 6, 30), (1987, 12, 31), (1989, 12, 31), (1990, 12, 31),
(1992, 6, 30), (1993, 6, 30), (1994, 6, 30), (1995, 12, 31),
(1997, 6, 30), (1998, 12, 31), (2005, 12, 31));
Days_In_Four_Years : constant := 365 * 3 + 366;
Days : Natural;
Leap : Leap_Second_Date;
Years : Natural;
if Leap_Support then
declare
type Leap_Second_Date is record
Year : Year_Number;
Month : Month_Number;
Day : Day_Number;
end record;
Leap_Second_Dates :
constant array (1 .. Leap_Seconds_Count) of Leap_Second_Date :=
((1972, 6, 30), (1972, 12, 31), (1973, 12, 31), (1974, 12, 31),
(1975, 12, 31), (1976, 12, 31), (1977, 12, 31), (1978, 12, 31),
(1979, 12, 31), (1981, 6, 30), (1982, 6, 30), (1983, 6, 30),
(1985, 6, 30), (1987, 12, 31), (1989, 12, 31), (1990, 12, 31),
(1992, 6, 30), (1993, 6, 30), (1994, 6, 30), (1995, 12, 31),
(1997, 6, 30), (1998, 12, 31), (2005, 12, 31));
Days_In_Four_Years : constant := 365 * 3 + 366;
Days : Natural;
Leap : Leap_Second_Date;
Years : Natural;
begin
for Index in 1 .. Leap_Seconds_Count loop
Leap := Leap_Second_Dates (Index);
begin
for Index in 1 .. Leap_Seconds_Count loop
Leap := Leap_Second_Dates (Index);
-- Calculate the number of days from the start of Ada time until
-- the current leap second occurence. Non-leap centenial years
-- are not accounted for in these calculations since there are
-- no leap seconds after 2100 yet.
-- Calculate the number of days from the start of Ada time until
-- the current leap second occurence. Non-leap centenial years
-- are not accounted for in these calculations since there are
-- no leap seconds after 2100 yet.
Years := Leap.Year - Ada_Min_Year;
Days := (Years / 4) * Days_In_Four_Years;
Years := Years mod 4;
Years := Leap.Year - Ada_Min_Year;
Days := (Years / 4) * Days_In_Four_Years;
Years := Years mod 4;
if Years = 1 then
Days := Days + 365;
if Years = 1 then
Days := Days + 365;
elsif Years = 2 then
Days := Days + 365 * 2;
elsif Years = 2 then
Days := Days + 365 * 2;
elsif Years = 3 then
Days := Days + 365 * 3;
end if;
elsif Years = 3 then
Days := Days + 365 * 3;
end if;
Days := Days + Cumulative_Days_Before_Month (Leap.Month);
Days := Days + Cumulative_Days_Before_Month (Leap.Month);
if Is_Leap (Leap.Year)
and then Leap.Month > 2
then
Days := Days + 1;
end if;
if Is_Leap (Leap.Year)
and then Leap.Month > 2
then
Days := Days + 1;
end if;
Days := Days + Leap.Day;
Days := Days + Leap.Day;
-- Index - 1 previous leap seconds are added to Time (Index) as
-- well as the lower buffer for time zones.
-- Index - 1 previous leap seconds are added to Time (Index) as
-- well as the lower buffer for time zones.
Leap_Second_Times (Index) := Ada_Low +
(Time (Days) * Secs_In_Day + Time (Index - 1)) * Nano;
end loop;
end;
Leap_Second_Times (Index) := Ada_Low +
(Time_Rep (Days) * Secs_In_Day + Time_Rep (Index - 1)) * Nano;
end loop;
end;
end if;
end Ada.Calendar;
......@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
-- Copyright (C) 1992-2006, Free Software Foundation, Inc. --
-- Copyright (C) 1992-2007, Free Software Foundation, Inc. --
-- --
-- This specification is derived from the Ada Reference Manual for use with --
-- GNAT. The copyright notice above, and the license provisions that follow --
......@@ -53,7 +53,7 @@ package Ada.Calendar is
function Clock return Time;
-- The returned time value is the number of nanoseconds since the start
-- of Ada time (1901-1-1 0.0 GMT).
-- of Ada time (1901-01-01 00:00:00.0 UTC).
function Year (Date : Time) return Year_Number;
function Month (Date : Time) return Month_Number;
......@@ -68,8 +68,8 @@ package Ada.Calendar is
Seconds : out Day_Duration);
-- Break down a time value into its date components set in the current
-- time zone. If Split is called on a time value created using Ada 2005
-- Time_Of in some arbitrary time zone, the input value always will be
-- interpreted as some point in time relative to the local time zone.
-- Time_Of in some arbitrary time zone, the input value will always be
-- interpreted as relative to the local time zone.
function Time_Of
(Year : Year_Number;
......@@ -96,8 +96,8 @@ package Ada.Calendar is
function "-" (Left : Time; Right : Duration) return Time;
function "-" (Left : Time; Right : Time) return Duration;
-- The first three functions will raise Time_Error if the resulting time
-- value is less than the start of Ada time in GMT or greater than the
-- end of Ada time in GMT. The last function will raise Time_Error if the
-- value is less than the start of Ada time in UTC or greater than the
-- end of Ada time in UTC. The last function will raise Time_Error if the
-- resulting difference cannot fit into a duration value.
function "<" (Left, Right : Time) return Boolean;
......@@ -135,16 +135,16 @@ private
-- Implementation of Time --
----------------------------
-- Time is represented as an unsigned 64 bit integer count of nanoseconds
-- since the start of Ada time (1901-1-1 0.0 GMT). Time values produced
-- by Time_Of are internaly normalized to GMT regardless of their local
-- time zone. This representation ensures correct handling of leap seconds
-- as well as performing arithmetic. In Ada 95, Split will treat a time
-- value as being in the local time zone and break it down accordingly.
-- In Ada 2005, Split will treat a time value as being in the designated
-- time zone by the corresponding formal parameter or in GMT by default.
-- The size of the type is large enough to cover the Ada 2005 range of
-- time (1901-1-1 0.0 GMT - 2399-12-31-86_399.999999999 GMT).
-- Time is represented as a signed 64 bit integer count of nanoseconds
-- since the start of Ada time (1901-01-01 00:00:00.0 UTC). Time values
-- produced by Time_Of are internaly normalized to UTC regardless of their
-- local time zone. This representation ensures correct handling of leap
-- seconds as well as performing arithmetic. In Ada 95, Split and Time_Of
-- will treat a time value as being in the local time zone, in Ada 2005,
-- Split and Time_Of will treat a time value as being in the designated
-- time zone by the formal parameter or in UTC by default. The size of the
-- type is large enough to cover the Ada 2005 range of time (1901-01-01
-- 00:00:00.0 UTC - 2399-12-31-23:59:59.999999999 UTC).
------------------
-- Leap seconds --
......@@ -155,17 +155,19 @@ private
-- leap second is added after the last day of June or December. The count
-- of seconds during those occurences becomes:
-- ... 58, 59, leap second 60, 1, 2 ...
-- ... 58, 59, leap second 60, 0, 1, 2 ...
-- Unlike leap days, leap seconds occur simultaneously around the world.
-- In other words, if a leap second occurs at 23:59:60 GMT, it also occurs
-- on 18:59:60 -5 or 2:59:60 +2 on the next day.
-- In other words, if a leap second occurs at 23:59:60 UTC, it also occurs
-- on 18:59:60 -5 the same day or 2:59:60 +2 on the next day.
-- Leap seconds do not follow a formula. The International Earth Rotation
-- and Reference System Service decides when to add one. Leap seconds are
-- included in the representation of time in Ada 95 mode. As a result,
-- the following two time values will conceptually differ by two seconds:
-- the following two time values will differ by two seconds:
-- Time_Of (1972, 7, 1, 0.0) - Time_Of (1972, 6, 30, 86_399.0) = 2 secs
-- 1972-06-30 23:59:59.0
-- 1972-07-01 00:00:00.0
-- When a new leap second is added, the following steps must be carried
-- out:
......@@ -185,41 +187,14 @@ private
-- non-leap. As a consequence, seven non-leap years occur over the period
-- of year - 4 to year + 4. Internaly, routines Split and Time_Of add or
-- subtract a "fake" February 29 to facilitate the arithmetic involved.
-- This small "cheat" remains hidden and the following calculations do
-- produce the correct difference.
-- Time_Of (2100, 3, 1, 0.0) - Time_Of (2100, 2, 28, 0.0) = 1 day
-- Time_Of (2101, 1, 1, 0.0) - Time_Of (2100, 12, 31, 0.0) = 1 day
-- The underlying type of Time has been chosen to be a 64 bit signed
-- integer number since it allows for easier processing of sub seconds
-- and arithmetic.
type Time_Rep is mod 2 ** 64;
type Time_Rep is range -2 ** 63 .. +2 ** 63 - 1;
type Time is new Time_Rep;
-- Due to boundary time values and time zones, two days of buffer space
-- are set aside at both end points of Ada time:
-- Abs zero Hard low Soft low Soft high Hard high
-- +---------+============+#################+============+----------->
-- Buffer 1 Real Ada time Buffer 2
-- A time value in a any time zone may not excede the hard bounds of Ada
-- time, while a value in GMT may not go over the soft bounds.
Buffer_D : constant Duration := 2.0 * Secs_In_Day;
Buffer_N : constant Time := 2 * Nanos_In_Day;
-- Lower and upper bound of Ada time shifted by two days from the absolute
-- zero. Note that the upper bound includes the non-leap centenial years.
Ada_Low : constant Time := Buffer_N;
Ada_High : constant Time := (121 * 366 + 378 * 365) * Nanos_In_Day +
Buffer_N;
-- Both of these hard bounds are 28 hours before and after their regular
-- counterpart. The value of 28 is taken from Ada.Calendar.Time_Zones.
Hard_Ada_Low : constant Time := Ada_Low - 100_800 * Nano;
Hard_Ada_High : constant Time := Ada_High + 100_800 * Nano;
Days_In_Month : constant array (Month_Number) of Day_Number :=
(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
......@@ -234,7 +209,7 @@ private
package Arithmetic_Operations is
function Add (Date : Time; Days : Long_Integer) return Time;
-- Add X number of days to a time value
-- Add a certain number of days to a time value
procedure Difference
(Left : Time;
......@@ -248,11 +223,11 @@ private
-- values are positive, negative otherwise.
function Subtract (Date : Time; Days : Long_Integer) return Time;
-- Subtract X number of days from a time value
-- Subtract a certain number of days from a time value
end Arithmetic_Operations;
package Delays_Operations is
function To_Duration (Ada_Time : Time) return Duration;
function To_Duration (Date : Time) return Duration;
-- Given a time value in nanoseconds since 1901, convert it into a
-- duration value giving the number of nanoseconds since the Unix Epoch.
end Delays_Operations;
......@@ -263,18 +238,21 @@ private
-- within the range of 0 .. 6 (Monday .. Sunday).
procedure Split
(Date : Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Day_Secs : out Day_Duration;
Hour : out Integer;
Minute : out Integer;
Second : out Integer;
Sub_Sec : out Duration;
Leap_Sec : out Boolean;
Time_Zone : Long_Integer);
-- Split a time value into its components
(Date : Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Day_Secs : out Day_Duration;
Hour : out Integer;
Minute : out Integer;
Second : out Integer;
Sub_Sec : out Duration;
Leap_Sec : out Boolean;
Is_Ada_05 : Boolean;
Time_Zone : Long_Integer);
-- Split a time value into its components. Set Is_Ada_05 to use the
-- local time zone (the value in Time_Zone is ignored) when splitting
-- a time value.
function Time_Of
(Year : Year_Number;
......@@ -286,19 +264,20 @@ private
Second : Integer;
Sub_Sec : Duration;
Leap_Sec : Boolean;
Leap_Checks : Boolean;
Use_Day_Secs : Boolean;
Is_Ada_05 : Boolean;
Time_Zone : Long_Integer) return Time;
-- Given all the components of a date, return the corresponding time
-- value. Set Use_Day_Secs to use the value in Day_Secs, otherwise the
-- day duration will be calculated from Hour, Minute, Second and Sub_
-- Sec. Set flag Leap_Checks to verify the validity of a leap second.
-- Sec. Set Is_Ada_05 to use the local time zone (the value in formal
-- Time_Zone is ignored) when building a time value and to verify the
-- validity of a requested leap second.
end Formatting_Operations;
package Time_Zones_Operations is
function UTC_Time_Offset (Date : Time) return Long_Integer;
-- Return the offset in seconds from GMT
-- Return the offset in seconds from UTC
end Time_Zones_Operations;
end Ada.Calendar;
......@@ -457,7 +457,18 @@ package body Ada.Calendar.Formatting is
begin
Formatting_Operations.Split
(Date, Year, Month, Day, Seconds, H, M, Se, Su, Leap_Second, Tz);
(Date => Date,
Year => Year,
Month => Month,
Day => Day,
Day_Secs => Seconds,
Hour => H,
Minute => M,
Second => Se,
Sub_Sec => Su,
Leap_Sec => Leap_Second,
Time_Zone => Tz,
Is_Ada_05 => True);
-- Validity checks
......@@ -491,8 +502,18 @@ package body Ada.Calendar.Formatting is
begin
Formatting_Operations.Split
(Date, Year, Month, Day, Dd,
Hour, Minute, Second, Sub_Second, Le, Tz);
(Date => Date,
Year => Year,
Month => Month,
Day => Day,
Day_Secs => Dd,
Hour => Hour,
Minute => Minute,
Second => Second,
Sub_Sec => Sub_Second,
Leap_Sec => Le,
Time_Zone => Tz,
Is_Ada_05 => True);
-- Validity checks
......@@ -529,8 +550,18 @@ package body Ada.Calendar.Formatting is
begin
Formatting_Operations.Split
(Date, Year, Month, Day, Dd,
Hour, Minute, Second, Sub_Second, Leap_Second, Tz);
(Date => Date,
Year => Year,
Month => Month,
Day => Day,
Day_Secs => Dd,
Hour => Hour,
Minute => Minute,
Second => Second,
Sub_Sec => Sub_Second,
Leap_Sec => Leap_Second,
Time_Zone => Tz,
Is_Ada_05 => True);
-- Validity checks
......@@ -621,10 +652,17 @@ package body Ada.Calendar.Formatting is
return
Formatting_Operations.Time_Of
(Adj_Year, Adj_Month, Adj_Day, Seconds, H, M, Se, Ss,
(Year => Adj_Year,
Month => Adj_Month,
Day => Adj_Day,
Day_Secs => Seconds,
Hour => H,
Minute => M,
Second => Se,
Sub_Sec => Ss,
Leap_Sec => Leap_Second,
Leap_Checks => True,
Use_Day_Secs => True,
Is_Ada_05 => True,
Time_Zone => Tz);
end Time_Of;
......@@ -663,10 +701,17 @@ package body Ada.Calendar.Formatting is
return
Formatting_Operations.Time_Of
(Year, Month, Day, Dd, Hour, Minute, Second, Sub_Second,
(Year => Year,
Month => Month,
Day => Day,
Day_Secs => Dd,
Hour => Hour,
Minute => Minute,
Second => Second,
Sub_Sec => Sub_Second,
Leap_Sec => Leap_Second,
Leap_Checks => True,
Use_Day_Secs => False,
Is_Ada_05 => True,
Time_Zone => Tz);
end Time_Of;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment