aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/a-calend.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/a-calend.adb')
-rw-r--r--gcc/ada/a-calend.adb254
1 files changed, 135 insertions, 119 deletions
diff --git a/gcc/ada/a-calend.adb b/gcc/ada/a-calend.adb
index f5fbbd5..731c4ed 100644
--- a/gcc/ada/a-calend.adb
+++ b/gcc/ada/a-calend.adb
@@ -30,7 +30,7 @@
------------------------------------------------------------------------------
with Ada.Unchecked_Conversion;
-
+with Interfaces.C;
with System.OS_Primitives;
package body Ada.Calendar is
@@ -109,6 +109,21 @@ package body Ada.Calendar is
new Ada.Unchecked_Conversion (Time_Rep, Duration);
-- Convert a time representation value into a duration value
+ function UTC_Time_Offset
+ (Date : Time;
+ Is_Historic : Boolean) return Long_Integer;
+ -- This routine acts as an Ada wrapper around __gnat_localtime_tzoff which
+ -- in turn utilizes various OS-dependent mechanisms to calculate the time
+ -- zone offset of a date. Formal parameter Date represents an arbitrary
+ -- time stamp, either in the past, now, or in the future. If flag
+ -- Is_Historic is set, this routine would try to calculate to the best of
+ -- the OS's abilities the time zone offset that was or will be in effect
+ -- on Date. If the flag is set to False, the routine returns the current
+ -- time zone with Date effectively set to Clock.
+ -- NOTE: Targets which support localtime_r will aways return a historic
+ -- time zone even if flag Is_Historic is set to False because this is how
+ -- localtime_r operates.
+
-----------------
-- Local Types --
-----------------
@@ -176,6 +191,13 @@ package body Ada.Calendar is
Unix_Min : constant Time_Rep :=
Ada_Low + Time_Rep (17 * 366 + 52 * 365) * Nanos_In_Day;
+ -- The Unix upper time bound expressed as nonoseconds since the start of
+ -- Ada time in UTC.
+
+ Unix_Max : constant Time_Rep :=
+ Ada_Low + Time_Rep (34 * 366 + 102 * 365) * Nanos_In_Day +
+ Time_Rep (Leap_Seconds_Count) * Nano;
+
Epoch_Offset : constant Time_Rep := (136 * 365 + 44 * 366) * Nanos_In_Day;
-- The difference between 2150-1-1 UTC and 1970-1-1 UTC expressed in
-- nanoseconds. Note that year 2100 is non-leap.
@@ -626,6 +648,110 @@ package body Ada.Calendar is
Time_Zone => 0);
end Time_Of;
+ ---------------------
+ -- UTC_Time_Offset --
+ ---------------------
+
+ function UTC_Time_Offset
+ (Date : Time;
+ Is_Historic : Boolean) return Long_Integer
+ is
+ -- The following constants denote February 28 during non-leap centennial
+ -- years, the units are nanoseconds.
+
+ 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_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_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 nanoseconds:
+
+ Nanos_In_56_Years : constant := (14 * 366 + 42 * 365) * Nanos_In_Day;
+
+ type int_Pointer is access all Interfaces.C.int;
+ type long_Pointer is access all Interfaces.C.long;
+
+ type time_t is
+ range -(2 ** (Standard'Address_Size - Integer'(1))) ..
+ +(2 ** (Standard'Address_Size - Integer'(1)) - 1);
+ type time_t_Pointer is access all time_t;
+
+ procedure localtime_tzoff
+ (timer : time_t_Pointer;
+ is_historic : int_Pointer;
+ off : long_Pointer);
+ pragma Import (C, localtime_tzoff, "__gnat_localtime_tzoff");
+ -- This routine is a interfacing wrapper around the library function
+ -- __gnat_localtime_tzoff. Parameter 'timer' represents a Unix-based
+ -- time equivalent of the input date. If flag 'is_historic' is set, this
+ -- routine would try to calculate to the best of the OS's abilities the
+ -- time zone offset that was or will be in effect on 'timer'. If the
+ -- flag is set to False, the routine returns the current time zone
+ -- regardless of what 'timer' designates. Parameter 'off' captures the
+ -- UTC offset of 'timer'.
+
+ Adj_Cent : Integer;
+ Date_N : Time_Rep;
+ Flag : aliased Interfaces.C.int;
+ Offset : aliased Interfaces.C.long;
+ Secs_T : aliased time_t;
+
+ -- Start of processing for UTC_Time_Offset
+
+ begin
+ Date_N := Time_Rep (Date);
+
+ -- Dates which are 56 years apart fall on the same day, day light saving
+ -- and so on. Non-leap centennial years violate this rule by one day and
+ -- as a consequence, special adjustment is needed.
+
+ Adj_Cent :=
+ (if Date_N <= T_2100_2_28 then 0
+ elsif Date_N <= T_2200_2_28 then 1
+ elsif Date_N <= T_2300_2_28 then 2
+ else 3);
+
+ if Adj_Cent > 0 then
+ Date_N := Date_N - Time_Rep (Adj_Cent) * Nanos_In_Day;
+ end if;
+
+ -- Shift the date within bounds of Unix time
+
+ while Date_N < Unix_Min loop
+ Date_N := Date_N + Nanos_In_56_Years;
+ end loop;
+
+ 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
+
+ Date_N := Date_N - Unix_Min;
+
+ -- Convert the date into seconds
+
+ Secs_T := time_t (Date_N / Nano);
+
+ -- Determine whether to treat the input date as historical or not
+
+ Flag := (if Is_Historic then 1 else 0);
+
+ localtime_tzoff
+ (Secs_T'Unchecked_Access,
+ Flag'Unchecked_Access,
+ Offset'Unchecked_Access);
+
+ return Long_Integer (Offset);
+ end UTC_Time_Offset;
+
----------
-- Year --
----------
@@ -1024,11 +1150,7 @@ package body Ada.Calendar is
function Day_Of_Week (Date : Time) return Integer is
Date_N : constant Time_Rep := Time_Rep (Date);
- Time_Zone : constant Long_Integer :=
- Time_Zones_Operations.UTC_Time_Offset
- (Date => Date,
- Is_Historic => False);
-
+ Time_Zone : constant Long_Integer := UTC_Time_Offset (Date, True);
Ada_Low_N : Time_Rep;
Day_Count : Long_Integer;
Day_Dur : Time_Dur;
@@ -1141,9 +1263,8 @@ package body Ada.Calendar is
else
declare
Off : constant Long_Integer :=
- Time_Zones_Operations.UTC_Time_Offset
- (Date => Time (Date_N),
- Is_Historic => False);
+ UTC_Time_Offset (Time (Date_N), False);
+
begin
Date_N := Date_N + Time_Rep (Off) * Nano;
end;
@@ -1364,15 +1485,12 @@ package body Ada.Calendar is
else
declare
Current_Off : constant Long_Integer :=
- Time_Zones_Operations.UTC_Time_Offset
- (Date => Time (Res_N),
- Is_Historic => False);
+ UTC_Time_Offset (Time (Res_N), False);
Current_Res_N : constant Time_Rep :=
Res_N - Time_Rep (Current_Off) * Nano;
Off : constant Long_Integer :=
- Time_Zones_Operations.UTC_Time_Offset
- (Date => Time (Current_Res_N),
- Is_Historic => False);
+ UTC_Time_Offset (Time (Current_Res_N), False);
+
begin
Res_N := Res_N - Time_Rep (Off) * Nano;
end;
@@ -1416,115 +1534,13 @@ package body Ada.Calendar is
package body Time_Zones_Operations is
- -- The Unix time bounds in nanoseconds: 1970/1/1 .. 2037/1/1
-
- Unix_Min : constant Time_Rep := Ada_Low +
- Time_Rep (17 * 366 + 52 * 365) * Nanos_In_Day;
-
- 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
- -- centennial years, the units are nanoseconds.
-
- 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_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_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 nanoseconds:
-
- Nanos_In_56_Years : constant := (14 * 366 + 42 * 365) * Nanos_In_Day;
-
- subtype long is Long_Integer;
- subtype int is Integer;
- type long_Pointer is access all long;
- type int_Pointer is access all int;
-
- type time_t is
- range -(2 ** (Standard'Address_Size - Integer'(1))) ..
- +(2 ** (Standard'Address_Size - Integer'(1)) - 1);
- type time_t_Pointer is access all time_t;
-
- procedure localtime_tzoff
- (timer : time_t_Pointer;
- is_historic : int_Pointer;
- off : long_Pointer);
- pragma Import (C, localtime_tzoff, "__gnat_localtime_tzoff");
- -- This is a lightweight wrapper around the system library function
- -- localtime_r. Parameter 'off' captures the UTC offset which is either
- -- retrieved from the tm struct or calculated from the 'timezone' extern
- -- and the tm_isdst flag in the tm struct. Flag 'is_historic' denotes
- -- whether 'timer' is a historical time stamp. If this is not the case,
- -- the routine returns the offset of the local time zone.
-
---------------------
-- UTC_Time_Offset --
---------------------
- function UTC_Time_Offset
- (Date : Time;
- Is_Historic : Boolean := True) return Long_Integer
- is
- Adj_Cent : Integer;
- Date_N : Time_Rep;
- Flag : aliased int;
- Offset : aliased long;
- Secs_T : aliased time_t;
-
+ function UTC_Time_Offset (Date : Time) return Long_Integer is
begin
- Date_N := Time_Rep (Date);
-
- -- Dates which are 56 years apart fall on the same day, day light
- -- saving and so on. Non-leap centennial years violate this rule by
- -- one day and as a consequence, special adjustment is needed.
-
- Adj_Cent :=
- (if Date_N <= T_2100_2_28 then 0
- elsif Date_N <= T_2200_2_28 then 1
- elsif Date_N <= T_2300_2_28 then 2
- else 3);
-
- if Adj_Cent > 0 then
- Date_N := Date_N - Time_Rep (Adj_Cent) * Nanos_In_Day;
- end if;
-
- -- Shift the date within bounds of Unix time
-
- while Date_N < Unix_Min loop
- Date_N := Date_N + Nanos_In_56_Years;
- end loop;
-
- 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
-
- Date_N := Date_N - Unix_Min;
-
- -- Convert the date into seconds
-
- Secs_T := time_t (Date_N / Nano);
-
- -- Determine whether to treat the input date as historical or not
-
- Flag := (if Is_Historic then 1 else 0);
-
- localtime_tzoff
- (Secs_T'Unchecked_Access,
- Flag'Unchecked_Access,
- Offset'Unchecked_Access);
-
- return Offset;
+ return UTC_Time_Offset (Date, True);
end UTC_Time_Offset;
end Time_Zones_Operations;