Version 1.4 of ais/ai-00351.txt

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

!standard 9.06(19)          04-02-16 AI95-00351/03
!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 is complex. This is needed not only in carefully formatted output, but also in logs and debugging code.
Finally, determining the UTC time is not possible. This is needed in many applications, such as internet communication. 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
Change Year_Number in 9.6(11):
subtype Year_Number is Integer range 1901 .. 2399;
Add the following to 9.6:
The following language-defined library packages exist:
package Ada.Calendar.Time_Zones is
-- Time zone manipulation:
type Time_Offset is range -1440 .. 1440;
Unknown_Zone_Error : exception;
function Local_Time_Offset (Date : in Time := Clock) return Time_Offset;
end Ada.Calendar.Time_Zones;
package Ada.Calendar.Arithmetic is
-- Arithmetic on days:
type Day_Count is range -366*(1+Year_Number'last - Year_Number'first) .. 366*(1+Year_Number'last - Year_Number'first);
subtype Leap_Seconds_Count is Integer range -999 .. 999;
procedure Difference (Left, Right : Time; Days : out Day_Count; Seconds : out Duration; Leap_Seconds : out Leap_Seconds_Count);
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;
end Ada.Calendar.Arithmetic;
with Ada.Calendar.Arithmetic, Ada.Calendar.Time_Zones; package Ada.Calendar.Formatting is
-- Day of the week:
type Day_Name is (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);
function Day_of_Week (Date : Time) return Day_Name;
-- 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; Time_Zone : in Time_Zones.Time_Offset := 0) return Hour_Number;
function Minute (Date : in Time; Time_Zone : in Time_Zones.Time_Offset := 0) return Minute_Number;
function Second (Date : in Time; Time_Zone : in Time_Zones.Time_Offset := 0) return Minute_Number;
function Sub_Second (Date : in Time; Time_Zone : in Time_Zones.Time_Offset := 0) 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; Time_Zone : in Time_Zones.Time_Offset := 0; 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; Leap_Second: Boolean := False; Time_Zone : in Time_Zones.Time_Offset := 0)
return Time;
function Time_Of (Year : Year_Number; Month : Month_Number; Day : Day_Number; Seconds : Day_Duration; Leap_Second: Boolean := False; Time_Zone : in Time_Zones.Time_Offset := 0)
return Time;
procedure Split (Date : in Time; Time_Zone : in Time_Zones.Time_Offset := 0; 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; Leap_Second: out Boolean);
procedure Split (Date : in Time; Time_Zone : in Time_Zones.Time_Offset := 0; Year : out Year_Number; Month : out Month_Number; Day : out Day_Number; Seconds : out Day_Duration; Leap_Second: out Boolean);
-- Simple image and value: function Image (Date : Time; Include_Time_Fraction : in Boolean := False) return String;
function Value (Date : String) return Time;
function Image (Elapsed_Time : Duration; Include_Time_Fraction : in Boolean := False) return String;
function Value (Elapsed_Time : String) return Duration;
end Ada.Calendar.Formatting;
Type Time_Offset represents the number of minutes difference between the mplementation-defined timezone used by Ada.Calendar and another timezone. Subtracting this value from a time value yields the time for the timezone.
function Local_Time_Offset (Date : in Time := Clock) return Time_Offset; Returns, as a number of minutes, the difference between the implementation-defined timezone of the values of Calendar, and UTC time, at the time Date. if the timezone of the Calendar implementation is unknown, then Unknown_Zone_Error is raised.
Notes: The time in the time zone known as Greenwich Mean Time (GMT) is generally equivalent to UTC time.
The implementation-defined timezone used for type Time may be, but need not be, the local timezone. Local_Time_Offset always returns the difference between the implementation-defined timezone of package Calendar. If Local_Time_Offset does not raise Unknown_Zone_Error, UTC time can be safely calculated (within the accuracy of the underlying time-base).
AARM Notes: The Date parameter is needed to take into account time differences caused by daylight-savings time and other time changes.
Other timezones can be supported with a child package.
The accuracy of this routine is not specified; the intent is that the facilities of the underlying target operating system are used to implement it.
Subtracting Duration(Local_Time_Zone*60) from Clock provides the UTC time. In the US, for example, Time_Offset will generally be negative.
procedure Difference (Left, Right : Time; Days : out Day_Count; Seconds : out Duration; Leap_Seconds : out Leap_Seconds_Count); Returns the difference between Left and Right. Days is the number of days of difference, Seconds is the remainder seconds of difference, and Leap_Seconds is the number of leap seconds. if Left < Right, then Seconds <= 0.0, Days <= 0, and Leap_Seconds <= 0. Otherwise, all values are non-negative.
AARM Note: The number of days is calculated midnight-to-midnight. Leap_Seconds, if any, are not included in Seconds.
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 as 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 as 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 Day_of_Week (Date : Time) return Day_Name;
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; Time_Zone : in Time_Zones.Time_Offset := 0) return Hour_Number; Returns the hour for Date, as appropriate the specified timezone.
function Minute (Date : in Time; Time_Zone : in Time_Zones.Time_Offset := 0) return Minute_Number; Returns the minute within the hour for Date, as appropriate to the specified timezone.
function Second (Date : in Time; Time_Zone : in Time_Zones.Time_Offset := 0) return Minute_Number; Returns the second within the hour and minute for Date, as appropriate to the specified timezone.
function Sub_Second (Date : in Time; Time_Zone : in Time_Zones.Time_Offset := 0) return Second_Duration; Returns the fraction of second for Date. (This has the same accuracy as Day_Duration), as appropriate to the specified timezone.
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; Time_Zone : in Time_Zones.Time_Offset := 0; 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 constituent parts (Year, Month, Day, Hour, Minute, Second, Sub_Second), relative to the specified timezone.
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; Leap_Second: Boolean := False; Time_Zone : in Time_Zones.Time_Offset := 0)
return Time; Returns a Time built from the date and time values, relative to the specified timezone. Time_Error is raised if Leap_Second is True, and Hour, Minute, and Second are not appropriate for a Leap_Second.
AARM Note: A leap second always occurs as midnight, and is 23:59:60 UTC in ISO notation. So, if the timezone is UTC, if any of Hour /= 23, Minute /= 59, or Second /= 59, then Time_Error should be raised. However, we do not say that, because other time zones will have different values where a leap second is allowed.
function Time_Of (Year : Year_Number; Month : Month_Number; Day : Day_Number; Seconds : Day_Duration; Leap_Second: Boolean := False; Time_Zone : in Time_Zones.Time_Offset := 0)
return Time; Returns a Time built from the date and time values, relative to the specified timezone. Time_Error is raised if Leap_Second is True, and Seconds is not appropriate for a Leap_Second.
procedure Split (Date : in Time; Time_Zone : in Time_Zones.Time_Offset := 0; 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; Leap_Second: out Boolean); Split Date into its constituent parts (Year, Month, Day, Hour, Minute, Second, Sub_Second), relative to the specified timezone. Leap_Second is true if Date identifies a leap second.
procedure Split (Date : in Time; Time_Zone : in Time_Zones.Time_Offset := 0; Year : out Year_Number; Month : out Month_Number; Day : out Day_Number; Seconds : out Day_Duration; Leap_Second: out Boolean); Split Date into its constituent parts (Year, Month, Day, Seconds), relative to the specified timezone. Leap_Second is true if Date identifies a leap second.
function Image (Date : Time; Include_Time_Fraction : in Boolean := False) return String; Returns a string form of the Date. The format is "Year-Month-Day Hour:Minute:Second", where each value other than Year is a 2 digit form of the value of the functions defined in Calendar and Calendar.Formatting, including a leading '0', if needed. Year is a 4 digit value. if Include_Time_Fraction is True, Sub_Seconds*100 is suffixed to the string as a 2 digit value following a '.'.
AARM Note: The Image provides a string in ISO 8601 format, the international standard time format. Alternative representations allowed in ISO 8601 are not supported here.
ISO 8601 allows 24:0:0 for midnight; and a seconds value of 60 for leap seconds. These are not allowed here (the routines mentioned above cannot produce those results).
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. If the implementation has access to a complete ISO 8601 decoding routine, we certainly want to let it be used. But we do require that any string that Image can produce be convertible here without raising Constraint_Error.
function Image (Elapsed_Time : Duration; Include_Time_Fraction : in Boolean := False) return String; Returns a string form of the Elapsed_Time. The format is "Hours:Minute:Second", where each value is a 2 digit form of the value, including a leading '0', if needed. if Include_Time_Fraction is True, and Sub_Seconds*100 is suffixed to the string as a 2 digit value following a '.'.
AARM Note: This cannot be implemented (directly) by calling Ada.Calendar.Formatting.Split, since it may be out of the range of Day_Duration, and thus the number of hours may be out of the range of Hour_Number.
function Value (Elapsed_Time : String) return Duration; Returns a Duration value for the image given as Elapsed_Time. The string should be formatted as described for Image. Constraint_Error is raised if the function cannot interpret the given string as a Duration value.
Implementation Advice
An implementation should support leap seconds if the target system supports them. If leap seconds are not supported, functions returning leap seconds should return zero, and Time_Of should raise Time_Error if Leap_Second is true.
!discussion
The proposal is taken from the operations provided in GNAT.Calendar and Claw.Time.
The packages are defined as children of Ada.Calendar. While the operations could be added to Ada.Calendar itself, doing so would potentially add ambiguities to many existing programs. (There are many new overloadings of Split and Time_Of.) 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 packages should be a child, and not stand-alone packages, so that their implementation can take advantage of the internal representation of type Time.
These operations are most valuable for wall clock time and date values. Thus, we have chosen not to provide similar operations for Ada.Real_Time.
The rather vague descriptions of the Hour:Minute:Second:Sub_Second functions is similar to the existing description of Ada.Calendar.
This package provides mechanisms to handle leap seconds. This is critical if the target is connected to a time-base. Otherwise, programs could potentially wait too long when a leap second is inserted.
We have chosen to keep the invariant that there are 86400.0 seconds in a day. This is important, since existing Ada programs assume that, and changing it could break many programs. Therefore, we have adopted the model that Split ignores leap seconds - it will return 23:59:59 for a leap second. Similarly, "-" ignores leap seconds. The difference between 23:00:00 and 01:00:00 the next day is always 7200.0 seconds. Difference will return a count of leap seconds in case that information is needed.
The time of day of a leap second depends on the time zone in use. (They always happen at midnight UTC). Thus, they can occur at any local time of day.
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 defined to provide a human readable output compatible with ISO 8601. The ISO 8601 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.
The format has been chosen to maximize human readability without compromising machine readability. The more compact ISO forms are not used here.
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.
Ada 95 defines the results of Time_Of and Split relative to an "implementation-defined timezone". We extend this by providing a Time_Offset type, and providing a function to return the offset of the "implementation-defined timezone" to UTC time. We also provide defaulted parameters to Split and Time_Of so that a specified timezone can be used with those routines.
Supporting more timezones other than local and UTC is much more difficult. An implementation can add such support with child packages.
We expect the timezone functions will use the underlying operating system facilities. If those are inaccurate (say determining the starting date of daylight savings time in 1960 in Italy), we do not expect the Ada implementation to try to correct them.
The upper bound of the subtype Ada.Calendar.Year_Number is increased in order to eliminate Ada's Y2.1K problem. The lower bound is unchanged, because a lot of Ada 95 code uses Year_Number'First to represent No_Time or Unknown_Time, and dates in the distant past aren't usually interesting. The change in range is purposely kept small, so that we are not requiring a lot of extra bits in representations of Ada.Calendar.Time.
--!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: Pascal Leroy
Sent: Wednesday, September 24, 2003  3:21 AM

