[Ada] Time_IO.Image: Allow printing the time zone

Message ID 20200706113855.GA135650@adacore.com
State New
Headers show
Series
  • [Ada] Time_IO.Image: Allow printing the time zone
Related show

Commit Message

Pierre-Marie de Rodat July 6, 2020, 11:38 a.m.
This patch adds support to Image for the GNU standard format "%:::z",
which prints the time zone in the format "+hh", "-hh", "+hh:mm", or
"-hh:mm", as appropriate. We do not support any of the other standard
GNU time-zone formats (%z, %:z, %::z, %Z).

Tested on x86_64-pc-linux-gnu, committed on trunk

gcc/ada/

	* libgnat/g-catiio.ads: Document newly supported format.  Add
	ISO_Time constant, for convenience.
	* libgnat/g-catiio.adb (Image_Helper): New helper function to do
	all the formatting work, called by the two exported Image
	functions.  Add support for "%:::z" here. Add a Time_Zone
	parameter used by the "%:::z" processing. This parameter is not
	used for the actual time zone computations; local time is always
	used for that, for ease of implementation reasons.  It would
	make sense to use Append throughout this function, but that's a
	cleanup for another day.
	(Image): Modify these to pass the local time zone, or the
	specified time zone, as appropriate.

Patch

diff --git a/gcc/ada/libgnat/g-catiio.adb b/gcc/ada/libgnat/g-catiio.adb
--- a/gcc/ada/libgnat/g-catiio.adb
+++ b/gcc/ada/libgnat/g-catiio.adb
@@ -69,6 +69,14 @@  package body GNAT.Calendar.Time_IO is
    -- Local Subprograms --
    -----------------------
 
+   function Image_Helper
+     (Date      : Ada.Calendar.Time;
+      Picture   : Picture_String;
+      Time_Zone : Time_Zones.Time_Offset) return String;
+   --  This is called by the two exported Image functions. It uses the local
+   --  time zone for its computations, but uses Time_Zone when interpreting the
+   --  "%:::z" tag.
+
    function Am_Pm (H : Natural) return String;
    --  Return AM or PM depending on the hour H
 
@@ -168,6 +176,10 @@  package body GNAT.Calendar.Time_IO is
       return Image (Sec_Number (N), Padding, Length);
    end Image;
 
+   -----------
+   -- Image --
+   -----------
+
    function Image
      (N       : Sec_Number;
       Padding : Padding_Mode := Zero;
@@ -213,15 +225,16 @@  package body GNAT.Calendar.Time_IO is
       Time_Zone : Time_Zones.Time_Offset) return String
    is
       --  We subtract off the local time zone, and add in the requested
-      --  Time_Zone, and then pass it on to the version of Image that uses
-      --  the local time zone.
+      --  Time_Zone, and then pass it on to Image_Helper, which uses the
+      --  local time zone.
 
       use Time_Zones;
       Local_TZ : constant Time_Offset := Local_Time_Offset (Date);
       Minute_Offset : constant Integer := Integer (Time_Zone - Local_TZ);
       Second_Offset : constant Integer := Minute_Offset * 60;
    begin
-      return Image (Date + Duration (Second_Offset), Picture);
+      return Image_Helper
+        (Date + Duration (Second_Offset), Picture, Time_Zone);
    end Image;
 
    -----------
@@ -232,6 +245,21 @@  package body GNAT.Calendar.Time_IO is
      (Date    : Ada.Calendar.Time;
       Picture : Picture_String) return String
    is
+      use Time_Zones;
+      Local_TZ : constant Time_Offset := Local_Time_Offset (Date);
+   begin
+      return Image_Helper (Date, Picture, Local_TZ);
+   end Image;
+
+   ------------------
+   -- Image_Helper --
+   ------------------
+
+   function Image_Helper
+     (Date      : Ada.Calendar.Time;
+      Picture   : Picture_String;
+      Time_Zone : Time_Zones.Time_Offset) return String
+   is
       Padding : Padding_Mode := Zero;
       --  Padding is set for one directive
 
