Version 1.1 of ais/ai-00351.txt

Unformatted version of ais/ai-00351.txt version 1.1
Other versions for file ais/ai-00351.txt

!standard 9.06(19)          03-09-22 AI95-00351/01
!class amendment 03-09-22
!status work item 03-09-22
!status received 03-09-22
!priority Medium
!difficulty Easy
!subject Time operations
!summary
This proposal adds a number of useful operations on Calendar.Time.
!problem
Calendar.Time is missing a number of operations commonly needed by applications.
First, there is no day-of-the-week function. It is often necessary to do a task on a particular day of the week (maintenance tasks in servers often are executed on Sundays when the load in minimal). Determining the day of the week for an Ada.Calendar.Time value is complex.
Second, determining the Hour:Minutes:Seconds representation of a time value is not trivial. This representation is needed for most output of time values. Similarly, values often need to be converted from Hours:Minutes:Seconds to time values.
Third, determining elapsed time is difficult if more than Duration'Last seconds have elapsed. This makes it more likely that Ada programs and libraries will fail if they run longer than anticipated. We've had profilers, loggers, and other components fail due to this shortcoming.
Fourth, displaying a time value in complex. This is often needed in logs and debugging code where the format is not critical.
Finally, determining the UTC time is not possible. This is needed in many applications, such as internet comminucation. Since Ada does not define whether the time value represents UTC time, local time, or some other time, it isn't possible to use Calendar.Time in such applications.
!proposal
(See wording.)
!wording
package Ada.Calendar.Operations is
-- Day of the week:
type Days_in_Week_Type is (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
function Day_of_Week (Time : Time) return Days_in_Week_Type;
-- Hours:Minutes:Seconds access:
subtype Hour_Number is Natural range 0 .. 23; subtype Minute_Number is Natural range 0 .. 59; subtype Second_Number is Natural range 0 .. 59; subtype Second_Duration is Day_Duration range 0.0 .. 1.0;
function Hour (Date : in Time) return Hour_Number;
function Minute (Date : in Time) return Minute_Number;
function Second (Date : in Time) return Second_Number;
function Sub_Second (Date : in Time) return Second_Duration;
function Seconds_Of (Hour : in Hour_Number; Minute : in Minute_Number; Second : in Second_Number := 0; Sub_Second : in Second_Duration := 0.0) return Day_Duration;
procedure Split (Seconds : in Day_Duration; Hour : out Hour_Number; Minute : out Minute_Number; Second : out Second_Number; Sub_Second : out Second_Duration);
procedure Split (Date : in Time; Year : out Year_Number; Month : out Month_Number; Day : out Day_Number; Hour : out Hour_Number; Minute : out Minute_Number; Second : out Second_Number; Sub_Second : out Second_Duration);
function Time_Of (Year : Year_Number; Month : Month_Number; Day : Day_Number; Hour : Hour_Number; Minute : Minute_Number; Second : Second_Number; Sub_Second : Second_Duration := 0.0)
return Time;
-- Arithmetic on days:
type Day_Count is range -366*(1+Year_Number'last - Year_Number'first) .. 366*(1+Year_Number'last - Year_Number'first);
procedure Difference (Left, Right : Time; Days : out Day_Count; Seconds : out Duration);
function "+" (Left : Time; Right : Day_Count) return Time;
function "+" (Left : Day_Count; Right : Time) return Time;
function "-" (Left : Time; Right : Day_Count) return Time;
function "-" (Left, Right : Time) return Day_Count;
-- Simple image and value: function Image (Date : Time; Include_Day_of_Week : in Boolean := True; Use_Text_Month : in Boolean := True; Include_Time_Fraction : in Boolean := False) return String;
function Value (Date : String) return Time;
-- Time zone manipulation:
Unknown_Zone_Error : exception;
function To_UTC_Time (Date : in Time) return Time;
function To_Local_Time (Date : in Time) return Time;
end Ada.Calendar.Operations;
function Day_of_Week (Time : Time) return Days_in_Week_Type;
Returns the day of the week for Time. This is based on the Year, Month, and Day values of Time.
function Hour (Date : in Time) return Hour_Number; Returns the hour for Date.
function Minute (Date : in Time) return Minute_Number; Returns the minute within the hour for Date.
function Second (Date : in Time) return Second_Number; Returns the second within the hour and minute for Date.
function Sub_Second (Date : in Time) return Second_Duration; Returns the fraction of second for Date. (This has the same accuracy as Day_Duration).
function Seconds_Of (Hour : in Hour_Number; Minute : in Minute_Number; Second : in Second_Number := 0; Sub_Second : in Second_Duration := 0.0) return Day_Duration; Returns a Day_Duration value for the Hour:Minute:Second.Sub_Second. This value can be used in Calendar.Time_Of as well as the argument to Calendar."+" and Calendar."-".
procedure Split (Seconds : in Day_Duration; Hour : out Hour_Number; Minute : out Minute_Number; Second : out Second_Number; Sub_Second : out Second_Duration); Split Seconds into Hour:Minute:Second.Sub_Second.
procedure Split (Date : in Time; Year : out Year_Number; Month : out Month_Number; Day : out Day_Number; Hour : out Hour_Number; Minute : out Minute_Number; Second : out Second_Number; Sub_Second : out Second_Duration); Split Date into its consituent parts (Year, Month, Day, Hour, Minute, Second, Sub_Second).
function Time_Of (Year : Year_Number; Month : Month_Number; Day : Day_Number; Hour : Hour_Number; Minute : Minute_Number; Second : Second_Number; Sub_Second : Second_Duration := 0.0)
return Time; Returns a Time built from the date and time values.
procedure Difference (Left, Right : Time; Days : out Day_Count; Seconds : out Duration); Returns the difference between Left and Right. Days is the number of days of difference, Seconds is the remainder seconds of difference. if Left < Right, then Seconds is negative and Days is non-positive. Otherwise, both values are non-negative.
function "+" (Left : Time; Right : Day_Count) return Time; function "+" (Left : Day_Count; Right : Time) return Time;
Add a number of days to a time value. Time_Error is raised if the result is not representable in a value of type Time.
function "-" (Left : Time; Right : Day_Count)
return Time; Subtract a number of days from a time value. Time_Error is raised if the result is not representable in a value of type Time.
function "-" (Left, Right : Time) return Day_Count;
Subtract two time values, and return the number of days between them. This is the same value that Difference would return in Days.
function Image (Date : Time; Include_Day_of_Week : in Boolean := True; Use_Text_Month : in Boolean := True; Include_Time_Fraction : in Boolean := False) return String; Returns a string form of the Date. The format is "Day Month Year Hour:Minute:Second", where each value other than Year is a 2 digit form of the value, including a leading '0', if needed. Year is a 4 digit value. if Include_Day_of_Week is True, the string is prefixed by an abbreviated form of the day of the week ("Sun, ", "Mon, ", "Tue, ", "Wed, ", "Thu, ", "Fri, ", "Sat, "). if Use_Text_Month is True, the Month value is given as a abbreviated text form of the month: ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"). if Include_Time_Fraction is True, and Sub_Seconds*100 is suffixed to the string as a 2 digit value following a '.'.
AARM Note: The default parameters of Image combine to provide a string in RFC-1123 format, the Internet standard time format (without the time zone adjustment, which can be calculated by determining the difference between Local_Time and UTC_Time).
function Value (Date : String) return Time; Returns a Time value for the image given as Date. The string should be formatted as described for Image. Constraint_Error is raised if the function cannot interpret the given string as a Time value.
AARM Note: We do not require that the given string is in exactly the form returned by Image, as that would complicate the definition and implementation for no value. For instance, the absence of leading zeros shouldn't prevent that string from being decoded. But we do require that any string that Image can produce be convertible here without raising Constraint_Error.
function To_UTC_Time (Date : in Time) return Time; Convert Date to UTC (Coordinated Universal Time). if Date already is a UTC time, no change is made. if the conversion cannot be made (the time zone information is not known, for instance), Unknown_Zone_Error is raised.
function To_Local_Time (Date : in Time) return Time; Convert Date to the local time. if Date already is a local time, no change is made. The local time is assumed to include any time zone and/or daylight savings time adjustments needed. if Date already is a UTC time, no change is made. if the conversion cannot be made (the time zone information is not known, for instance), Unknown_Zone_Error is raised.
Note: The time in the time zone known as Greenwich Mean Time (GMT) is generally equivalent to UTC time.
AARM Notes: These functions imply that it is possible to tell what the time zone of a time value is. That may require having a bit in the Time value. It is intended that 'local time' be whatever the underlying system defines it to be (it isn't necessary to be the local time of the location), and that underlying system operations are used to implement the functions. The Ada system is not expected to overcome someone missetting the clock!
If the underlying system has no concept of time zones, then Unknown_Zone_Error should be raised for all uses of these routines.
!discussion
The proposal is taken from the operations provided in GNAT.Calendar and Claw.Time.
The package is defined as a child of Ada.Calendar. While the operations could be added to Ada.Calendar itself, doing so would potentially add ambiguities to many existing programs. In addition, while Ada.Calendar may be included in many programs, these operations are less likely to be needed and their overhead should not burden existing programs. The package should be a child, and not a stand-alone package, so that its implementation can take advantage of the internal representation of type Time.
These operations are most valuable for real time and date values. Thus, we have chosen not to provide similar operations for Ada.Real_Time.
[Open issue: Should this be added to Chapter 9, or to Annex A? A case can be + made either way. Note that I didn't decide either way in the proposed wording.]
The rather vague descriptions of the Hour:Minute:Second:Sub_Second functions is similar to the existing description of Ada.Calendar.
The result of procedure Difference is a bit weird. We define the remainder this way so that the Seconds value would be the same as the result "-" if the two times are less than one day apart.
Image is primarily defined to provide the Internet form (following RFC-1123) of the Date. Since RFC's aren't ISO standards, we repeat the definition and don't mention it in normative text. An alternative name of "Internet_Image" was considered, but this seemed to cover up the fact that the function can be used to provide a string for logging and debugging purposes as well.
The RFC-1123 form was used to allow us to provide a simple, useful form without providing extensive formatting and localization facilities. In this sense, Image is similar to 'Image of types: a quick and useful image string where format is not critical.
More complex formatting routines have been suggested. These were not included in the proposal because they are complex or lack capability for non-English-speaking locales.
Three kinds of formatting routines have been proposed. The simplest is the 'many default parameter form'. This would look similar to the Image function, just with many more parameters. Claw.Time contains a function like this. However, experience with the Claw function shows that not only is the large number of parameters daunting (even to the designer!), but it still lacks in flexibility (limited number of orderings, no non-English words). Renamings of the function help in ease of use, but nothing can help the flexibility.
A second approach is the generic signature & generic package scheme. This provides good localization, but at the cost of a generic signature package. The good news is that this package would not change often, and a predefined one could be provided for English and other common locales. But using it still requires an instantiation with many parameters. This is similar to the renaming, and it too lacks in flexibility in some cases.
A third approach is the format string approach. GNAT provides a package like this; Windows provides a function like this in its API. This provides a lot of flexibility in ordering, but little in terms of localization. (Windows does localization elsewhere.) Moreover, it would require several pages of RM description.
These possibilities are all quite complex, none covers everything desired, and none would really allow a Value function. Thus, we do not provide a formatted output function, preferring instead to provide the building blocks (such as the Hour:Minute:Second splitter) which can be used to write whatever is needed.
The UTC and local time conversion functions assume that a time value has an indication of the time zone. That would need to be added in many implementations. That's clearly a negative. But, Ada does not define whether Ada.Calendar.Clock returns a local time value, a UTC time value, or something else. Thus, we chose this strategy in order to avoid requiring implementations in which Ada.Calendar.Clock does not return the local time to change. As a positive side-effect, we can convert times multiple times without weird results. We also can determine easily if UTC time is supported at all.
There are a number of alternatives available. First, we could define that Ada.Calendar.Clock returns local time. Then To_UTC_Time and To_Local_Time would not need to check the existing time zone, but rather just apply the conversion. We rejected this because some implementations might have to change the implementation of Clock (a compatibility problem), and because it would make the conversions less safe. We could fix the conversion problem by adding a derived type for UTC_Time, but this would lead to an explosion of operations.
Another alternative would be to have a function that returns the difference between UTC time and local time (as a Duration value, presumabibly). However, this function could only return the current difference. But that may not be the difference for times in the recent past or near future (because of daylight savings time and the like). We could add a time as a parameter, but even then the result of the function would be prone to misuse.
[Open issue: Should we increase the year range in Calendar to 1600..2400? This would potentially require two more bits in the Time value. 1600 is used as the lower bound, as current calendar wasn't used universally until around that date. But it would avoid Ada's own Y2.1K problem.]
--!corrigendum 9.06(00)
!ACATS test
Test(s) need to be constructed.
!appendix

From: Robert I. Eachus
Sent: Thursday, June 5, 2003  12:36 PM

Tucker Taft wrote:
> While we are at it, I might argue for Boolean_Text_IO
> and Duration_Text_IO, because these are perhaps even
> more appropriate than Integer_Text_IO, since as Robert
> points out, using Integer is generally "bad form,"
> while using Boolean and Duration seems eminently reasonable.

Duration_IO would be a definite plus.  Boolean_IO would IMHO be a waste
of effort, similar to instantiating Enumeration_IO for Character.  Maybe
not quite as bad, but still something you don't want beginners to be
misled by.

Of course the real need is for a simple to use Time_IO package.  The
problem is internationalization.  I think the right solution would be to
have a package Ada.Time_IO with lots of customization options, and a
dozen or so pre-instantiations such as Ada.Time_IO.American,
Ada.Time_IO.Engish, Ada.Time_IO.French, Ada.Time_IO.Spanish,
Ada.Time_IO.French_Canadian and so on.  (And yes, the right way to do
this is with about twenty-three generic parameters including the names
of the months, the names of the weekdays and so on.)

Might as well put a straw man out there. A trivial alternative would be
to make Ada.Time_IO an empty package with Generic_Time_IO as a child.

with Ada.Calendar; use Ada.Calendar;
with Ada.Text_IO;
package Ada.Time_IO is

    generic

      Include_Day: in Boolean := True;
      Include_Time: in Boolean := True;
      Twentyfour_Hour_Clock : in Boolean := False;
      Leading_Zero_In_Hour : Boolean := False;
      Morning_Indicator: in String := "AM";
      Evening_Indicator: in String := "PM";
      Include_Seconds: in Boolean := True;
      Fractional_Digits: in Natural := 3;
      Time_First: in Boolean := False;
      Numeric_Month: in Boolean := False;
      Month_Before_Day: in Boolean := True;
      Punctuation_After_Day: in Boolean := True;
      Punctuation_Character: in Character := ',';

      Sunday: in String := "Sunday";
      Monday: in String := "Monday";
      Tuesday: in String := "Tuesday";
      Wednesday: in String := "Wednesday";
      Thursday: in String := "Thursday";
      Friday: in String := "Friday";
      Saturday: in String := "Saturday";

      January: in String := "January";
      February: in String := "February";
      March: in String := "March";
      April: in String := "April";
      May: in String := "May";
      June: in String := "June";
      July: in String := "July";
      August: in String := "August";
      September: in String := "September";
      October: in String := "October";
      November: in String := "November";
      December: in String := "December";

    package Generic_Time_IO is

      function Date_Time (As_Of: in Time := Clock) return String;

      procedure Put_Date_Time(As_Of: in Time := Clock);

      procedure Put_Date_Time(File: in Ada.Text_IO.File_Type;
                              As_Of: in Time := Clock);

      function Date (As_Of: in Time := Clock) return String;

      procedure Put_Date (As_Of: in Time := Clock);

      procedure Put_Date(File: in Ada.Text_IO.File_Type;
                         As_Of: in Time := Clock);

      function Time_Of_Day (As_Of: in Time := Clock) return String;

      procedure Put_Time(As_Of: in Time := Clock);

      procedure Put_Time(File: in Ada.Text_IO.File_Type;
                         As_Of: in Time := Clock);

    end Generic_Time_IO;

end Ada.Time_IO;

****************************************************************

From: Randy Brukardt
Sent: Thursday, June 5, 2003  3:40 PM

> Of course the real need is for a simple to use Time_IO package.  The
> problem is internationalization.  I think the right solution
> would be to
> have a package Ada.Time_IO with lots of customization options, and a
> dozen or so pre-instantiations such as Ada.Time_IO.American,
> Ada.Time_IO.Engish, Ada.Time_IO.French, Ada.Time_IO.Spanish,
> Ada.Time_IO.French_Canadian and so on.  (And yes, the right way to do
> this is with about twenty-three generic parameters including the names
> of the months, the names of the weekdays and so on.)
>
> Might as well put a straw man out there. A trivial alternative would be
> to make Ada.Time_IO an empty package with Generic_Time_IO as a child.

I agree that a Time_IO is needed, but it's not the only Time enhancement
that's needed. We provided a number of missing features in Claw.Time (some
of which are provided in GNAT's libraries as well):

 -- Day-of-the week;
 -- Duration splitters/constructors (to Hours/Minutes/Seconds, which is
deceptively easy to write incorrectly. The Gnat version I looked at was
implemented incorrectly and would give the wrong answer in some cases);
 -- Math with a wider range than Duration, for calculating elapsed time and
operation launch times in programs that are going to run more than one day.
Consider an operation that runs once a week, or a program that reports its
"Up time" periodically. (I did this by adding a bound of operations on
"Day_Count" [a number of days], but that was not completely satisfactory.
Perhaps allowing the number of seconds to be expressed as a Long_Float would
have been better.;
 -- Basic time-zone functions (To_UTC_Time, To_Local_Time);
 -- And a function Time_Image.

For Time_Image, I used a set of function parameters to control the
representation (getting the localization info from Windows). It still wasn't
that satisfactory, which is one of the main reasons I never proposed a set
of Time packages.

I found that it was necessary to rename it (to change the defaults) almost
every time it was used, because so many different formats are needed. It
hardly ever has been the case that I used the existing defaults (because it
had too much precision, or too little, or the format was specified by an
external force [such as the times in HTTP]). That, I suppose, argues that
the generic approach isn't that bad.

One thing that is clearly missing from Robert's suggestion is a way to print
elapsed times, which is a common requirement. You can do so as
Duration'Image, but usually you'd rather have Hours:Minutes:Seconds (and
again, you may need more than one day here, so it often is
Days:Minutes:Seconds).

Of course, all of the this stuff can be built yourself, or scarfed off of
the Internet, but it is so common that it really should be in the standard.
(The same arguments that applied to Ada.Directories apply here, including
availablity to every C programmer.)

****************************************************************

From: Robert Dewar
Sent: Thursday, June 5, 2003  4:51 PM

here are packages that GNAT provides:

(I do not agree with the 23 generic parameters approach, this seems a perfect
example of letting best be the enemy of good :-)

------------------------------------------------------------------------------
--                                                                          --
--                         GNAT RUN-TIME COMPONENTS                         --
--                                                                          --
--                G N A T . C A L E N D A R . T I M E _ I O                 --
--                                                                          --
--                                 S p e c                                  --
--                                                                          --
--            Copyright (C) 1999-2003 Ada Core Technologies, Inc.           --
--                                                                          --
-- This specification is derived from the Ada Reference Manual for use with --
-- GNAT. The copyright notice above, and the license provisions that follow --
-- apply solely to the  contents of the part following the private keyword. --
--                                                                          --
-- 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- --
-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
-- for  more details.  You should have  received  a copy of the GNU General --
-- Public License  distributed with GNAT;  see file COPYING.  If not, write --
-- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
-- MA 02111-1307, USA.                                                      --
--                                                                          --
-- As a special exception,  if other files  instantiate  generics from this --
-- unit, or you link  this unit with other files  to produce an executable, --
-- this  unit  does not  by itself cause  the resulting  executable  to  be --
-- covered  by the  GNU  General  Public  License.  This exception does not --
-- however invalidate  any other reasons why  the executable file  might be --
-- covered by the  GNU Public License.                                      --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------

--  This package augments standard Ada.Text_IO with facilities for input
--  and output of time values in standardized format.

package GNAT.Calendar.Time_IO is

   Picture_Error : exception;
   --  Exception raised for incorrect picture

   type Picture_String is new String;
   --  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 :
   --
   --          %    a literal %
   --          n    a newline
   --          t    a horizontal tab
   --
   --          Time fields:
   --
   --          %H   hour (00..23)
   --          %I   hour (01..12)
   --          %k   hour ( 0..23)
   --          %l   hour ( 1..12)
   --          %M   minute (00..59)
   --          %p   locale's AM or PM
   --          %r   time, 12-hour (hh:mm:ss [AP]M)
   --          %s   seconds  since 1970-01-01  00:00:00 UTC
   --                (a nonstandard extension)
   --          %S   second (00..59)
   --          %T   time, 24-hour (hh:mm:ss)
   --
   --          Date fields:
   --
   --          %a   locale's abbreviated weekday name (Sun..Sat)
   --          %A   locale's    full   weekday   name,    variable   length
   --                  (Sunday..Saturday)
   --          %b   locale's abbreviated month name (Jan..Dec)
   --          %B   locale's    full    month    name,   variable    length
   --                  (January..December)
   --          %c   locale's date and time (Sat Nov 04 12:02:33 EST 1989)
   --          %d   day of month (01..31)
   --          %D   date (mm/dd/yy)
   --          %h   same as %b
   --          %j   day of year (001..366)
   --          %m   month (01..12)
   --          %U   week number  of year with  Sunday as first day  of week
   --                  (00..53)
   --          %w   day of week (0..6) with 0 corresponding to Sunday
   --          %W   week number  of year with  Monday as first day  of week
   --                  (00..53)
   --          %x   locale's date representation (mm/dd/yy)
   --          %y   last two digits of year (00..99)
   --          %Y   year (1970...)
   --
   --          By default,  date pads numeric fields with zeroes.  GNU date
   --          recognizes the following nonstandard numeric modifiers:
   --
   --          -    (hyphen) do not pad the field
   --          _    (underscore) pad the field with spaces
   --
   --  Here are some GNAT extensions to the GNU Date specification:
   --
   --          %i   milliseconds (3 digits)
   --          %e   microseconds (6 digits)
   --          %o   nanoseconds  (9 digits)

   ISO_Date : constant Picture_String;
   --  This format follow 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;
   --  This format is the common US date format: "MM/DD/YY",
   --  month and day number, two digits year separated by slashes.

   European_Date : constant Picture_String;
   --  This format is the common European date format: "DD/MM/YY",
   --  day and month number, two digits year separated by slashes.

   function Image
     (Date    : Ada.Calendar.Time;
      Picture : Picture_String)
      return    String;
   --  Return Date as a string with format Picture.
   --  raise Picture_Error if picture string is wrong

   procedure Put_Time
     (Date    : Ada.Calendar.Time;
      Picture : Picture_String);
   --  Put Date with format Picture.
   --  raise Picture_Error if picture string is wrong

private
   ISO_Date      : constant Picture_String := "%Y-%m-%d";
   US_Date       : constant Picture_String := "%m/%d/%y";
   European_Date : constant Picture_String := "%d/%m/%y";

end GNAT.Calendar.Time_IO;

****************************************************************

From: Robert I. Eachus
Sent: Thursday, June 5, 2003  6:53 PM

> (I do not agree with the 23 generic parameters approach, this seems a perfect
> example of letting best be the enemy of good :-)

My strawman actually has 31 parameters.  Instantiating it with other
than named parameter association would be painful.

But the intent was to have the generic present, and a dozen or so
children that deal with the necessary localizations.  That way we
wouldn't have various countries arguing about the "correct" way to do
things, just providing instantiations.

As for the GNAT packages I have used them on occasion. As with my
proposal the problem is that the user doesn't want to deal with all the
syntax and semantic necessary to provide choices.  If I were to propose
the GNAT packages for standardization, the first thing I would do would
be increase the number of constant formats  and hide the complete
generality--really documentation in the GNAT version--from 'normal'
users.  No reason for it not to be there for users who insist on doing
their own layout.  But users who just want to print a date shouldn't
have to spend an hour or more figuring out how to do it.

 From my point of view though, the painful part is days of the week.  I
think it is almost criminal that Ada.Calendar doesn't have this function:

type Weekday is (Sunday, Monday, Tuesday, Wendesday, Thurday, Friday,
Saturday);

function Day_of_Week (T: in Time) return Weekday;

I have code for the above, Dave Emery has also written a version, etc.
But it should be in the standard library. The implementation is trivial
for the format of many hardware system clocks, but a hardware
independent version is half a page of code.

****************************************************************

From: Randy Brukardt
Sent: Thursday, June 5, 2003  8:55 PM

I don't like the 23 generic (or non-generic, in the Claw case) much, either.

But I don't see much to recommend the GNAT package, either. (Indeed, I
studied this approach when I create Claw.Time; Windows has a very similar
time formatting routine.)

I didn't use it because the formatting strings aren't at all Ada-like:
they're case-sensitive (at least picture strings in Annex F aren't
case-sensitive), and they look like C. In addition, we have a problem if we
tried to use this in the Ada standard, because we don't have a Locale (which
this package leans on heavily). Perhaps we need a Locale, but if Time_IO is
a can of worms, Locale is a dump truck of worms. I don't think we have the
time to do it.

As I said previously, I don't think that the 23 parameter approach works,
either. (Based on my experience with the routine in Claw.Time.)

What we need, of course is a Q&D routine with little or control on the
output format at all. After all, the primary need for these routines is for
debugging output. If they happen to provide some specific format that
someone needs, great, but that shouldn't be the focus.

For formatting beyond that, it would be much better to give the users a
proper set of splitters (Hour/Minute/Second + Day_of_the_Week) and let them
format it themselves.

But I don't have much hope that we can agree on that, so we necessarily will
end up with something that tries to be all things to all people -- a quest
that is doomed and will be a major time sink.

****************************************************************

From: Robert I. Eachus
Sent: Thursday, June 5, 2003  9:08 PM

That's why I thought the (actually) 31 parameter generic was the way to
go.  At least 99% of the users will with Ada.Time_IO.American,
Ada.Time_IO.English, Ada.Time_IO.French, or whatever and never see the
ugly generic they instantiate.  As for those who want to spend time
arguing for another standard instance, they can either write it or go
away.  Some of those instances will make it into the standard, and those
that don't will still be available to those who wrote them.

As for me, I have another project I am working on now.  But I can go
ahead and implement the generic, and either put up my own web site or
get someone who already runs one to collect generic instantiations.  I
don't know what the names of the months are in Polish or Hungarian, and
I don't care.  But someone who does can put together an instance in less
than an hour.

****************************************************************

From: Robert Dewar
Sent: Thursday, June 5, 2003  10:09 PM

> But I don't have much hope that we can agree on that, so we necessarily will
> end up with something that tries to be all things to all people -- a quest
> that is doomed and will be a major time sink.
                                     ^^^^

:-)

****************************************************************

From: Robert I. Eachus
Sent: Thursday, June 5, 2003  12:36 PM

****************************************************************

Questions? Ask the ACAA Technical Agent