[This is part of a private conversation on RFC 1123 and ISO 8601 between Randy
and Pascal; it's included here for the various web references. - ED]

> I chose it simply because it is useful in practice. It's the
> only standard time format that I've ever come across in
> practice. I've never heard of ISO 8601; I don't doubt that it
> is easier to use. (I would have preferred an all-numeric
> format for obvious reasons). Is there a reference to it that
> doesn't cost $500?

See http://www.cl.cam.ac.uk/~mgk25/iso-time.html.  ISO 8601 is the
format recommended by the W3C consortium.  See
http://www.w3.org/TR/NOTE-datetime and http://www.w3.org/Protocols/Time/
for details and links.

> First of all, RFC 1123 is trivial to parse: all the fields
> (including the spaces) are
> fixed width. That is, it isn't parsed at all - you just take
> the appropriate slices and stuff them into Integer'Value.

This is not quite true as some of the fields are optional (time fraction
and day of week) and the month may be either numerical or alphabetical.
So a bit more analysis than just "taking the appropriate slices" is
needed (I suppose that you want Value to be able to parse all strings
that can be produced by Image).  But this point is unimportant, as
writing the implementation of Value cannot take more than one hour
anyway.

I am more concerned by the fact that the output format doesn't sort.  I
have found in many practical instances that using the ISO date format
makes things much easier because you get sorting for free (e.g. in
filenames or log records).

> Second, it certainly isn't dependent on US culture at all.
> This would be a very unusual date format to see in a US
> document. Certainly, it is dependent on English (for the days
> of week and month names), but the order of the items is wrong
> for the US (it is always month first around here).

True.  However the thing that I found amusing is the description of
timezones in RFC 822 (as you realize the time format in RFC 1123 is
really the same as that in RFC 822, except for a few details like "oh,
yeah, the year 2000!").  The timezones supported by RFC 822 are UT, GMT,
EST, EDT, CST, CDT, MST, MDT, PST, PDT and no others.  If that's not
US-centric, then what is?  (I realize that you don't include the
timezone in your format, and wisely so, because a timezone can really
have any name you like.)

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

From: Martin Dowie
Sent: Friday, October 17, 2003  2:46 AM


Firstly a tpyo:

    function Day_of_Week (Time : Time) return Days_in_Week_Type;

should be:

    function Day_of_Week (T : Time) return Days_in_Week_Type;

(can't have parameter name matching the parameter type name)
and shouldn't:

    subtype Second_Duration is Day_Duration range 0.0 .. 1.0;

be:

    subtype Second_Duration is Day_Duration
       range 0.0 .. Day_Duration'Pred (1.0);

as a value of '1.0' should really be added to the 'Second' count
not Sub_Second.

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

From: Thomas Wolf
Sent: Friday, October 17, 2003  5:50 AM

Some more comments:

1. Week Start
-------------

The proposed package Ada.Calendar.Operations has

    -- Day of the week:

    type Days_in_Week_Type is
      (Sunday, Monday, Tuesday, Wednesday, Thursday,
       Friday, Saturday);

ISO-8601 defines the week to start on Monday. I believe if
Ada 0X (also an ISO-standard) should define it's representation
for day-in-week in accordance with ISO 8601, i.e.

    type Days_in_Week_Type is
      (Monday, Tuesday, Wednesday, Thursday,
       Friday, Saturday, Sunday);

While it may be true that some algorithms such as Zeller's
congruence for computing the day of the week have orginally
been developed with 0=sunday, 1=monday, it is trivial to
map their results onto an ordering where
Days_In_Week_Type'First = Monday.

It's not a big issue, but I think an ISO standard for Ada 0X
should not gratuitously introduce an ordering different from
the already existing ISO 8601. (The situation for e.g. C may
have been different, for ISO 8601 didn't exist -- I think so,
at least -- when the C89 was put together.)

2. Images
---------

As for date/time images, I'd suggest that the ARG also considers
following the ISO 8601 format.

Furthermore, I'm personally convinced that image functions that
include a textual day or month representation like "Mon" or "Dec"
are a bad idea. Day and month names are highly locale-specific
(or, if you prefer, language-specific). Better leave that to
the applications using this. (And given a Day_Of_Week function,
it's no big deal to generate any string image one might want for
any Day_Of_Week_Type value.)

Just as an idea: in my own utility packages, I have

   type Date_Format is (DMY, MDY, YMD);
   --  Day-Month-Year, Month-Day-Year, Year-Month-Day.

   function Image
     (Date      : in Ada.Calendar.Time;
      Format    : in Date_Format := YMD;
      Separator : in String      := "-";
      Padding   : in Boolean     := True)
     return String;
   --  Individual date components are separated by the given
   --  Separator.
   --
   --  If Padding is true, day and month numbers smaller than
   --  10 have a leading zero.
   --
   --  Examples: (assuming Padding = True)
   --
   --  03-OCT-2001 yields
   --
   --  Format = MDY, Separator = "/"   ==> 10/03/2001    (English)
   --  Format = DMY, Separator = ". "  ==> 03. 10. 2001  (German)
   --  Format = YMD, Separator = "-"   ==> 2001-10-03    (ISO 8601)
   --  Format = YMD, Separator = ""    ==> 20011003
   --
   --  With the default arguments, the function returns the ISO 8601
   --  date representation.

(I also have individual Image functions for Ada.Calendar.Day_Duration,
producing HH:MM:SS[.Fraction], for I find it useful to keep date and
time formatting separate.)

3. Extending the range of Ada.Calendar.Time
-------------------------------------------

AI-351 mentions in its discussion section

> [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.]

I suppose "current calendar" means "Gregorian calendar". Well,
that one wasn't used "universally" (let's restrict that to
planet Earth :-) until way later. For the gory details of when
which region/country switched from the Julian to the Gregorian
calendar, see the Calendar FAQ at
<http://www.tondering.dk/claus/calendar.html>, question 2.2.4.

But even without looking there: Russia changed as late as 1918!

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

From: Martin Dowie
Sent: Friday, October 17, 2003  6:11 AM

One other question...

why extend via a child package rather than just adding the
new routines to the existing Ada.Calendar package?

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

From: Jean-Pierre Rosen
Sent: Friday, October 17, 2003  6:18 AM

From: "Thomas Wolf" <twolf@acm.org>
> ISO-8601 defines the week to start on Monday. I believe if
> Ada 0X (also an ISO-standard) should define it's representation
> for day-in-week in accordance with ISO 8601, i.e.

I definitely support this. Many (and I believe most) countries start
weeks on Monday.

> 2. Images
> ---------
As 0.02Euros input, here is what I use for my own Image/Value of time:

   -- Syntax of format strings:
   -- %Y : Year number (4 digits!)
   -- %M : Month number
   -- %D : Day number
   -- %h : Hours
   -- %m : minutes
   -- %s : seconds
   -- %c : hundredth of second (cents :-)
   -- %<char> : <char> unchanged. Useful for %%
   -- Any other character is copied verbatim on output, and
   -- must be matched exactly on input.
   -- A misformed input string to Value raises Time_Error.
   -- Value is somewhat tolerant: if the input string is to short,
defaults
   -- are taken for the missing fields (taken from the current date for
the
   -- date, and 0:0:0.0 for the time).
   -- Extra spaces are allowed in front of numeric values.
   -- In any case, it is guaranteed that a string produced by Image with
a
   -- format can be parsed by Value with the same format.
   Compact  : constant String := "%Y%M%D%h%m%s%c";
   European : constant String := "%D/%M/%Y %h:%m:%s";
   British  : constant String := "%M/%D/%Y %h:%m:%s";
   ISO      : constant String := "%Y/%M/%D %h:%m:%s.%c";

  function Image (Item : Time;   Format : String) return String;
  function Value (Item : String; Format : String) return Time;


Moreover, I found it useful to add these:
  function Min (Left, Right : Time) return Time;
  function Max (Left, Right : Time) return Time;

(And I can provide a free implementation of these functions to whoever
needs them).

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

From: Robert A. Duff
Sent: Friday, October 17, 2003  8:03 AM

Thomas Wolf says:

> ...ISO-8601 defines the week to start on Monday.

I know, and I find that annoying.  I mean, the convention that the week
starts on Sunday predates ISO by thousands of years, and this fact is
well documented.  When (and why) did various countries switch?

> As for date/time images, I'd suggest that the ARG also considers
> following the ISO 8601 format.

Yes, I agree with *that*.

> Furthermore, I'm personally convinced that image functions that
> include a textual day or month representation like "Mon" or "Dec"
> are a bad idea.

I don't agree.  Of course, as an English speaker, I'm biased.
But we spell "begin" and "Put_Line" and "True" and everything else in
English.  Why should days of the week be different?

Unless Ada goes all the way to supporting locales (which seems like too
much), we should just use "Sunday", etc.

> AI-351 mentions in its discussion section
>
> > [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.]
>
> I suppose "current calendar" means "Gregorian calendar". Well,
> that one wasn't used "universally" (let's restrict that to
> planet Earth :-) until way later. For the gory details of when
> which region/country switched from the Julian to the Gregorian
> calendar, see the Calendar FAQ at
> <http://www.tondering.dk/claus/calendar.html>, question 2.2.4.
>
> But even without looking there: Russia changed as late as 1918!

I don't understand the issue.  Who cares when and where our current
calendar was adopted.  It's *our* calendar, and we can use it perfectly
well to talk about dates thousands of years ago (or in 1917).  The fact
that the people living thousands of years ago used a different calendar
(or, if you go back far enough, had no idea what a calendar *is*) seems
irrelevant to me.  What am I missing?

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

From: Tucker Taft
Sent: Friday, October 17, 2003  8:29 AM

The ARG came up with almost all of the same suggestions
at its review of this AI at our recent ARG meeting.  A new
version will be forthcoming shortly that uses ISO 8601,
drops all textual aspects in the image/value functions,
etc.

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

From: Robert A. Duff
Sent: Friday, October 17, 2003  9:26 AM

Did they also vote that Boolean'Image should return a locale-dependent
result?!

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

From: Tucker Taft
Sent: Friday, October 17, 2003  10:25 AM

Non.   ;-)

****************************************************************
From: Thomas Wolf
Sent: Friday, October 17, 2003  8:54 AM

On 17 Oct 2003 at 9:03, Bob Duff wrote:

> Thomas Wolf says:
>
> > ...ISO-8601 defines the week to start on Monday.
>
> I know, and I find that annoying.  I mean, the convention that the week
> starts on Sunday predates ISO by thousands of years, and this fact is
> well documented.  When (and why) did various countries switch?

Is this relevant? On which day a week starts in real life is a highly
subjective matter. ISO has defined something which at least is not
complete nonsense (they didn't define, say, Thursday to be the start
of a week). So why should Ada depart from the definition given in
another ISO standard? (BTW, I'd have to look this up, but doesn't the
ISO week number also depend on the day defined to be the start of the
week?)

> > As for date/time images, I'd suggest that the ARG also considers
> > following the ISO 8601 format.
>
> Yes, I agree with *that*.
>
> > Furthermore, I'm personally convinced that image functions that
> > include a textual day or month representation like "Mon" or "Dec" are
> > a bad idea.
>
> I don't agree.  Of course, as an English speaker, I'm biased.
> But we spell "begin" and "Put_Line" and "True" and everything else in
> English.  Why should days of the week be different?

Juat to avoid any confusion: I was writing about the contents of the
string generated by Image, not about the fact that the enumeration
literals are spelled using the English day names.

> Unless Ada goes all the way to supporting locales (which seems like too
> much), we should just use "Sunday", etc.

As the spelling of the enumeration literal, yes. But an image function
producing strings containing "Sunday" or "Sun" will not be very helpful
wherever the string representation should be in some other language.

I believe one would be better off with an Image function that didn't
include day (or month) names in the generated string and have an
application add or insert the appropriate strings in the appropriate
lanugages.

I'm not suggesting Ada should support locales.

> > AI-351 mentions in its discussion section
> >
> > > [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.]
> >
> > I suppose "current calendar" means "Gregorian calendar". Well,
> > that one wasn't used "universally" (let's restrict that to
> > planet Earth :-) until way later. For the gory details of when
> > which region/country switched from the Julian to the Gregorian
> > calendar, see the Calendar FAQ at
> > <http://www.tondering.dk/claus/calendar.html>, question 2.2.4.
> >
> > But even without looking there: Russia changed as late as 1918!
>
> I don't understand the issue.  Who cares when and where our current
> calendar was adopted.  It's *our* calendar, and we can use it perfectly
> well to talk about dates thousands of years ago (or in 1917).  The fact
> that the people living thousands of years ago used a different calendar
> (or, if you go back far enough, had no idea what a calendar *is*) seems
> irrelevant to me.  What am I missing?

Maybe the author of the AI knows. I just mentioned this because I don't
understand the reasoning in the sentence "1600 is used as the lower
bound, as [the] current calendar wasn't used universally until around
that date.", which is not mine, but is taken verbatim from the AI.
Hence I pointed out that this reasoning is bogus. So, why 1600?

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

From: Robert A. Duff
Sent: Friday, October 17, 2003  9:58 AM

Thomas Wolf said:

> On 17 Oct 2003 at 9:03, Bob Duff wrote:
>
> > Thomas Wolf says:
> >
> > > ...ISO-8601 defines the week to start on Monday.
> >
> > I know, and I find that annoying.  I mean, the convention that the week
> > starts on Sunday predates ISO by thousands of years, and this fact is
> > well documented.  When (and why) did various countries switch?
>
> Is this relevant? On which day a week starts in real life is a highly
> subjective matter. ISO has defined something which at least is not
> complete nonsense (they didn't define, say, Thursday to be the start
> of a week). So why should Ada depart from the definition given in
> another ISO standard?

Why should ISO depart from a definition that dates back thousands of
years?  Grr.  If ISO defines the "North Pole" to be in Antarctica,
should we all obey?

I suppose you're right, though -- Ada pretty much has to obey ISO on
the weekday point.  Grumble.

I'm still curious to know which countries think that Monday is the first
day, and when they started thinking that, and why.  Anybody know?
And was ISO following their lead, or the other way around?

(By the way, in the U.S., the "weekend" means "Saturday and Sunday",
even though Sunday is not at the "end".  Strange.)

>... (BTW, I'd have to look this up, but doesn't the
> ISO week number also depend on the day defined to be the start of the
> week?)

Probably.

> Juat to avoid any confusion: I was writing about the contents of the
> string generated by Image, not about the fact that the enumeration
> literals are spelled using the English day names.

Yes, I understood that.  But given the existence of (for example)
Boolean'Image, there is no law saying "Ada shall not have predefined
stuff that prints out messages in English".

It would be great if Ada could support Internationalization, and support
it well.  But that's too hard (I think we all agree), especially since
"do it well" probably means fitting in well with
operating-system-dependent support for locales.  Given that, it seems
silly to forbid the standard from having something that's useful for at
least *some* programs.

But it's not important, and I don't care much one way or the other,
and I'll shut up and quit arguing about it.

> I'm not suggesting Ada should support locales.

Yes, I understood that, too.

> Maybe the author of the AI knows. I just mentioned this because I don't
> understand the reasoning in the sentence "1600 is used as the lower
> bound, as [the] current calendar wasn't used universally until around
> that date.", which is not mine, but is taken verbatim from the AI.
> Hence I pointed out that this reasoning is bogus. So, why 1600?

Yeah.  Why not 1, for that matter?

Or should we call it 0001?  ;-)

I suppose the issue is how many bits are needed to represent it.

There's a reason not to include negative years -- there is no year 0 in
our calendar, so that would mess up calculations.

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

From: Thomas Wolf
Sent: Friday, October 17, 2003  10:06 AM

> Did they also vote that Boolean'Image should return a locale-dependent
> result?!

I hope not. But why should they? For me, the argument about
day and month names in strings returned from the image function
for Time has nothing to do with the question whether
Boolean'Image (True) = "TRUE" or Day_In_Week_Type'Image (Sunday)
= "SUNDAY". That's just fine.

But including the day name in a time string generated by the Image
function for type Time is something else: the day name is not
a characteristic of Time itself; it is just a name. As such it
doesn't belong into the result returned by the standard Image
function for the type.

Or what would you think of Integer'Image (0) = "Zero"??

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

From: Tucker Taft
Sent: Friday, October 17, 2003 10:32 AM

> ...
> I'm still curious to know which countries think that Monday is the first
> day, and when they started thinking that, and why.  Anybody know?
> And was ISO following their lead, or the other way around?
>
> (By the way, in the U.S., the "weekend" means "Saturday and Sunday",
> even though Sunday is not at the "end".  Strange.)

