2007-04-20 Hristian Kirtchev <kirtchev@adacore.com>
authorHristian Kirtchev <kirtchev@adacore.com>
Wed, 6 Jun 2007 10:14:46 +0000 (12:14 +0200)
committerArnaud Charlet <charlet@gcc.gnu.org>
Wed, 6 Jun 2007 10:14:46 +0000 (12:14 +0200)
* 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

gcc/ada/a-calend-vms.adb
gcc/ada/a-calend-vms.ads
gcc/ada/a-calend.adb
gcc/ada/a-calend.ads
gcc/ada/a-calfor.adb

index 7c8fa12bbfeccff7d2090744c5b193d187c54cc0..4707e133e5affa10d69be1073e54fbb9dc96419f 100644 (file)
@@ -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;
index 6fc05f3f80ab84c6b18353475e79c2a8ce6a0cb1..f0c974927326b091ba93215d5cde70179ad28719 100644 (file)
@@ -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;
index 0af43fd7536ecbc9284db5f94c13f0ecccce55fd..c2dc77c76519e2af02bccbb1945f9a8eafd283b0 100644 (file)
@@ -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;
index 7bac8b762f0ef16a27fad8f47c8ddbb81f76cde2..711cd22af7e2171d771d9b25303e7941e6b869e3 100644 (file)
@@ -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;
index c870362d400a3b981c6ee10ac46aeee2710b1074..b8a8c01e7b666414496c192a8fed7fbfd44db8a7 100644 (file)
@@ -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;