@@ -424,6 +452,43 @@  package body GNAT.Calendar.Time_IO is
                     Image (Minute, Padding, Length => 2) & ':' &
                     Image (Second, Padding, Length => 2);
 
+               --  Time zone. Append "+hh", "-hh", "+hh:mm", or "-hh:mm", as
+               --  appropriate.
+
+               when ':' =>
+                  declare
+                     use type Time_Zones.Time_Offset;
+                     TZ_Form : constant Picture_String := "%:::z";
+                     TZ : constant Natural := Natural (abs Time_Zone);
+                  begin
+                     if P + TZ_Form'Length - 1 <= Picture'Last
+                       and then Picture (P .. P + TZ_Form'Length - 1) = "%:::z"
+                     then
+                        if Time_Zone >= 0 then
+                           Result := Result & "+";
+                        else
+                           Result := Result & "-";
+                        end if;
+
+                        Result := Result &
+                          Image (Integer (TZ / 60), Padding, Length => 2);
+
+                        if TZ mod 60 /= 0 then
+                           Result := Result & ":";
+                           Result := Result &
+                             Image (TZ mod 60, Padding, Length => 2);
+                        end if;
+
+                        P := P + TZ_Form'Length - 2; -- will add 2 below
+
+                     --  We do not support any of the other standard GNU
+                     --  time-zone formats (%z, %:z, %::z, %Z).
+
+                     else
+                        raise Picture_Error with "unsupported picture format";
+                     end if;
+                  end;
+
                --  Locale's abbreviated weekday name (Sun..Sat)
 
                when 'a' =>
@@ -550,7 +615,7 @@  package body GNAT.Calendar.Time_IO is
       end loop;
 
       return To_String (Result);
-   end Image;
+   end Image_Helper;
 
    --------------------------
    -- Month_Name_To_Number --


diff --git a/gcc/ada/libgnat/g-catiio.ads b/gcc/ada/libgnat/g-catiio.ads
--- a/gcc/ada/libgnat/g-catiio.ads
+++ b/gcc/ada/libgnat/g-catiio.ads
@@ -43,7 +43,7 @@  package GNAT.Calendar.Time_IO is
    --  This is a string to describe date and time output format. The string is
    --  a set of standard character and special tag that are replaced by the
    --  corresponding values. It follows the GNU Date specification. Here are
-   --  the recognized directives :
+   --  the recognized directives:
    --
    --          %    a literal %
    --          n    a newline
@@ -62,6 +62,8 @@  package GNAT.Calendar.Time_IO is
    --                (a nonstandard extension)
    --          %S   second (00..59)
    --          %T   time, 24-hour (hh:mm:ss)
+   --          %:::z  numeric time zone with : to necessary precision
+   --                 (e.g., -04, +05:30)
    --
    --          Date fields:
    --
@@ -98,8 +100,11 @@  package GNAT.Calendar.Time_IO is
    --          %e   microseconds (6 digits)
    --          %o   nanoseconds  (9 digits)
 
+   ISO_Time : constant Picture_String;
+   --  ISO 8601 standard date and time, with time zone.
+
    ISO_Date : constant Picture_String;
-   --  This format follow the ISO 8601 standard. The format is "YYYY-MM-DD",
+   --  This format follows the ISO 8601 standard. The format is "YYYY-MM-DD",
    --  four digits year, month and day number separated by minus.
 
    US_Date : constant Picture_String;
@@ -174,6 +179,7 @@  package GNAT.Calendar.Time_IO is
    --  Put Date with format Picture. Raise Picture_Error if bad picture string
 
 private
+   ISO_Time      : constant Picture_String := "%Y-%m-%dT%H:%M:%S%:::z";
    ISO_Date      : constant Picture_String := "%Y-%m-%d";
    US_Date       : constant Picture_String := "%m/%d/%y";
    European_Date : constant Picture_String := "%d/%m/%y";