I am surprised by your vehemence on this.  I personally much
prefer weekly calendars where saturday and sunday are at the
"end," and I have always thought of Sunday as the 7th day,
not the 1st day.  I suspect this may be semi-cultural and semi-religious.
I realize that on most monthly calendars (in the U.S.), the left-most
column is generally Sunday, but I never took that to mean that Sunday
was the "first" day of the week.  Hmmmm....

I just took a look at my Palm organizer, and it has a settable preference
for whether the first day of the week is Sunday or Monday.
Interesting.

In any case, I recommend that everyone wait for the newer
revision of this AI, and make comments relative to that, as
it will be largely rewritten based on the recent ARG discussions.

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

From: Erhard Ploedereder
Sent: Friday, October 17, 2003  9:20 AM

> > Furthermore, I'm personally convinced that image functions that
> > include a textual day or month representation like "Mon" or "Dec"
> > are a bad idea.

> I don't agree.  Of course, as an English speaker, I'm biased.
> But we spell "begin" and "Put_Line" and "True" and everything else in
> English.  Why should days of the week be different?

I must admit that this enumeration type had me worried, too,
wrt. international acceptance. It is the first instance, where a truly
every-day word is cast into language concrete, with an immediate consequence
on program output. I eventually convinced myself that all other options were
inferior.

However, in defining ancillary semantics, we should make sure that we do not
impose implicit semantics anywhere that render a facility useless, if the
output is intended to read Lundi or Montag, and there is no simple
write-around.

For 'Image on the Enumtype, there is an easy writearound.

A predefined function that gives me the whole shebang of say
   2003-Mar-18, Wed, 10:00 p.m.
without being able to somehow localize it to read
   2003-Mär-18, Mi, 22:00
would run into significant political difficulty.

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

From: Peter Hermann
Sent: Friday, October 17, 2003   6:51 AM

On Fri, Oct 17, 2003 at 12:49:37PM +0200, Thomas Wolf wrote:
> ISO-8601 defines the week to start on Monday. I believe if
> Ada 0X (also an ISO-standard) should define it's representation
> for day-in-week in accordance with ISO 8601, i.e.
>
>     type Days_in_Week_Type is
>       (Monday, Tuesday, Wednesday, Thursday,
>        Friday, Saturday, Sunday);

100% agreement.

useful for own definitions like e.g.
subtype working_days is days_in_week_type range monday..friday;
subtype weekend is ... etc.

--------------------------------------------------------------------

>    --  03-OCT-2001 yields
>    --
>    --  Format = MDY, Separator = "/"   ==> 10/03/2001    (English)

is useful for certain sorting needs within one year.

>    --  Format = DMY, Separator = ". "  ==> 03. 10. 2001  (German)

may be useful for rare sorting needs.

>    --  Format = YMD, Separator = "-"   ==> 2001-10-03    (ISO 8601)
>    --  Format = YMD, Separator = ""    ==> 20011003

is indeed useful for most sorting needs.

--------------------------------------------------------------------

> > [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.]

should be considered.
implications on calculations of differences have to be taken
into account.

-------------------------------------------------------------------

this code may stimulate, too:
http://www.csv.ica.uni-stuttgart.de/homes/ph/adapilotresources/basic_tools/calenday.ads
( + ...adb  ;-)

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

From: John Halleck
Sent: Friday, October 17, 2003  10:01 AM

> One other question...
>
> why extend via a child package rather than just adding the
> new routines to the existing Ada.Calendar package?

  Well, Several obvious but trivial reasons immediately
  occur to me.

     1) one trivial point is that if you add a child package
        you don't break any existing code.
        If you extend a package you stand SOME chance of using
        some names that duplicate what you have chosen.

     2) If it is NOT a child package, you now have two different
        packages (the old one and the new extended one) that have
        the same name, and knowing a site has Ada.Calendar doesn't
        tell you which one it is.  (But knowing they have
        Ada.Calendar.someextentionorother tells you a lot.)

   I'm sure that others on this list can suggest even more compelling
   reasons.

> [...]

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

From: Peter Hermann
Sent: Friday, October 17, 2003  10:33 AM

On Fri, Oct 17, 2003 at 03:53:54PM +0200, Thomas Wolf wrote:
> > Unless Ada goes all the way to supporting locales (which seems like too
> > much), we should just use "Sunday", etc.
>
> As the spelling of the enumeration literal, yes. But an image function
> producing strings containing "Sunday" or "Sun" will not be very helpful
> wherever the string representation should be in some other language.

As a German I can live with
   type day_name is (mon,tue,...,sun);
   type month_name is (jan,feb,...,dec);
   type boolean is (false,true);

and using these as indices into my locales when needed.

> I believe one would be better off with an Image function that didn't
> include day (or month) names in the generated string and have an
> application add or insert the appropriate strings in the appropriate
> lanugages.


> I'm not suggesting Ada should support locales.

me too: no overkill.

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

From: Erhard Ploedereder
Sent: Friday, October 17, 2003 11:34 AM


> I'm still curious to know which countries think that Monday is the first
> day, and when they started thinking that, and why.  Anybody know?

Germany definitely starts weeks on Monday.

As to origins, I am rather certain that the cause is the traditional
counting of Christianity to have Sunday as the 7th day of the week, a day of
rest, church going and singing hosianahs. Justification taken from
Genesis. This goes back to the very origins of Church, Popes, Patriarchs,
i.e., nearly 2000 years. Why they chose Sunday to be the holy day instead
of Saturday, is an easy guess.

I wouldn't be surprised, if the answer were the same for almost all European
countries, since the Church in its various incarnations used to have a lot
of influence on the secular European world. (Even in the US, despite
separation of Church and State, the secular "day of rest" is the Sunday.)

As to the ISO decision: simply look at the above and the majority situation
of countries active and voting in ISO.

All this not in terms of justification, only explanation. If you take Judaic
tradition, the week starts on Sunday. If you're Moslem, the week starts on
Saturday, doesn't it?  And I have no idea how Hinduism and Buddhism have
decided on this question. Or, if you have a hankering for Napoleon, he tried
to introduce the 10-day week, a singularly unsuccessful attempt :-)

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

From: Adam Beneschan
Sent: Friday, October 17, 2003 12:18 PM

I don't think this is correct.  The seventh day of the week from
Genesis, the day God rested, i.e. the "sabbath", has always been
associated with Saturday.  In fact, the word for Saturday is "sabato"
in Italian, and I believe it's similar in some other languages.
Sunday is identified as the Christian holy day because it's the day of
Jesus' resurrection (according to the Gospels, Jesus was crucified on
the day before the Sabbath, and resurrected on the day after).  As I
recall reading, the early Christians observed both---they observed the
Sabbath as a day of rest and the following day as a celebration of the
resurrection.  I'm not sure at what point the observance of the
Sabbath generally stopped (there were theological reasons why it was
no longer considered necessary, according to some blurbs I've read).
But I'm pretty sure that Christianity has always identified Saturday,
not Sunday, as the seventh day.  So the idea of a week starting on
Monday and ending in Sunday is more likely a more contemporary idea.

I could be wrong about some of this, though.

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

From: Jeffery Carter
Sent: Friday, October 17, 2003  1:23 PM

Thomas Wolf wrote:
>
>     type Days_in_Week_Type is
>       (Sunday, Monday, Tuesday, Wednesday, Thursday,
>        Friday, Saturday);

Personally, I think this type should be named Day_Of_Week_Type, or even
just Day_Name (regardless of the order of the days). Days in week is 7.

> Furthermore, I'm personally convinced that image functions that
> include a textual day or month representation like "Mon" or "Dec"
> are a bad idea. Day and month names are highly locale-specific
> (or, if you prefer, language-specific). Better leave that to
> the applications using this. (And given a Day_Of_Week function,
> it's no big deal to generate any string image one might want for
> any Day_Of_Week_Type value.)

PragmARC.Date_Handler has extensive image functions that can be
customized if desired to handle any local names that can be expressed as
type String (lines may wrap):

    -- Image operations:

    -- Image functions with a Zero_Fill parameter may have extra leading characters in the result.
    -- If Zero_Fill, these will be '0'; otherwise they will be ' '.

    -- Provide the image of any year CE:
    function Year_Image_Short (Year : Positive; Zero_Fill : Boolean := True) return String;
    -- Returns the decimal image of Year rem 100.
    -- If Zero_Fill, result will always be 2 characters long. Otherwise, result will be 1 or 2 characters long.

    function Year_Image_Long  (Year : Positive; Zero_Fill : Boolean := True; Width : Positive := 4) return String;
    -- Returns the decimal image of Year. Result will be large enough to hold this image, or Width characters long,
    -- whichever is larger.

    type Case_Selection is (Lower, Mixed, Upper, As_Is); -- Determines the formatting of month names

    type Name_List is array (Calendar.Month_Number) of Unbounded_String; -- Used to provide month names

    Default_Short_Name : constant Name_List := (01 => To_Unbounded_String ("Jan"),
						02 => To_Unbounded_String ("Feb"),
                                                03 => To_Unbounded_String ("Mar"),
						04 => To_Unbounded_String ("Apr"),
                                                05 => To_Unbounded_String ("May"),
						06 => To_Unbounded_String ("Jun"),
                                                07 => To_Unbounded_String ("Jul"),
						08 => To_Unbounded_String ("Aug"),
                                                09 => To_Unbounded_String ("Sep"),
						10 => To_Unbounded_String ("Oct"),
                                                11 => To_Unbounded_String ("Nov"),
						12 => To_Unbounded_String ("Dec") );
                                                -- Default "short" month names

    Default_Long_Name  : constant Name_List := (01 => To_Unbounded_String ("January"),
                                                02 => To_Unbounded_String ("February"),
                                                03 => To_Unbounded_String ("March"),
                                                04 => To_Unbounded_String ("April"),
                                                05 => To_Unbounded_String ("May"),
                                                06 => To_Unbounded_String ("June"),
                                                07 => To_Unbounded_String ("July"),
                                                08 => To_Unbounded_String ("August"),
                                                09 => To_Unbounded_String ("September"),
                                                10 => To_Unbounded_String ("October"),
                                                11 => To_Unbounded_String ("November"),
                                                12 => To_Unbounded_String ("December") );
                                                -- Default "long" month names

    function Month_Image_Numeric (Month : Calendar.Month_Number; Zero_Fill : Boolean := True) return String;
    -- Returns the decimal image of Month.
    -- If Zero_Fill, result will always be 2 characters long. Otherwise, result will be 1 or 2 characters long.

    function Month_Image_Alpha (Month : Calendar.Month_Number; Casing : Case_Selection := Mixed; Name : Name_List) return String;
    -- Returns To_String (Name (Month) ), formatted as directed by Casing.

    -- Renamings for default month names:
    function Month_Image_Short
       (Month : Calendar.Month_Number; Casing : Case_Selection := Mixed;
        Name : Name_List := Default_Short_Name)
    return String renames Month_Image_Alpha;
    function Month_Image_Long
       (Month : Calendar.Month_Number; Casing : Case_Selection := Mixed;
        Name : Name_List := Default_Long_Name)
    return String renames Month_Image_Alpha;

    function Day_Image (Day : Calendar.Day_Number; Zero_Fill : Boolean := True) return String;
    -- Returns the decimal image of Day.
    -- If Zero_Fill, result will always be 2 characters long. Otherwise, result will be 1 or 2 characters long.

    type AM_PM_ID is (AM, PM);
    type AM_PM_List is array (AM_PM_ID) of Unbounded_String;

    Default_AM_PM_Name : constant AM_PM_List := (AM => To_Unbounded_String (" am"), PM => To_Unbounded_String (" pm") );

    function Hour_Image_12 (Hour : Hour_Number;
                            AM_PM : AM_PM_List := Default_AM_PM_Name; Zero_Fill : Boolean := True) return String;
    -- If Hour = 0, Image is "12". If Hour in 1 .. 12, Image is image of Hour. Otherwise, Image is image of Hour - 12.
    -- If Hour < 12, returns Image & To_String (AM_PM (AM) ). Otherwise, returns Image & To_String (AM_PM (PM) ).
    -- If Zero_Fill, Image will always be 2 characters long. Otherwise, Image will be 1 or 2 characters long.

    function Hour_Image_24 (Hour : Hour_Number; Zero_Fill : Boolean := True) return String;
    -- Returns the decimal image of Hour.
    -- If Zero_Fill, result will always be 2 characters long. Otherwise, result will be 1 or 2 characters long.

    function Minute_Image (Minute : Minute_Number; Zero_Fill : Boolean := True) return String;
    -- Returns the decimal image of Minute.
    -- If Zero_Fill, result will always be 2 characters long. Otherwise, result will be 1 or 2 characters long.

    function Seconds_Image (Seconds : Minute_Duration;
                            Zero_Fill : Boolean := True; Aft : Natural := 0) return String;
    -- Returns the decimal image of Seconds, with Aft digits after the decimal point.
    -- If Aft = 0, result will not contain a decimal point.
    -- If Aft = 0 and Zero_Fill, result will always be 2 characters long.
    -- If Aft = 0 and not Zero_Fill, result will be 1 or 2 characters long.
    -- If Aft > 0 and Zero_Fill, the portion of result left of the decimal point will always be 2 characters long.
    -- Otherwise, the portion of result left of the decimal point may be 1 or 2 characters long.
    -- If Seconds = Minute_Duration'Last, returns the image of 0.0.

    function Image (Date : Calendar.Time) return String;
    -- Splits Date into Year, Month, Day, Hour, Minute, and Seconds, then
    -- returns the 23-character string resulting from
    --    Year_Image_Long (Year)    & ' ' &
    --    Month_Image_Short (Month) & ' ' &
    --    Day_Image (Day)           & ' ' &
    --    Hour_Image_24 (Hour)      & ':' &
    --    Minute_Image (Minute)     & ':' &
    --    Seconds_Image (Seconds, Aft => 2);

This last is a quick way to obtain a default full image of a Time.
Naturally, the package also provides Split to obtain hours, minutes, and
seconds, and a Day_Of_Week function.

If the day name is desired in an image, Day_Of_Week may be used; the
return value may be used to index an array of local day names if the
values of the enumeration are not satisfactory.

Components may be arranged in any order, with any separators, as
required by local standards.

So far, no user has requested any additional image functionality.

The PragmAda Reusable Components are available from

http://home.earthlink.net/~jrcarter010/pragmarc.htm

should you want to inspect this package further

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

From: Robert A. Duff
Sent: Friday, October 17, 2003  2:34 PM

> As to the ISO decision: simply look at the above and the majority situation
> of countries active and voting in ISO.

Fascinating.  Sorry for some off-topic chatting, but...

I didn't *really* mean to bring religion into this discussion,
but that's where our 7-day week notion comes from, and no matter what
religion you are, or none, you have to admit this is where it
originates.

The book of Genesis, in the Jewish Torah (which is also part of the
Christian Bible) in chapter 1, explains how God created the world in 6
days.  In 2(1-2) it says something about how God rested on the seventh
day.  [The rest of chapter 2 tells a *different* story about
world-creation, contradicting chapter 1; this is the story of Adam and
Eve.]

Later parts of the Torah define the seventh day as the sabbath, i.e. day
of rest.  This is the day known as Saturday in English (which I guess
comes from the Roman god Saturn, which has nothing to do with either
Judaism or Christianity).  But I believe in some European languages
(Italian and Spanish maybe?) this day is still called sabat or something
like it.

I thought Christians still view the sabbath as the last day of the week,
but they just don't celebrate it anymore; they instead celebrate Sunday,
because that's the day Jesus was resurrected.  I had no idea that in
Europe that meant a redefinition of "sabbath" or of "last day of week".
I just thought Christians celebrate the first day of the week.

These days, we can't truly appreciate the notion of sabbath, since we
have a 40-hour work week, and we get to rest on both Saturday *and*
Sunday.

> All this not in terms of justification, only explanation. If you take Judaic
> tradition, the week starts on Sunday. If you're Moslem, the week starts on
> Saturday, doesn't it?

I don't know.  Muslims do their main worship on Friday, I believe, but I
don't know if they define that as the last day of the week.

>...And I have no idea how Hinduism and Buddhism have
> decided on this question. Or, if you have a hankering for Napoleon, he tried
> to introduce the 10-day week, a singularly unsuccessful attempt :-)

Yeah, Napoleon's experiment was interesting.  ;-)

Anyway, I guess Ada should do what ISO wants in this regard.

But I'm used to Sunday being the *first* day of the week, and
I will never buy a calendar that shows otherwise, no matter what
pretty pictures it shows.

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

From: Alexandre E. Kopilovitch
Sent: Friday, October 17, 2003  3:41 PM

>if you have a hankering for Napoleon, he tried
>to introduce the 10-day week, a singularly unsuccessful attempt :-)

In Soviet Union, in 1920th and/or 30th, Communists repeated this attempt -
they decided that holidays must be 5, 15 and 25 each month, but retreated after
some time.

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

From: Gary Dismukes
Sent: Friday, October 17, 2003  3:58 PM

> > One other question...
> >
> > why extend via a child package rather than just adding the
> > new routines to the existing Ada.Calendar package?
>
>   Well, Several obvious but trivial reasons immediately
>   occur to me.
>
>      1) one trivial point is that if you add a child package
>         you don't break any existing code.
>         If you extend a package you stand SOME chance of using
>         some names that duplicate what you have chosen.
> ...

More specifically, adding new declarations to existing predefined
packages runs the risk of causing ambiguities in existing applications
that have use clauses.  Generally we want to avoid causing that kind
of incompatibility.

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

From: Martin Dowie
Sent: Friday, October 17, 2003  5:41 PM

If you're already in the habit of using a use clauses, you still run
this risk if you "with" and "use" the new package...

Sorry, but (as a user) it just looks gratuitous to me :-(

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

From: Randy Brukardt
Sent: Friday, October 17, 2003  6:00 PM

Sigh. Anytime you add a "with" or "use", you should expect things to break.
But that can only happen in *new* or *modified* code. What we're concerned
about is *existing* code that is recompiled with compiler that happens to
support Ada 200Y features. This should work, unmodified. That's especially
important as we're expecting Ada 200Y to be adopted incrementally, not all
at once as Ada 95 was. If someone doesn't use new features, their code
should continue to work. (There are a couple of cases where that won't be
true, but we believe that they are unlikely to occur in practice. Extra
overloadings of "Split" are much more likely to cause trouble.)

In any case, AI-351/01 was a straw man proposed by me in order to get a
discussion going at the ARG level. That goal was wildly successful. :-) I'd
suggest waiting for the next version before commenting, as a lot of things
will be different. (No one yet has complained about leap seconds, which was
the topic that managed to dominate the ARG discussion.)

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

From: Pascal Obry
Sent: Saturday, October 18, 2003  1:44 AM

 > Sorry, but (as a user) it just looks gratuitous to me :-(

It avoids dragging a bunch of routines that you maybe do not need. This
helps minimize the compilation time, the link time and also the size of the
executable. I think all this is really sufficient to use child packages when
possible.

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

From: Martin Dowie
Sent: Saturday, October 18, 2003  2:30 AM

> Sigh. Anytime you add a "with" or "use", you should expect things to break.
> But that can only happen in *new* or *modified* code. What we're concerned

Or when I decide to:
  a) put my code through a new compiler, or
  b) put my code through a new compiler for a new language standard. :-)

I mean, really, what's the worst that's going to happen? The compiler is going
to tell me there is an ambiguous call, I look up the new RM (or porting guide,
someone is going to provide a porting guide, like last time, yes?) and I see that
I can now either bin my routine as the lanuage now has the routine I need
built-in, or use my 'trusted' routine, by making the call unambiguous and use
which ever one I want.

As a user (again!) - I can live with this!! It isn't as if the routine (esp. 'Split', which
I agree is the likeliest 'culprit') is going to do anything different to what I actually
want...

If we change which language standard we are working to (and compiler), we
know in advance there may be some cost and changes required - this one
looks trivial and a child package, to add the routines that should have been
there to start with, just looks 'kludgy'...

> suggest waiting for the next version before commenting, as a lot of things

Ok - can't wait for the new proposal! :-)

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

From: Nick Roberts
Sent: Friday, October 17, 2003  3:51 PM

"Robert A Duff" <bobduff@TheWorld.com> wrote:

> I suppose you're right, though -- Ada pretty much has to obey
> ISO on the weekday point.  Grumble.

It does if it is to remain an ISO standard: ISO mandates that its standards
must be based on other ISO standards wherever applicable (as I'm sure you
know, Bob :-)

> I'm still curious to know which countries think that Monday is
> the first day, and when they started thinking that, and why.
> Anybody know? And was ISO following their lead, or the other
> way around?

ISO 8601 itself acknowledges that people from different cultural and
religious backgrounds recognise different days as being the first day of the
week, and it states that the decision to plump for Monday is based purely on
the fact that the vast majority of businesses around the world use Monday as
the first day of the week in calculating week numbers (within the year). In
fact, this actually means that a week is considered to fall within a certain
year if its Thursday does.

> >... (BTW, I'd have to look this up, but doesn't the ISO week
> > number also depend on the day defined to be the start of
> > the week?)
>
> Probably.

Yes it does.

> ... But given the existence of (for example) Boolean'Image,
> there is no law saying "Ada shall not have predefined stuff
> that prints out messages in English".

Indeed. Especially since there is also no law that says an Ada compiler
cannot have a non-standard mode in which it prints predefined stuff in
another language. But I agree that it isn't necessary for the Ada standard
to provide images of the day or month names, when this is functionality that
can almost trivially be supplied by the user.

> It would be great if Ada could support Internationalization,
> and support it well.  But that's too hard (I think we all agree),
> especially since "do it well" probably means fitting in well with
> operating-system-dependent support for locales.

Handling time locales, as well as language locales, well is a fantastically
complicated business. The GNU stuff has a huge file that contains
information about timezones (and daylight saving times) around the world
which is not only current but also historic! No way can that kind of thing
be put into the principal Ada standard.

It could be made some sort of secondary standard, maybe. If so, then frankly
I'd more happily support a standard that was independent of programming
language and operating system (perhaps being based on an OMG IDL module).

> Given that, it seems silly to forbid the standard from having
> something that's useful for at least *some* programs.

It seems reasonable to me for the standard to define enumeration types for
day of the week and month of the year with English names for the enumeration
literals. The user can then very easily supply arrays of ((un)bounded?)
strings to produce names in another language. This technique is often used
to make a Boolean value produce "No" and "Yes", "Non" and "Oui", or
whatever.

> > Maybe the author of the AI knows. I just mentioned this
> > because I don't understand the reasoning in the sentence
> > "1600 is used as the lower bound, as [the] current calendar
> > wasn't used universally until around that date.", which is
> > not mine, but is taken verbatim from the AI. Hence I
> > pointed out that this reasoning is bogus. So, why 1600?
>
> Yeah.  Why not 1, for that matter?
>
> Or should we call it 0001?  ;-)

The SQL-92 standard (ISO 9075:1992(E)) defines its year type to have the
range 0001 to 9999. Myself, I would support the standard changing
Ada.Calendar to say:

   subtype Year_Number is Integer range [implementation defined];

and simply stipulating that the implementation-defined range must minimally
encompass [1901,2099].

This would allow a bigger year range to be provided (with a standard name),
but its actual range could be chosen to be most appropriate for the
implementation. It's a compromise that has worked well for Integer itself.

> There's a reason not to include negative years -- there is no
> year 0 in our calendar, so that would mess up calculations.

One could, perhaps, posit the rule that the year n CE always equates to the
year 1-n BC (as well as to the year n AD). Perhaps more sensibly one could
posit that any year n CE for n < N does not determinately equate to any year
AD or BC, where you can argue about N as much as you like (is it 1582, for
example?). In short, there's no point in worrying about year 0 CE, or
negative years CE; astronomers don't (they cheerfully talk about negative
years in the millions, although they do all their calculations in JD).

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

From: Dan Eilers
Sent: Saturday, October 18, 2003  5:54 PM

Thomas Wolf wrote:
> ISO-8601 defines the week to start on Monday.  ...

I'm not so sure this is true.

Unfortunately, ISO-8601 apparently isn't available on the web.
Can anyone quote the part that "defines the week to start on Monday"?

ISO has a web page that informally describes ISO-8601, at:
  http://www.iso.ch/iso/en/prods-services/popstds/datesandtime.html

This web page describes ISO-8601 as a standard for writing dates
unambiguously, not a standard for arranging the layout of columns
on monthly calendars, or for specifying the internal representation
of week-day enumeration types used in programming languages.
If this web page is correct in describing the purpose and scope of
ISO-8601, then I would consider Ada to be in perfectly fine conformance
if it provided facilities for printing dates in all the ISO-8601 formats,
regardless of what internal representation is used for a week-day
enumeration type in package Calendar.

My understanding from the ISO web page is that for the purpose of
printing dates in an alternative week-date format used by certain
commercial and industrial processes, the week-date format is computed
by using a formula that assigns Monday=1 and Sunday=7.  It is of
course perfectly reasonable for certain commercial and industrial
processes to use formulas that consider Monday=1, since Monday is
generally considered to be the first day of a work week.  But from
what I can tell, this use of Monday=1 in ISO 8601 is solely for the
limited purpose of calculating week-dates in this alternative format,
rather than a broad requirement that "weeks must start on Monday".
Since this format is explicitly described as an "alternate", I think
Ada would be perfectly correct in using the more conventional
definition of Sunday as the first day of the week.

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

From: Juanma Barranquero
Sent: Tuesday, October 21, 2003  5:59 PM

> Unfortunately, ISO-8601 apparently isn't available on the web.

http://lists.ebxml.org/archives/ebxml-core/200104/pdf00005.pdf

> Can anyone quote the part that "defines the week to start on Monday"?

Pg. 4 (from "3. Terms and definitions"):

 "3.28
  week, calendar
  time-interval of seven days, starting on a Monday and identified by
  its ordinal number within a calendar year

  NOTE  A calendar week is often also referred to as week"

Pg. 7:

 "4.3.2.2  The calendar week

  In parallel with the reference system described in 4.3.2.1, there is a
  reference system based on an unbounded series of contiguos calendar
  weeks. Each calendar week has seven calendar days as indicated in
  Table 2.

                     Table 2 -- Calendar days

           Ordinal day                   Calendar day
          number in the                      name
               week

                01                          Monday
                ...                         ..."

Pg. 13:

  "5.2.3  Week date

   [...]

   -- day of the week is represented by one decimal digit. Monday shall
      be identified as day [1] of any calendar week, and subsequent days
      of the same week shall be numbered in ascending sequence to Sunday
      (day [7])."

Pg. 25:

  "Annex A (Informative)

   [...]

   The uniform numbering of weeks necessitates a unique designation of
   the day on which a week begins. For commercial purposes, i.e.
   accounting, planning and similar purposes for which a week number might
   be used, Monday has been found the most appropriate as the first day
   of the week."

So you could argue that ISO 8601 only defines Monday as the first day of
the week for "applications", but OTOH, that's the whole point of ISO
8601, and that's the *only* definition of week to be found on the whole
document...

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

From: Dan Eilers
Sent: Tuesday, October 21, 2003  8:14 PM

Thanks for the URL.

Having read this, I would contend, in the absence of further guidance
from the ISO-8601 maintenance committee, that ISO-8601 is silent on
the definition of week'first outside the narrow context of "week-date"
formats used for commercial purposes where Monday=1 is appropriate and
was chosen as the first day of the commercial work week.

I would note in particular that the Scope section, does not list
standardization of week'first among its eight items, except as a
subitem to item (c) on week-date formats.

> Pg. 25:
>
>   "Annex A (Informative)
>
>    [...]
>
>    The uniform numbering of weeks necessitates a unique designation of
>    the day on which a week begins. For commercial purposes, i.e.
>    accounting, planning and similar purposes for which a week number might
>    be used, Monday has been found the most appropriate as the first day
>    of the week."

It seems clear from this paragraph that the definition of week'first would
not have been included in ISO-8601 at all, except that it was "necessitated"
by the week-date format, and the considerations of which day to make
first did not go beyond the commercial work week considerations of the
intended users of this week-date format.

> So you could argue that ISO 8601 only defines Monday as the first day of
> the week for "applications", but OTOH, that's the whole point of ISO
> 8601, and that's the *only* definition of week to be found on the whole
> document...

I would contend that it's the "*only definition of week to be found on
the whole document" because ISO-8601 did not see any need to standardize
the definition of week'first outside the narrow context of week-date formats.

Absent any clear mandate from the ISO-8601 committee, I would contend
that the ARG should use the most widely accepted definition of week'first,
so as to avoid criticism as being out of step with customary usage.

I note that existing Ada software uses week'first=Sunday, at least
as the default, as in:

pragmarc-date_handler.ads:
    type Day_Name is (Sunday, Monday, Tuesday, Wednesday, Thursday,
                      Friday, Saturday);

claw-time.ads:
   type Days_in_Week_Type is (Sunday, Monday, Tuesday, Wednesday, Thursday,
                              Friday, Saturday);

gtk-calendar.ads:
  Week_Start_Monday : constant Gtk_Calendar_Display_Options;
   --  Start the calendar week on Monday, instead of the default Sunday.

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

From: Martin Dowie
Sent: Wednesday, October 22, 2003  3:01 AM

> I note that existing Ada software uses week'first=Sunday, at least
> as the default, as in:
>
> pragmarc-date_handler.ads:
>     type Day_Name is (Sunday, Monday, Tuesday, Wednesday, Thursday,
>                       Friday, Saturday);
>
> claw-time.ads:
>    type Days_in_Week_Type is (Sunday, Monday, Tuesday,
> Wednesday, Thursday,
>                               Friday, Saturday);
>
> gtk-calendar.ads:
>   Week_Start_Monday : constant Gtk_Calendar_Display_Options;
>    --  Start the calendar week on Monday, instead of the
> default Sunday.

And the exception that proves the rule:

package GNAT.Calendar is

   type Day_Name is
     (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);

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

From: Dan Eilers
Sent: Wednesday, October 22, 2003 11:16 AM

Interestingly, GNAT 3.15p seems somewhat conflicted about weekday'first.

a-calend.adb:
      tm_wday   : int;           -- days since Sunday (0 .. 6)

g-catiio.ads:
   --          %a   locale's abbreviated weekday name (Sun..Sat)
   --          %A   locale's    full   weekday   name,    variable   length
   --                  (Sunday..Saturday)
   --          %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)

g-catiio.adb:
               when 'T' =>
               ...
               --  Locale's abbreviated weekday name (Sun..Sat)

               when 'm' =>
               ...
               --  Week number of year with Sunday as first day of week
               --  (00..53)

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

From: Pascal Obry
Sent: Wednesday, October 22, 2003 11:28 AM

All your examples are interfaces to OS services. These are defined with Sunday
being the first day of the Week. As noted the GNAT.Calendar.Day_Name does
start on Monday and this is a user's API.

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

From: Dan Eilers
Sent: Wednesday, October 22, 2003 12:22 PM

I think interfaces to OS services are a signficant consideration, and
not to be minimized.  These OS services are defined by ISO standards
(ISO/IEC 9899:1990 and ISO/IEC 9945-1:1996) and are visible in existing
Ada user API's such as:

windex-time.ads:
   type Weekday_Type is (Sunday, Monday, Tuesday, Wednesday, Thursday,
          Friday, Saturday);
   for Weekday_Type use
      (Sunday    => 0,
       Monday    => 1,
       Tuesday   => 2,
       Wednesday => 3,
       Thursday  => 4,
       Friday    => 5,
       Saturday  => 6);

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

From: Pascal Obry
Sent: Wednesday, October 22, 2003  1:43 PM

 > I think interfaces to OS services are a signficant consideration, and
 > not to be minimized.

Agreed but only if in the spec. The quoted GNAT sources were only
implementation details.

 > These OS services are defined by ISO standards
 > (ISO/IEC 9899:1990 and ISO/IEC 9945-1:1996) and are visible in existing
 > Ada user API's such as:
 >
 > windex-time.ads:
 >    type Weekday_Type is (Sunday, Monday, Tuesday, Wednesday, Thursday,
 >           Friday, Saturday);

Ok, but you were talking about GNAT. Never we will be able to require all Ada
libraries to conform to one standard.

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

From: Dan Eilers
Sent: Wednesday, October 22, 2003  2:06 PM

Actually, I quoted several from the spec of g-catiio.

#  g-catiio.ads:
#     --          %a   locale's abbreviated weekday name (Sun..Sat)
#     --          %A   locale's    full   weekday   name,    variable   length
#     --                  (Sunday..Saturday)

Rather than being implementation details, these seem to reflect
common usage of a week running from Sunday to Saturday.

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

From: Thomas Wolf
Sent: Wednesday, October 22, 2003  3:23 AM

Maybe the ARG has already considered this in its last meeting,
but just in case this was not noted:

The proposed package has

    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;

[...]

    procedure Split (Seconds : in Day_Duration;
                     Hour : out Hour_Number;
                     Minute : out Minute_Number;
                     Second : out Second_Number;
                     Sub_Second : out Second_Duration);

What is this supposed to return for Seconds = Day_Duration'Last?
23:59:59 and Sub_Second=1.0? Wouldn't it be more natural to
define

  type Hour_Number is Natural range 0 .. 24;

and return 24:00:00.00?

When will the revised AI-351 be posted?

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

From: John Halleck
Sent: Wednesday, October 22, 2003  9:28 AM

Just to be picky...

What about leap seconds?  Ignoring them has already caused some
GPS software problems...

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

From: Tucker Taft
Sent: Wednesday, October 22, 2003  1:15 PM

Not to worry, the ARG spent most of the time relating to
this AI discussing leap seconds.  This issue will be dealt with
in the next version of the AI.  (I strongly recommend you all
hold your comments until you see that one.)

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

From: Jean-Pierre Rosen
Sent: Wednesday, October 22, 2003  12:25 PM

> Absent any clear mandate from the ISO-8601 committee, I would contend
> that the ARG should use the most widely accepted definition of week'first,
> so as to avoid criticism as being out of step with customary usage.
>
Could you show evidence that it is actually the "most widely accepted
definition of week'first"?
Maybe in the US, but I doubt it if you consider the whole world.

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

From: Dan Eilers
Sent: Wednesday, October 22, 2003  4:00 PM

Being from the U.S., I can attest that this is true in the U.S.
I doubt that the tradition in the U.S. was not imported from Europe.

My understanding is that in many languages, including French, German,
Spanish, Italian, Romanian, Hebrew, and Arabic, the name for Saturday
is derived from Sabbath, meaning the 7th day.

My understanding is that the first six days of the week are numbered
in various languages, such as Hebrew, Arabic, Modern Greek, Portuguese,
and Vietnamese, starting with Sunday as the first day.

My understanding is that German for Wednesday means mid-week.

My understanding is that some countries such as Russia did not adopt
the Gregorian calendar (on which Ada.Calendar is based) until relatively
recently, and may have other traditions.

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

From: Alexandre E. Kopilovitch
Sent: Wednesday, October 22, 2003  4:42 PM

>Being from the U.S., I can attest that this is true in the U.S.
>I doubt that the tradition in the U.S. was not imported from Europe.

It may be from England, which always was different from continental Europe
in many respects.

>My understanding is that some countries such as Russia did not adopt
>the Gregorian calendar (on which Ada.Calendar is based) until relatively
>recently, and may have other traditions.

I can assure you that in Russia 1st day of week is certainly Monday.
And I always thought that this is also true in all continental Europe.

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

From: Gary E. Barnes
Sent: Wednesday, October 22, 2003  4:26 PM

ISO-8601, in section 3 "Terms and definitions",

"3.17   week, calendar: A seven day period within a calendar
year, starting on a Monday and identified by its ordinal number
within the year; the first calendar week of the years is the one
that includes the first Thursday of that year.  In the Gregorian
calendar, this is equivalent to the week which includes
4 January."

And in section 5 "Representations" in the 2nd paragraph of
5.2.3 "Date identified by calendar week and day numbers",

"Day of the week is represented by one decimal digit.  Monday
shall be identified as day [1] of any calendar week, and subse-
quent days of the same week shall be numbered in ascending
sequence to Sunday (day [7])."

This would seem to imply that Ada should do something like,

type Day is (Monday, ... Sunday);
for Day use (Monday => 1, ... Sunday =>7);

Is 8601 ambiguous in some fashion?

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

From: Dan Eilers
Sent: Wednesday, October 22, 2003  5:26 PM

> Is 8601 ambiguous in some fashion?

No, its not ambiguous, but it has a very limited scope.
The scope explicitly involves external representations of dates
used in communication between mutually agreeable parties.

But that's not what is at issue here.  We are trying to determine if
8601 should be used as guidance outside its explicit scope, where we
are concerned with _internal_ representations within an Ada program.

> This would seem to imply that Ada should do something like,
>
> type Day is (Monday, ... Sunday);
> for Day use (Monday => 1, ... Sunday =>7);

That would be silly.  8601 only requires that the external representation
of Monday=1, and only in the context of week-date formats.  It says nothing
about internal representations.  (Other ISO standards, of course, do
say something about internal representations of dates.)

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

From: Juanma Barranquero
Sent: Wednesday, October 22, 2003  5:37 PM

> My understanding is that in many languages, including French, German,
> Spanish, Italian, Romanian, Hebrew, and Arabic, the name for Saturday
> is derived from Sabbath, meaning the 7th day.

Yes, the Spanish name for Saturday is "sábado", obviously derived from
"sabbath". Still, when spaniards talk about "the next week" they're
*always* referring to the group of seven contiguous days starting on
next Monday. And we, as English speakers do, talk about the "fin de
semana" (the weekend) in reference to Saturday & Sunday.

And finally, the Real Academia Dictionary says about "sábado": "Sixth
day of the week, seventh of the liturgical week."

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

From: Dan Eilers
Sent: Wednesday, October 22, 2003  7:27 PM

> And finally, the Real Academia Dictionary says about "sábado": "Sixth
> day of the week, seventh of the liturgical week."

Interesting.  My Webster's Ninth New Collegiate dictionary says:
  Saturday:  the seventh day of the week
  Sabbath: 1a. the seventh day of the week


> Yes, the Spanish name for Saturday is "sábado", obviously derived from
> "sabbath". Still, when spaniards talk about "the next week" they're
> *always* referring to the group of seven contiguous days starting on
> next Monday.

Do your calendars start the week with Monday?
Maybe there is a localization table somewhere that would show
the local convention for each country in the world.

>               And we, as English speakers do, talk about the "fin de
> semana" (the weekend) in reference to Saturday & Sunday.

  Weekend:  "The end of the week; specifically, the period between the
close of one working or business or school week and the beginning of
the next."

  "weekend" including Sunday doesn't cause us any cognitive difficulties,
because it is considered to be in relation to the "work week" or
"school week", not the calendar week.

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

From: Randy Brukardt
Sent: Wednesday, October 22, 2003  8:35 PM

Dan said:

> > Is 8601 ambiguous in some fashion?
>
> No, its not ambiguous, but it has a very limited scope.
> The scope explicitly involves external representations of dates
> used in communication between mutually agreeable parties.
>
> But that's not what is at issue here.  We are trying to determine if
> 8601 should be used as guidance outside its explicit scope, where we
> are concerned with _internal_ representations within an Ada program.

This discussion has reached the point of absurdity. The choice of the first
day of a week is a religious war - there is no logic at all in it. It is the
problem that caused there to be no day-of-week functions in Ada in the first
place, and we're heading in that direction again. Which, IMHO, is utterly
stupid.

Besides, the choice of the first of the Days_of_Week type is pretty much
irrelevant to the sorts of uses that it intended for. It only matters to
comparisons, and those are best done with the time values, not with day
names.

For instance, consider a task that needs to be run every Monday:

    if New_Day and then Day_of_Week (Clock) = Monday then
         -- Do the task
    end if;

Or the display of the day of the week in output:
    type Day_Abbreviations_Type is array (Days_of_Week) of String (1..3);
    Day_Abbreviations : constant Day_Abbreviations_Type :=
	   (Sunday => "Sun", Monday => "Mon", Tuesday => "Tue", Wednesday => "Wed",
          Thursday => "Thu", Friday => "Fri", Saturday => "Sat");

    Put (Day_Abbreviations (Day_of_Week (A_Time));

In neither case does the type definition matter a bit.

I'd probably advocate the "ISO" solution (that is, pick a solution that
matches no ones position) and start the type with Saturday. Then everyone
can complain equally. :-)

Thomas Wolf said:

> When will the revised AI-351 be posted?

I don't know, but the more discussion there is, the longer it will be before
I can work on it. (I have to get completed AIs ready for the upcoming WG9
meeting before I can work on any open issues. And then I have to file all of
the mail that has piled up this month.)

*Please* leave the discussion alone until you can read the minutes of the
October ARG meeting and/or read the revised AI. Otherwise, you're just
rehashing the already decided.

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

From: Pascal Obry
Sent: Thursday, October 23, 2003  2:05 AM

 > Actually, I quoted several from the spec of g-catiio.

Right but these are from the second category: Interface. Here is the important
comment:

   --  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 :

"GNU Date specification".

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

From: Jean-Pierre Rosen
Sent: Thursday, October 23, 2003  7:00 AM

> Being from the U.S., I can attest that this is true in the U.S.
> I doubt that the tradition in the U.S. was not imported from Europe.
Maybe from the UK...

> My understanding is that in many languages, including French, German,
> Spanish, Italian, Romanian, Hebrew, and Arabic, the name for Saturday
> is derived from Sabbath, meaning the 7th day.
Yes, but this is long forgotten.
Being from France, I can attest that the first day is Monday, and I guess it
is the case in most other European countries. Please, readers from other
countries, tell us about your habits.

Anyway, since this clearly varies between countries, this discussion has
already occured at ISO level. If the decision of the experts in dates
processing has been one way, I don't think we have any ground for making a
different decision.

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

From: Ardaud Charlet
Sent: Thursday, October 23, 2003  7:17 AM

> Yes, but this is long forgotten.

Not really.

> Being from France, I can attest that the first day is Monday, and I guess it
> is the case in most other European countries. Please, readers from other
> countries, tell us about your habits.

Just for the sake of completeness, the above is wrong.
Many people consider that the first day of the week is Sunday in France.

Which does not change the rest of this discussion in any way.

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

From: Ehud Lamm
Sent: Thursday, October 23, 2003  7:14 AM

In Israel the first day of the week is Sunday (it is called "yom rishon"
which means "first day", by the way).
The work week these days is usually from Sunday to Thursday.

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

From: Peter Hermann
Sent: Thursday, October 23, 2003  7:25 AM

> tell us about your habits.

Monday is #1 in all over Europe.
In Germany I am used to this without exception.

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

From: Martin Dowie
Sent: Thursday, October 23, 2003  9:06 AM

> > > > > why extend via a child package rather than just adding the
> > > > > new routines to the existing Ada.Calendar package?
[snip]
> Sigh. Anytime you add a "with" or "use", you should expect
> things to break. But that can only happen in *new* or *modified*
> code. What we're concerned about is *existing* code that is
> recompiled with compiler that happens to support Ada 200Y
> features. This should work, unmodified. That's especially
> important was we're expecting Ada 200Y to be adopted
> incrementally, not all at once as Ada 95 was. If someone doesn't
> use new features, their code should continue to work. (There are
> a couple of cases where that won't be true, but we believe that
> they are unlikely to occur in practice. Extra overloadings of
> "Split" are much more likely to cause trouble.)

Randy,

When you say there are a "couple of cases where that won't be true",
did you have AI95-00301 (Ada.Strings.Unbounded)) in mind?

If so, then I think this is a *lot* more likely to break existing
code in practice than adding the additional routines to Ada.Calendar.
From what I can see in 301 no one has even raised this as an issue.

But I guess YMMV. :-)

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

From: Juanma Barranquero
Sent: Thursday, October 23, 2003 12:52 PM

> Do your calendars start the week with Monday?

Yeah. A calendar with weeks starting on Sunday would look positively
weird (to us, anyway).

BTW, the system calendar in my Windows XP (Spanish) shows
monday-starting weeks. It is so in English releases?

>   "weekend" including Sunday doesn't cause us any cognitive difficulties,
> because it is considered to be in relation to the "work week" or
> "school week", not the calendar week.

The cognitive disonance is that, for most of us, there aren't two weeks,
a "work" week and a "calendar" or "religious" week. There are just weeks,
and they match with what you call "work week".

I'm talking seriously. I know a lot of people with good cultural
backgrounds who don't even know that the week ever started on Sunday.

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

From: Dan Eilers
Sent: Thursday, October 23, 2003  1:49 PM

> BTW, the system calendar in my Windows XP (Spanish) shows
> monday-starting weeks. It is so in English releases?

No, here the Windows XP calendar (and all the Unix calendars I
have access to) start the week on Sunday.  I'm sure there is
a localization file somewhere that gives the country-by-country
conventions, and it would be very enlightening to see.

> I'm talking seriously. I know a lot of people with good cultural
> backgrounds who don't even know that the week ever started on Sunday.

Wow.  Do Catholics in Spain still celebrate Easter on Sunday?
If so, they must wonder why Easter is celebrated on the 7th day of
the week when well-known passages in Matthew, Mark, Luke, and John
all place the resurrection "on the first day of the week".

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

From: Tucker Taft
Sent: Thursday, October 23, 2003  2:44 PM

Well we have always said that Ada language lawyers are great
at debating the number of angels that can fit on the head of a pin.
I think this long-running discussion thread is the closest
we have come to the literal meaning of this figure of speech.  ;-)

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

From: Juanma Barranquero
Sent: Thursday, October 23, 2003  2:10 PM

> Wow.  Do Catholics in Spain still celebrate Easter on Sunday?

Sure. Catholics do. According to statistics, like 95% or more of
spaniards are catholics. In the real world, not a person in ten goes to
church on a weekly (or even yearly) basis, other than to social acts
like marriages and the like. Most spanish catholics define themselves
like "non-practitioner catholics". I'm supposedly catholic and I haven't
celebrated Easter in my whole life.

And I'd say this is getting off-topic *really* fast :)

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

From: Alexandre E. Kopilovitch
Sent: Thursday, October 23, 2003  7:42 PM

To confuse you even more, I must tell you that Russian name for Sunday (both
common and official) is exactly "Resurrection" ("Voskresenye" in Russian), and
Russian Christians are mostly Ortodox Christians. Still Russians think of Sunday
as of 7th day of week.

I guess than those Christians for whom Sunday is 7th day of week may use quite
simple logic: as God rested on 7th day of week and we rest on Sunday (note
that Saturday was not a holiday until relatively recently) then ...

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

From: Randy Brukardt
Sent: Thursday, October 23, 2003 12:02 PM

Martin Dowie said:

> When you say there are a "couple of cases where that won't be true",
> did you have AI95-00301 (Ada.Strings.Unbounded)) in mind?

No. I was thinking of two AIs having to do with Ada.Exceptions.

> If so, then I think this is a *lot* more likely to break existing
> code in practice than adding the additional routines to Ada.Calendar.
> From what I can see in 301 no one has even raised this as an issue.

You must be looking at an old version of 301. There was a lot of discussion
about compatibility with it, and virtually all of the overloadings that
would cause trouble have either been removed or renamed. We removed some
more of them at the most recent meeting. What's left is a few new routines
with new names and an additional parameter to Index. No overloading that
might cause problems.

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

From: Martin Dowie
Sent: Thursday, October 23, 2003  12:20 PM

But the problem (in my eyes!) with the new Ada.Calendar subprograms
was that they were in a new child package (kludge alert!).

I was shot down for suggesting that the new operations should go in
Ada.Calendar and I now see in AI-301 that this is exactly what is
proposed to 'fix' ASU.

Me thinks there is some inconsistency a-foot!

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

From: Randy Brukardt
Sent: Thursday, October 23, 2003  1:10 PM

The new time operations don't go in Calendar because they don't have much to
do with the primary purpose of Calendar. The majority of them are for
human-readable time access, not for any of the core purposes of Calendar
(providing a time base).

The main problem that I see is the lame name of the child package, and the
problem there is that really there ought to be several child packages,
separating time zones, differences, and time formatting. That would make the
contents more logical and clearly separate from Calendar. Argubly the
differences stuff belongs in Calendar itself, but I think you'll find
opposition to that because the new operator symbols would make some existing
programs illegal. (Adding operators is always dangerous.)

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

From: Martin Dowie
Sent: Thursday, October 23, 2003  3:32 PM

> The new time operations don't go in Calendar because they don't have much to
> do with the primary purpose of Calendar. The majority of them are for
> human-readable time access, not for any of the core purposes of Calendar
> (providing a time base).

function Day_Of_Week from Time?

Actually, I think this is the one that irked me most... :-)

> The main problem that I see is the lame name of the child package, and the
> problem there is that really there ought to be several child packages,
> separating time zones, differences, and time formatting. That would make the
> contents more logical and clearly separate from Calendar. Argubly the
> differences stuff belongs in Calendar itself, but I think you'll find
> opposition to that because the new operator symbols would make some existing
> programs illegal. (Adding operators is always dangerous.)

Yeah, the name is/was _lousy_ I hope your new AI proposal fits this
description - sounds much better!

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

From: Jeffrey Carter
Sent: Thursday, October 23, 2003  7:41 PM

> Being from France, I can attest that the first day is Monday, and I
> guess it
> is the case in most other European countries. Please, readers from other
> countries,
> tell us about your habits.

European countries use Monday as the first week, including the UK, but
this is a fairly new convention (measured in decades in countries with
centuries of history). Back in the good old days, they used Sunday as
the first day.

In the US, Sunday is still considered the first day, but then we also
use inches, feet, miles, ounces, pounds, degrees F, and other obsolete
concepts.

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

From: David C. Hoos
Sent: Friday, October 24, 2003  12:29 PM

For what it's worth, the names of the days of the week in Portuguese
are Domingo, Segunda-feira, Terca-feira, Quarta-feira, Quinta-feira,
Sexta-feira, Sabado --.i.e. naming the workdaya in most of the world
as second-day through sixth-day.

For yet another convention, the imesheets in all of the defense contractors
for whom I have worked, the pay week is Saturday, Sunday, Monday,
Tuesday, Wednesday, Thursday, Friday.

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

From: Alexandre E. Kopilovitch
Sent: Friday, October 24, 2003  1:23 PM

Contrary to that, Russian names for days of week clearly indicate that Tuesday
is second day ("Vtornik"), Thursday is fourth day ("Chetverg") and Friday is
fifth day ("Pyatnitsa"). [Monday is associated with "per week" ("Ponedelnik"),
Wednesday - with "middle" ("Sreda"), Saturday is clearly originated from
Sabbat ("Subbota") and Sunday is exactly "resurrection" ("Voskresenye"). ]

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

From: Jeff Cousins
Sent: Thursday, October 30, 2003  3:53 AM

I think "liturgical week" points to the root of the problem.  The liturgical
week does not have to equal the secular week.  The Church of England has a
liturgical year that begins at Advent but that doesn't mean that it objects
to January 1st being commonly referred to as New Year's Day.

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

From: John Barnes
Sent: Friday, October 31, 2003  2:02 AM

And on a similar vein the UK tax year starts on April 6th.
It was March 25th (a Qurater Day) more or less in line with
the ancient Roman calendar I believe.  But when the
calendars corrected and 12 days were chopped out, the tax
authorities and taxpayers couldn't face a short year and so
it got shifted into April.

Well there's an irrelevant piece of infromation.

We need a standard - it doesn't matter too much what it is.

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

From: Jean-Pierre Rosen
Sent: Friday, October 31, 2003  3:15 AM

I suggest we apply YADR (Yet Another Dewar's Rule):
If it has been decided before, and there is no new element, don't change
the decision.

People at ISO, who were certainly more knowledgeable on this issue than
we are, have decided that the week would start on Monday. I don't think
we have anything new to add since this decision was taken. Moreover, we
would need *very compelling reasons* to have an ISO standard contradict
another ISO standard.

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

From: Dan Eilers
Sent: Friday, October 31, 2003 11:18 AM

I think it is somewhat unfair to characterize this issue as abiding
by vs. disregarding a prior ISO decision.  As you know, the prior
ISO decisions on this issue are in apparent conflict, so it is
more a question of which ISO decision is more directly relevant
for Ada's purposes.

The prior ISO standards relating to internal representations of dates
within software applications, and for communication of dates between
applications and operating systems services (e.g., ISO C, ISO C++,
and ISO Posix), use Sunday=0, Saturday=6.  The ISO standard for external
representation of dates uses Sunday=7, Saturday=6.

I would contend that the interoperability concerns with C, C++, and Posix
are more relevant for Ada's purposes than the interoperability concerns
with external date formats.

I would also note that even in Europe, where the convention for the
starting day of the secular week has shifted relatively recently from
its historic definition imposed by the Roman Emperor Constantine in
AD 321 (http://www.cjvlang.com/Dow/main/dow1.html), recent European
Committee on Standardization documents (e.g., CEN CWA 14051-1 2001,
http://www.uazone.org/multiling/euroml/euremldocs/cwa14051-1.pdf),
which are cognizant of ISO 8601, still use the traditional convention
of listing Sunday first when enumerating the days of the week.

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

From: Jean-Pierre Rosen
Sent: Monday, November 3, 2003  4:42 AM

OTOH, natural Ada usage would imply that you can define subtypes Work_Days and
Week_Ends, the latter meanint that you need Saturday and Sunday to be adjacent.

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

From: Jeff Cousins
Sent: Monday, November 3, 2003  5:46 AM

Or maybe we need an AI proposing modular enumeration types...

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

From: Peter Hermann
Sent: Monday, November 3, 2003  5:08 AM

which is most practical for the majority, like in:

International Standard ISO 8601 specifies numeric representations
of date and time:
"A week starts with Monday (day 1) and ends with Sunday (day 7)."

I see no need to sacrifice practicality to a religious minority.
BTW, is NYSE working on sundays?

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

From: Dan Eilers
Sent: Monday, November 3, 2003  2:58 PM

This is of course a completely different argument than your previous
contention that ISO compliance requires weeks to start on Monday.

Using subranges of enumeration types as poor-man's sets is not generally
advisable, since a change to the enumeration type (such as would happen
when switching to a different date package with a different weekday'first)
will wreak havoc.

There is an example of how to do sets properly in Ada at
http://www.adapower.com/lang/sets.htm.


Peter Hermann wrote:
> BTW, is NYSE working on sundays?

The NYSE, being a U.S. financial institution, is open for business
Monday through Friday, and considers Sunday to be first day of the week.
See http://www.nyse.com/events/1047970075331.html.

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

From: David C. Hoos, Sr.
Sent: Wednesday, November 5, 2003  6:18 AM

> There is an example of how to do sets properly in Ada at
> http://www.adapower.com/lang/sets.htm.

The correct link is
 http://www.adapower.com/lang/sets.html.

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

From: R. T. Crowley
Sent: Tuesday, November 11, 2003  2:34 PM

I have been having a rather interesting discussion with Dan Eilers of Irvine
Compiler Corporation, and he suggested I forward an opinion on the concept of
"week-date" to you from ISO TC154.  Apparently, there is some question as to
why the "week-date" numbering and starting point in ISO8601 is different from
that used in the ISO C, C++, and POSIX standards for representing dates/times
in binary form.  This discussion apparently began with an email from
Jean-Pierre Rosen, stating, "People at ISO, who were certainly more
knowledgeable on this issue than we are, have decided that the week would start
on Monday.  I don't think we have anything new to add since this decision was
taken.  Moreover, we would need *very compelling reasons* to have an ISO
standard contradict another ISO standard."  After some discussion among our
experts on this we would like to present some further detail.

First, we need to consider the scope of ISO8601.  The standard described in ISO8601 is about representation of dates and times in data interchange when expressed in characters, so it applies to representation on paper, on screen,
in text based messages (e.g. EDI), and in text based files and databases.  How
a date is actually represented internally in a (computer) system is not
ISO8601's business.  Obviously if you have an environment which is text
oriented (like COBOL) you are well advised to use text representation.
However, if you work in a "bit oriented environment" you might consider to
condense something like 2003-11-12 into less bits (if that serves any purpose)
as long as you do not use it for information interchange.  You could for
instance convert to Julian date, and store that value as a (bit encoded)
integer.  In our current terminology we would call that a different time scale.
However, whereas direct conflicts may in this way be circumvented (in a fairly
artificial way) and may be mappable; the results of a statement like "the turnover in week X = $...."  in an Ada and an ISO8601 environment become risky
to compare as they cover different time intervals.

Second, and perhaps more directly to Mr. Rosen's comments about the concept of
week we should understand there is more in the definition of week then just assigning numbers to days.  ISO8601 is very clear in stating which days
together form a (calendar) week, showing Saturday and Sunday at the end of the
week clearly shows why those two days are called the "weekEND" in English.
Showing weeks beginning on Monday is according to a long standing tradition (therefore a business need) as practiced in Europe and many other parts of the
world.  If one were to show Sunday to (next) Saturday on one page of an agenda,
one would not be able to say which week is contained on that page because it
would contain parts of two weeks.  By showing Monday to Sunday on a page you
can do this.  Making Sunday the first day of the week will not only change the
week-number associated with the day, but for some days even the year to which
the week is assigned.

Third, the choice of numbers applied to each day was questioned during the
discussion since ISO8601starts by showing the week-date for Monday as a 1, and
ISO C, C++, and POSIX standards show a week-date for Sunday as a 0.  It is
apparent the assignment of specific codes was done to indicate a sort order rather than to assign any specific meaning based on the numerals used, in and
of themselves.  The numbers or codes used could be arbitrarily chosen as any
numerical, or even alphabetical, sequence, as long as they keep the days of the
week in proper order according to international custom.

I trust this clarifies the points shown, and indicates the position of ISO
TC154 on the matter, based upon our interpretation of the standard in ISO8601
according to the questions raised.  Please feel free to contact me or Louis Visser (louis.visser@nen.nl) on any further questions to do with ISO8601 you
may have.

          Best Regards,
               Bob

     R.T.Crowley - Vice Chair, ISO TC154 US TAG
                         Senior Vice President

     Research Triangle Software, Inc.
     Suite 200
     1135 Kildaire Farm Road
     Cary, NC  27511

     Tel: +1-919-657-0505
     Cell: +1-919-349-3557
     Fax: +1-919-657-0589
     Web: www.rtseducation.com
              www.ediassistant.com
              www.cryptobuddy.com
              www.rtsz.com

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

From: Randy Brukardt
Sent: Tuesday, November 11, 2003  5:20 PM

R.T. Crowley wrote:

> I have been having a rather interesting discussion with Dan Eilers of Irvine
> Compiler Corporation, and he suggested I forward an opinion on the concept of
> "week-date" to you from ISO TC154.
...
> First, we need to consider the scope of ISO8601.  The standard
> described in ISO8601 is about representation of dates and times
> in data interchange when expressed in characters, so it applies
> to representation on paper, on screen,
> in text based messages (e.g. EDI), and in text based files and databases. How
> a date is actually represented internally in a (computer) system is not
> ISO8601's business.  Obviously if you have an environment which is text
> oriented (like COBOL) you are well advised to use text representation.
> However, if you work in a "bit oriented environment" you might consider to
> condense something like 2003-11-12 into less bits (if that serves any purpose)
> as long as you do not use it for information interchange.  You could for
> instance convert to Julian date, and store that value as a (bit encoded)
> integer.  In our current terminology we would call that a different time scale.
> However, whereas direct conflicts may in this way be circumvented (in a fairly
> artificial way) and may be mappable; the results of a statement
> like "the turnover in week X = $...."  in an Ada and an ISO8601
> environment become risky to compare as they cover different time intervals.

This seems to have a bit of a misconception of what we're doing. We're
working on standardizing a program interface to provide improved
capabilities for manipulating times. Nothing in the Ada standard says
anything about binary representations (these are always up to the
implementation); it only have an effect on how times (and part of times,
such as the day of the week) are manipulated in program text. Similarly
(except for one pair of functions which use a subset of the ISO 8601
representation), nothing in the standard requires any particular text
representation. We're simply defining a set of operations on times and their
properties. Any Ada implementation that managed to use a representation
where a compare or difference gets the "wrong" answer is wrong and ought to
be fixed. What the standard is about is insuring the definition of the
"right answer" is clear.

> Second, and perhaps more directly to Mr. Rosen's comments about the concept
> of week we should understand there is more in the definition of week
> then just assigning numbers to days.  ISO8601 is very clear in stating which days
> together form a (calendar) week, showing Saturday and Sunday at the end of the
> week clearly shows why those two days are called the "weekEND" in English.

As any American 5 year old can tell you, this argument is rubbish. It's
called the weekend because it is the days at each end of the week (the first
and last days). (Which doesn't change what ISO 8601 says, of course.)

> Showing weeks beginning on Monday is according to a long standing
> tradition (therefore a business need) as practiced in Europe and many
> other parts of the world.  If one were to show Sunday to (next) Saturday
> on one page of an agenda,
> one would not be able to say which week is contained on that page because it
> would contain parts of two weeks.  By showing Monday to Sunday on a page you
> can do this.  Making Sunday the first day of the week will not only change the
> week-number associated with the day, but for some days even the year to which
> the week is assigned.

Of course, this assumes a definition of "week" that does not match that used
in some significant parts of the world. The long standing tradition in the
US is precisely to do that (Sunday first, Saturday last which constitutes a
week), and here you're ignoring the "long-standing business need" for the
US. (The week-numbering definitions in ISO 8601 are so confusing -
especially to US-based users - and aren't particularly useful, so we don't
plan to offer any such capabilities in Ada.)

Anyway, taking off my end-user hat and putting on my ISO standards editor
hat: It is clear that the ISO 8601 committee did indeed consider these
issues and make a decision on which day was first. Those that were arguing
the opposite are simply wrong. (The fact that 8601 got the 'wrong' answer is
irrelevant. The process of ISO - one country, one vote - pretty much insures
that the wrong answer will be decided in cases where Europe [many countries]
differs from the US [one country]. That's just the way it is, folks, and
that isn't going to change.)

> Third, the choice of numbers applied to each day was questioned during the
> discussion since ISO8601starts by showing the week-date for Monday as a 1, and
> ISO C, C++, and POSIX standards show a week-date for Sunday as a 0.  It is
> apparent the assignment of specific codes was done to indicate a
> sort order rather than to assign any specific meaning based on the numerals
> used, in and of themselves.  The numbers or codes used could be arbitrarily
> chosen as any numerical, or even alphabetical, sequence, as long as they keep
> the days of the week in proper order according to international custom.

Right. The only substantive difference between the proposals is whether
Sunday < Monday or whether Sunday > Monday. In practice, this difference
will hardly ever matter (comparing days of the week is much more likely to
cause errors than comparing the original time values from which the days of
the week were extracted in the first place).

It's clear that ISO 8601 says that Sunday > Monday, and therefore (in the
absence of good arguments to the contrary), Ada should do the same. Given
that there is very little difference in practice (other than the odd
definition), it just isn't worth trying to get the 'right' definition.
(Especially as the only way to do that is to leave it out of the standard.)

(Which I hope brings to a close the 100+ messages on this topic...but I
doubt it.)

          Randy Brukardt
          Editor, ISO/IEC JTC1 SC22 WG9 ARG;
          Editor, ISO/IEC 8652 (Amendment in progress);
          Editor, AI-351 (the proposal in question), alternatively:
          Owner, This Hot Potato (as our chairman described it)

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

From: Peter Hermann
Sent: Wednesday, November 12, 2003  6:48 AM

> It's clear that ISO 8601 says that Sunday > Monday, and therefore (in the
> absence of good arguments to the contrary), Ada should do the same. Given

thank you: I need this for similar practical reasons like for instance
the overcoming of the arbitrary limit of number_bases (ac00070).

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

From: Nick Roberts
Sent: Saturday, November 15, 2003 11:08 PM

I'd like to make the following comments and preliminary amendment proposal,
which is based in part on the proposal and comments in AI-351.

If anything I say here contradicts what I've said before, please consider
this comment to be overriding.

~~~

1. Range of Ada.Calendar.Year_Number

I suggest the range of this subtype is made implementation defined. The
minimum range 1901..2099 should be imposed at the very least, of course,
but maybe the minimum should be extended somewhat. Randy suggests
1600..2400, which I think is probably about right.

I urge that the so-called 'Y2.1K problem' be taken seriously, and dealt
with as early as possible.

~~~

2. Hours, Minutes, and Seconds

I suggest the following package is introduced:

package Ada.Calendar.HMS is

   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;

   Seconds_Per_Minute : constant := 60.0;
   Seconds_Per_Hour   : constant := 60 * Seconds_Per_Minute;

   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 := 0;
                     Sub_Second : Second_Duration := 0.0) return Time;

end Ada.Calendar.HMS;

The named numbers Seconds_Per_Minute and Seconds_Per_Hour are to assist in
clearly and easily programming computations which involve hours and/or
minutes.

The meaning of the other declarations in this package are as already
described in AI-351.

~~~

3. Days and long durations

I suggest the following package is introduced:

with Ada.Calendar.HMS;
package Ada.Calendar.Diurnal is

   type Long_Duration is delta [imp def] range [imp def];

   type Day_Count is range 0..[imp def];

   Seconds_Per_Day : constant := 24 * HMS.Seconds_Per_Hour;

   function Whole_Days (Interval : Long_Duration) return Day_Count;

   procedure Split (Interval : in  Long_Duration;
                    Days     : out Day_Count;
                    Seconds  : out Day_Duration);

   function Duration_Of (Days    : Day_Count;
                         Seconds : Day_Duration := 0.0)
         return Long_Duration;

   function "+" (Left : Time; Right : Long_Duration) return Time;
   function "+" (Left : Long_Duration; Right : Time) return Time;
   function "-" (Left : Time; Right : Long_Duration) return Time;
   function "-" (Left, Right : Time) return Long_Duration;

end Ada.Calendar.Diurnal;

The fixed-point type Long_Duration represents a length of time (with no
specific start or end point), in seconds. The delta and range of this type
are implementation defined, but I suggest the standard imposes minimum
requirements, possibly:

   Long_Duration'Delta <= 1.0
   Long_Duration'First <= -(400 * 365.25 * 86_400)
   Long_Duration'Last  >= 400 * 365.25 * 86_400

The principle purpose of this type, as the name suggests, is to provide a
duration type with a much greater range than Standard.Duration, possibly at
the cost of reduced precision.

The type Day_Count is used by subprograms which manipulate intervals in
terms of whole days. Its upper bound is implementation defined, but I
suggest the standard imposes a minimum, for example 146_100 (about 400
years).

The named number Seconds_Per_Day is to assist the clear and easy
programming of computations which involve intervals in terms of days.

The usual composition, decomposition, and mixed arithmetic operations are
provided.

~~~

4. Weeks and days of the week

I suggest the following package is introduced:

with Ada.Calendar.Diurnal;
package Ada.Calendar.Weeks is

   Seconds_Per_Week : constant := Ada.Calendar.Diurnal.Seconds_Per_Day * 7;

   type Day_Name is
      (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);

   function Day_of_Week (Date : Time) return Day_Name;

end Ada.Calendar.Weeks;

I support using the declaration:

   type Day_Name is
      (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);

rather than the declaration:

   type Day_Name is
      (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);

since the latter would preclude an encoding that was compatible with the C
encoding (where Sunday has the code 0, Monday has 1, and so on). It would
strongly suit at least some implementations to be able to use the C
encoding.

Within an application, it would be very easy to define a different
effective ordering of the days, for example by declaring an appropriate
constant array.

I am sure that the choice between the above two possible declarations of
Day_Name has no significant impact on the computation of week numbers
(within the year) conforming to ISO 8601, and has no other consequences as
regards conformity to ISO 8601 provided an array such as the following were
used to convert between each day of the week and its corresponding number:

   subtype Day_of_Week_Number is Integer range 1..7;

   DOW_Number: constant array (Day_Name) of Day_of_Week_Number :=
      (Monday    => 1,
       Tuesday   => 2,
       Wednesday => 3,
       Thursday  => 4,
       Friday    => 5,
       Saturday  => 6,
       Sunday    => 7);

That a standard programming languages declares Sunday first should not be
interpreted as an assertion as to the correctness of that order of the days
of the week from a political, trade, industrial, traditional, religious, or
cultural point of view. It would be a purely technical decision.

~~~

5. Time-related I/O

I suggest the proposed Image and Value functions are dropped, and the
following I/O packages are provided, which use a format based on ISO 8601,
with only the simplest formatting options:

with Ada.Calendar, Ada.Text_IO;
package Ada.Time_Text_IO is

   Default_Aft   : Ada.Text_IO.Field := Day_Duration'Aft;
   Default_Width : Ada.Text_IO.Field := 20+Default_Aft;

   procedure Get (File  : in  Ada.Text_IO.File_Type;
                  Item  : out Ada.Calendar.Time;
                  Width : in  Ada.Text_IO.Field := 0);

   procedure Get (Item  : out Ada.Calendar.Time;
                  Width : in  Ada.Text_IO.Field := 0);

   procedure Put (File  : in  Ada.Text_IO.File_Type;
                  Item  : out Ada.Calendar.Time;
                  Width : in  Ada.Text_IO.Field := Default_Width;
                  Aft   : in  Ada.Text_IO.Field := Default_Aft);

   procedure Put (Item  : out Ada.Calendar.Time;
                  Width : in  Ada.Text_IO.Field := Default_Width;
                  Aft   : in  Ada.Text_IO.Field := Default_Aft);

   procedure Get (From : in  String;
                  Item : out Ada.Calendar.Time;
                  Last : out Positive);

   procedure Put (To   : out String;
                  Item : out Ada.Calendar.Time;
                  Aft  : in  Ada.Text_IO.Field := Default_Aft);

end Ada.Time_Text_IO;

with Ada.Calendar.Diurnal, Ada.Text_IO;
generic
   type Interval_Type is delta <>;
package Ada.Text_IO.Time_Interval_IO is

   Day_Count_Width : constant := Ada.Calendar.Diurnal.Day_Count'Width;

   Default_Aft   : Ada.Text_IO.Field := Duration'Aft;
   Default_Width : Ada.Text_IO.Field := 14 + Day_Count_Width + Default_Aft;

   procedure Get (File  : in  Ada.Text_IO.File_Type;
                  Item  : out Interval_Type;
                  Width : in  Ada.Text_IO.Field := 0);

   procedure Get (Item  : out Interval_Type;
                  Width : in  Ada.Text_IO.Field := 0);

   procedure Put (File  : in  Ada.Text_IO.File_Type;
                  Item  : out Interval_Type;
                  Width : in  Ada.Text_IO.Field := Default_Width;
                  Aft   : in  Ada.Text_IO.Field := Default_Aft);

   procedure Put (Item  : out Interval_Type;
                  Width : in  Ada.Text_IO.Field := Default_Width;
                  Aft   : in  Ada.Text_IO.Field := Default_Aft);

   procedure Get (From : in  String;
                  Item : out Interval_Type;
                  Last : out Positive);

   procedure Put (To   : out String;
                  Item : out Interval_Type;
                  Aft  : in  Ada.Text_IO.Field := Default_Aft);

end Ada.Text_IO.Time_Interval_IO;

with Ada.Text_IO;
generic
   type Offset_Type is delta <>;
package Ada.Text_IO.Time_Offset_IO is

   Default_Width : Ada.Text_IO.Field := 6;
   Default_Aft   : Ada.Text_IO.Field := 0;

   procedure Get (File  : in  Ada.Text_IO.File_Type;
                  Item  : out Offset_Type;
                  Width : in  Ada.Text_IO.Field := 0);

   procedure Get (Item  : out Offset_Type;
                  Width : in  Ada.Text_IO.Field := 0);

   procedure Put (File  : in  Ada.Text_IO.File_Type;
                  Item  : out Offset_Type;
                  Width : in  Ada.Text_IO.Field := Default_Width;
                  Aft   : in  Ada.Text_IO.Field := Default_Aft);

   procedure Put (Item  : out Offset_Type;
                  Width : in  Ada.Text_IO.Field := Default_Width;
                  Aft   : in  Ada.Text_IO.Field := Default_Aft);

   procedure Get (From : in  String;
                  Item : out Offset_Type;
                  Last : out Positive);

   procedure Put (To   : out String;
                  Item : out Offset_Type;
                  Aft  : in  Ada.Text_IO.Field := Default_Aft);

end Ada.Text_IO.Time_Offset_IO;

The general format for the output of values of the type Ada.Calendar.Time
by the package Ada.Time_Text_IO is:

   YYYY-MM-DDTHH:MM:SS.SSSSSS

where '-', ':', 'T', and '.' are literal, and each numeric field has
leading zeroes. The number of sub-second digits output is given by Aft; if
Aft is 0, the decimal separator '.' is not output. Examples are:

   1965-06-28T23:53:12.970
   2003-11-15T20:55:01.246357

The format expected for input is the same, except that any number of sub-
second digits are permitted (and the decimal separator may be omitted if
there are none), and either (but not both together) of the following
variations are permitted: the '-', 'T', and ':' literals may be omitted;
each numeric field may have some or all of its leading zeroes omitted.

The general format for the output of values of the type Interval_Type in
instantiations of the generic package Ada.Text_IO.Time_Interval_IO is:

   PnDTnHnMn.nS

where 'P', 'D', 'T', 'H', 'S', and '.' are literal, and each numeric field
has no leading zeroes or blanks. The given interval must not be negative
(Constraint_Error is raised if it is), and will be equal to the number of
days (the n before the 'D') scaled by the number of seconds per day, plus
the number of hours (the n before the 'H') and minutes (the n before the
'M') also appropriately scaled, and seconds (the n.n before the 'S'). The
number of sub-second digits output is given by Aft; if Aft is 0, the
decimal separator '.' is not output. Examples are:

   P147DT3H57M46S
   P0DT0H1M20.000000S

The format expected for input is the same, except that any number of sub-
second digits are permitted (and the decimal separator may be omitted if
there are none), and leading zeroes are permitted.

The general format for the output of values of the type Offset_Type in
instantiations of the generic package Ada.Text_IO.Time_Offset_IO is:

   sHH:MM:SS.SSSSSS

where ':' and '.' are literal, and each numeric field has leading zeroes.
The initial 's' is a '-' if the given offset is negative, or '+' otherwise.
The given offset will be equal to the number of hours ('HH') and minutes
('MM') appropriately scaled, and seconds ('SS'). The number of sub-second
digits output is given by Aft; if Aft is 0, the decimal separator '.' is
not output. If the magnitude is not less than 24 hours, the exception
Constraint_Error is raised. Examples are:

   +01:00:00
   -00:03:52.013

The format expected for input is the same, except that any number of sub-
second digits are permitted (and the decimal separator may be omitted if
there are none), and either (but not both together) of the following
variations are permitted: the ':' literals may be omitted; each numeric
field may have some or all of its leading zeroes omitted.

For all three packages, a maximum width is given in the parameter Width or
in the case of output into a string it is taken to be the width of the
string. If the value 0 is passed for the Width parameter, then there is no
maximum width. If the maximum width is insufficient (for all the output to
fit), the seconds, the preceding separator ':' or following separator 'S',
and any decimal separator '.' and sub-seconds are not output. If the
maximum width is still insufficient, then the minutes, the preceding
separator ':' or following separator 'M' are not output. Except for
instantiations of Ada.Text_IO.Time_Offset_IO, if the maximum width is still
insufficient, then the hours, the preceding separator 'T' and following
separator 'H' if any are not output. If the maximum width is still
insufficient, the exception Ada.IO_Exceptions.Layout_Error is raised (and
nothing is output).

The advantage of using a purely numeric format whose components are in
strictly descending order of significance (from left to right) in all of
these packages is that textual sorting will always work: times will be
sorted in correct chronological order; intervals will be sorted in correct
magnitude order; offsets will be sorted according to magnitude grouped by
negative and positive values.

The advantage of having no spaces in any one time, interval, or offset is
that spaces are used as delimiters between numeric (and enumeration
literal) values in Ada, and it might be valuable to be able to use spaces
as delimiters between those and time-related values.

The specific advantage of outputting time-related values using ISO 8601
formats is to reduce the danger of misinterpretation or the failure of
interpretation by a human (for example by someone not familiar with a
particular non-standard format or a particular language's name for a day or
month) or by software.

I think it is getting into muddy waters trying to cater for too many other
formats, and unnecessary. Within an application, more complicated formats
are easily output by instantiating inner packages of Ada.Text_IO for
subtypes declared in Ada.Calendar (and its children), possibly together
with constant arrays for day or month names. I don't think it would be
appropriate to provide these facilities in the (primary) language standard,
since applications' requirements tend to be too complex and inidividual.

~~~

6. Conversion between local and universal time

In general there will be certain local times (as returned by
Ada.Calendar.Clock) which correspond to more than one UTC time, and vice
versa. This is certainly the case for localities which have daylight saving
time at certain times of the year, but it is a situation that could be
caused by the local time changing for any reason (for example, because the
computer was moved). At the miniscule level, another cause of this problem
will be the occasional adjustments made to UTC (the addition or subtraction
of a leap second).

If the local time can change -- and I think we have to assume that in
general it can -- then either the implementation must get these
calculations wrong, or it must store an indication of the current time zone
(or associated offset from UTC) in the type Time. I suspect the latter
option was not intended, being an unacceptable distributed overhead. The
former option might be considered acceptable, but I just like to point out
the potential problems.

[Incidentally, would the term 'bloat' be a good replacement for the
cumbersome 'distributed overhead'? In fact, isn't the term 'distributed
overhead' itself an example of terminological bloat? :-]

I suggest that if a universal time facility is going to be provided by the
language standard, it should be in a separate package, in a separate
optional annex:

package Ada.Calendar.Zones is

   type Universal_Time is delta [imp def] range [imp def]; -- MJD/UTC

   subtype Local_Time_Offset is Duration range -39_600.0 .. +46_800.0;

   function "+" (Left  : Universal_Time;
                 Right : Local_Time_Offset) return Universal_Time;

   function "+" (Left  : Local_Time_Offset;
                 Right : Universal_Time) return Universal_Time;

   function "-" (Left  : Universal_Time;
                 Right : Local_Time_Offset) return Universal_Time;

   function "-" (Left  : Universal_Time;
                 Right : Universal_Time) return Local_Time_Offset;

   procedure Read_Clock (Date   : out Time;
                         Offset : out Local_Time_Offset);

   procedure Read_Clock (Date      : out Time;
                         Offset    : out Local_Time_Offset;
                         Zone_Name : out String;
                         Zone_Last : out Natural);

   function To_Local (Date   : in Universal_Time;
                      Offset : in Local_Time_Offset := 0.0) return Time;

   function To_Universal (Date   : in Time;
                          Offset : in Local_Time_Offset := 0.0)
         return Universal_Time;

   function Zone_Offset return Local_Time_Offset;

   function Zone_Name return String;

   procedure Set_Zone (Offset : in Local_Time_Offset;
                       Name   : in String := "");

end Ada.Calendar.Zones;

The type Universal_Time is a (visibly) fixed point type that expresses a
point in universal time in terms of Modified Julian Days (MJD) aligned with
UTC (MJD/UTC). For more about MJD please see:

   http://tycho.usno.navy.mil/mjd.html

Note that MJD/UTC is specifically directly related to Coordinated Universal
Time (UTC), so that there is a direct and unambiguous mapping between them.
MJD/UTC can be considered a representation of UTC.

The standard should impose appropriate minimum requirements on the delta
and range of Universal_Time, possibly:

   Universal_Time'Delta <= 86_400 * Duration'Delta

   Universal_Time'First <=
      To_Universal( Time_of(Year_Number'First,1,1,0.0) )

   Universal_Time'Last >=
      To_Universal( Time_of(Year_Number'Last,12,31,86_400.0) )

Since the type Universal_Time is scalar, it should provide a very
convenient means of performing linear temporal calculations.

The subtype Local_Time_Offset represents the difference between local time
and UTC, in seconds, ranging from half a day behind to half a day ahead
with an extra hour leeway at both ends (to accommodate daylight saving
time). The polarity of offset values accords with ISO 8601:

   local time = universal time + offset

The usual mixed arithmetic operations between Universal_Time and
Local_Time_Offset are provided.

The To_Local function converts from universal time (MJD) to the Time type,
adjusted for the given Offset. [The given Offset will be added to the given
Date before the conversion to a Time value.]

The To_Universal function converts from the Time type to universal time
(MJD), adjusted for the given Offset. [The given Offset will be subtracted
from the given Date before the conversion to a Universal_Time value.]

The Read_Clock procedures provide the same functionality as the Clock
function, but they also supply the difference between the time system of
the clock and UTC. The second overloading also supplies the name of the
clock's time zone, if known; the value is put into the first n characters
of Zone_Name, where n is the length of the name, and n-Zone_Name'First+1 is
put into Zone_Last; if the zone name is unavailable for any reason, n=0.

The Zone_Offset and Zone_Name functions return the clock's current offset
and zone name (or "" if none). These values may be prone to external
modification at any moment.

The Set_Zone procedure makes it possible to change the (apparent or
effective) offset and zone name of the system clock. This procedure is
likely to be subject to privilege verification on many systems. It is
implementation defined whether the modifications made by this procedure
propagate to other programs executing in parallel with or after the calling
program.

If Set_Zone is refused permission, it should raise some appropriate
exception. Otherwise, if any of the subprograms fails, it should raise
Time_Error.

I think the advantages of the above package over the proposal in the AI
are:

(a) the Time type is not burdened with anything relating to conversions
between local and universal time;

(b) the Ada.Calendar.Zones package provides the basis for the addition of
much more sophisticated time zone functionality (that it would be
inappropriate to provide in the language standard itself);

(c) the package is optional, so it can be completely ignored by
implementations for which it would be inappropriate (somewhat better, I
think, than the implementation having to provide dummy bodies which always
raise an exception).

~~~

Note that I've spent quite a bit of time (a few days) on this comment,
revising it several times, so I hope that it is now in a reasonably
sensible and useful form. However, I must admit, this also suggests that it
probably still contains faults, so some eagle eyes (and minds) may be in
order when appraising it.

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

From: Martin Dowie
Sent: Monday, February 16, 2004  8:17 AM

I've found a few 'bugettes' in AI-351. I thought I'd e-mail them direct to you,
as I'm sure if I draw people to this AI on Ada-Comment, it will just start a
long an unproductive thread (again). In apparent descending order of importance:

1) Ada.Calendar.Time_Zones [ACTZ]: Ada.Calendar.Formatting [ACF] uses a type
   "Time_Zones.Time_Zone" but ACTZ does actually define such a type;

2) Ada.Calendar.Arithmetic [ACA]: Leap_Seconds_Count used but not defined;

3) Couple of typos in ACF, e.g.
    function Sub_Second (Date : in Time) return Second_Duration;
                         Time_Zone  : in Time_Zones.Time_Zone := 0)
                            return Second_Duration;
   Should there be 1 parameter or 2? I'm guessing 2.

   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;
                      Leap_Second: Boolean := False;
                      Time_Zone  : in Time_Zones.Time_Zone := 0);
                        return Time;
   Extra semi-colon before 'return Time' - this happens a couple of times.

If you think they (the first 2) are worth bring to the attention of Ada-Comment
then feel free to forward them on.

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

From: Martin Dowie
Sent: Monday, February 16, 2004  8:12 AM

> 2) Ada.Calendar.Arithmetic [ACA]: Leap_Seconds_Count used but
> not defined;

Ah, ok, it is defined in ACF, so this needs to be added to ACA's
context clause in the AI.

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


Questions? Ask the ACAA Technical Agent