Version 1.2 of ais/ai-00160.txt

Unformatted version of ais/ai-00160.txt version 1.2
Other versions for file ais/ai-00160.txt

!standard 09.06 (24)          97-11-14 AI95-00160/01
!class confirmation 96-09-04
!status ARG approved 9-0-1 (by letter ballot) 99-04-26
!status ARG approved (subject to letter ballot) 10-1-2 97-11-14
!status work item 96-09-09
!status received 96-09-04
!priority Medium
!difficulty Medium
!subject Daylight savings & Ada.Calendar
!summary 96-09-09
The values returned by Split and Time_Of are implementation defined at the boundaries of daylight savings time (assuming daylight savings time is supported by the implementation).
!question 96-09-09
Suppose an implementation chooses to keep Calendar.Clock in some canonical form, such as GMT, and that it also chooses to support daylight savings time, by making Split and Time_Of do the appropriate conversions. Is this a valid implementation? (Yes.)
If so, what should Split do when daylight savings time ends in the Fall, given that there are two different Time values for some Year/Month/Day/Second values? And what should Time_Of do when daylight savings time starts in the Spring, given that there are Year/Month/Day/Second values that do not correspond to any Time?
!response 96-09-09
9.6(24,26) say:
24 The functions Year, Month, Day, and Seconds return the corresponding values for a given value of the type Time, as appropriate to an implementation-defined timezone; the procedure Split returns all four corresponding values. Conversely, the function Time_Of combines a year number, a month number, a day number, and a duration, into a value of type Time. The operators "+" and "-" for addition and subtraction of times and durations, and the relational operators for times, have the conventional meaning.
26 The exception Time_Error is raised by the function Time_Of if the actual parameters do not form a proper date. This exception is also raised by the operators "+" and "-" if the result is not representable in the type Time or Duration, as appropriate. This exception is also raised by the function Year or the procedure Split if the year number of the given date is outside of the range of the subtype Year_Number.
9.6(24) uses the phrase "as appropriate to an implementation-defined timezone". The implementation is free to do daylight-savings-processing as part of its time zone handling, so the implementation suggested in the question above is valid. Since it explicitly says "implementation defined", the implementation can do what it wants, so long as the behavior is documented.
When implementing Ada on an operating system that supports time zones, it makes sense to implement the Ada operations in terms of the corresponding operating system operations. It is not reasonable to require Ada programs to do something different from other programs on that system. Nor is it reasonable to require an Ada implementation to re-implement this processing.
9.6(26) might be taken as a requirement that Time_Error be raised by Time_Of in the Spring. However, the RM does not define what is meant by a "proper date". Clearly, February 31 is not a "proper date" -- the term is not entirely meaningless -- but surely the term is vague enough to allow the Ada implementation to use the underlying operating system's notion of "proper date" with respect to the questionable cases considered here. Furthermore, raising Time_Error is probably undesirable, since it is more likely to cause an Ada program to malfunction in rare cases, than to catch a bug in the program.
!appendix

!section 9.6(24)
!subject Daylight savings & Ada.Calendar
!reference RM95-9.6(24)
!from Laurent Guerby 96-08-29
!keyword daylight savings, calendar
!reference 96-5664.a Laurent Guerby  96-8-29>>
!discussion

   The problem is that there's no unique correspondance between
Calendar.Time and dates of the form Year/Month/Day/Second because of
daylight savings. There are two different times for each date in the
range October 27th from 1am to 2am (since a 2am we're back to 1am) --
case 1. And no corresponding time for the range of date between 1am
and 2am the day we loose one hour of sleep -- case 2. The wording of
the relevant section of the RM is the following:

> 24   The functions Year, Month, Day, and Seconds return the corresponding
> values for a given value of the type Time, as appropriate to an
> implementation-defined timezone; the procedure Split returns all four
> corresponding values.  Conversely, the function Time_Of combines a year
> number, a month number, a day number, and a duration, into a value of type
> Time.  The operators "+" and "-" for addition and subtraction of times and
> durations, and the relational operators for times, have the conventional
> meaning.

   What Split should do in case 1, and what Time_Of should do in case
2? Raising Constraint_Error may be appropriate.

   After my signature is a test for case 1.

--
Laurent Guerby <guerby@gnat.com>, Team Ada.
   "Use the Source, Luke. The Source will be with you, always (GPL)."

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

with Ada.Calendar; use Ada.Calendar; use Ada;
with Ada.Text_IO; use Ada.Text_IO;

procedure LG2 is
   Year : Calendar.Year_Number := 1996;
   Month : Calendar.Month_Number := 10;
   Day : Calendar.Day_Number := 27;
   Sec : Calendar.Day_Duration := 3600.0;
   One_Hour : constant Calendar.Day_Duration := 3600.0;
   This : Calendar.Time := Calendar.Time_Of (Year, Month, Day, Sec);
   Check_This :  Calendar.Time;
begin
   Put_Line ("1996 10 27 3600.0");
   Calendar.Split (This, Year, Month, Day, Sec);
   Put (Year_Number'Image (Year));
   Put (Month_Number'Image (Month));
   Put (Day_Number'Image (Day));
   Put_Line (Day_Duration'Image (Sec));

   This := This + One_Hour;

   Put_Line ("Next hour should be 7200.00");
   Calendar.Split (This, Year, Month, Day, Sec);
   Put (Year_Number'Image (Year));
   Put (Month_Number'Image (Month));
   Put (Day_Number'Image (Day));
   Put_Line (Day_Duration'Image (Sec));

   Check_This := Calendar.Time_Of (Year, Month, Day, Sec);
   if Check_This /= This then
      Put_Line ("ooops");
   end if;

end LG2;

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

!section 9.6(24)
!subject Daylight savings & Ada.Calendar
!reference RM95-9.6(24)
!reference 96-5664.a Laurent Guerby  96-8-29
!from Ted Baker 96-08-30
!keyword daylight savings, calendar
!reference 96-5668.a Ted Baker  96-8-30>>
!discussion

Laurent asks:

| 1: What should Split to for a date in the range October
| 27th from 1am to 2am, where there are two different possible
| time values?

| 2: What should Time_Of do for the range of date between 1am
| and 2am the day we lose one hour of sleep?

These questions indicate a misunderstanding of Time.
The type Time behaves as a scalar type.
The functions Split and Time_Of are not affected by the time zone.
It is only the value of Clock that differs between time zones.

--Ted Baker

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

!section 9.6(24)
!subject Daylight savings & Ada.Calendar
!reference RM95-9.6(24)
!reference 96-5664.a Laurent Guerby  96-8-29
!from Robert Dewar
!keyword daylight savings, calendar
!reference 96-5670.a Robert Dewar 96-8-30>>
!discussion

Laurent asked

| 1: What should Split to for a date in the range October
| 27th from 1am to 2am, where there are two different possible
| time values?

| 2: What should Time_Of do for the range of date between 1am
| and 2am the day we lose one hour of sleep?

Ted Baker replied

  These questions indicate a misunderstanding of Time.
  The type Time behaves as a scalar type.
  The functions Split and Time_Of are not affected by the time zone.
  It is only the value of Clock that differs between time zones.

Robert Dewar responds

That is completely wrong Ted. What you say is true in Ada 83, but
Ada 95 was specifically designed to allow you to keep Time in GMT,
with the local time adjustment being in Split and Time_Of, which
are therefore affected byt the time zone.

GNAT takes advantage of this, for example in Time_OF, we have

      --  Since we do not have information on daylight savings,
      --  rely on the default information.

      TM_Val.tm_isdst := -1;

      Result_Secs := mktime (TM_Val'Unchecked_Access);

and in Split, we have

      Tm_Val := localtime (Adjusted_Seconds'Unchecked_Access);

The misunderstanding is yours, and Laurent's questions are valid and
significant.

P.S. maybe I am remembering wrong, but I thought I remembered
you arguing in favor of this change in Ada 95!

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

!section 9.6(24)
!subject Daylight savings & Ada.Calendar
!reference RM95-9.6(24)
!reference 96-5664.a Laurent Guerby  96-8-29
!reference 96-5672.a Ted Baker  96-8-31>>
|reference 96-5670.a Robert Dewar 96-8-30
!from Ted Baker
!keyword daylight savings, calendar
!discussion

Regarding my remarks on "misundertanding", I apologize for going
off half-cocked.  Perhaps my memory was distorted by wishful
thinking, i.e. my wishes turned into a false memory that we had
really solved the time-zone problem in Ada'95.

The ARM clearly leaves it up to the implementor to decide whether
Clock or Split and Time_Of will depend on a local time zone, and
what the local time zone will be.

Though this gives implementors some room to manoeuver, it does not
help applicatino portability or reliability.  A better solution to
the problem would have been to give the user rather than the
implementor control, i.e. to explicitly take into account time
zones, as an explicit new type, with new versions of Split and
Time_Of that take time-zone into account.  Politically, that
probably never had a chance because of concerns for not breaking
existing applications and implementations.

| 1: What should Split do for a date in the range October
| 27th from 1am to 2am, where there are two different possible
| time values?

The existence of this problem already depends on an implementation
choice to make Split and Time_Of (rather than Clock) depend on the
time zone.  Therefore, it makes sense that the implementor return
either of the two sensible values.  Given the effects of Split and
Time_Of are already explictly deeply implementation-dependent, I
don't think the ARG could benefit anyone by trying to specify more
here.

| 2: What should Time_Of do for the range of date between 1am
| and 2am the day we lose one hour of sleep?

This seems to be answered in the ARM, where it says "The exception
Time_Error is raised by the function Time_Of it the actual
parameters do not form a proper date."

--Ted Baker

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

!section 9.6(24)
!subject Daylight savings & Ada.Calendar
!reference RM95-9.6(24)
!reference 96-5664.a Laurent Guerby  96-8-29
!reference as: 96-5672.a Ted Baker  96-8-31
!reference 96-5675.a Robert Dewar 96-9-2>>
|reference 96-5670.a Robert Dewar 96-8-30
!from Robert Dewar 96-09-02
!keyword daylight savings, calendar
!discussion

Ted said

 The ARM clearly leaves it up to the implementor to decide whether
 Clock or Split and Time_Of will depend on a local time zone, and
 what the local time zone will be.

 Though this gives implementors some room to manoeuver, it does not
 help applicatino portability or reliability.  A better solution to
 the problem would have been to give the user rather than the
 implementor control, i.e. to explicitly take into account time
 zones, as an explicit new type, with new versions of Split and
 Time_Of that take time-zone into account.  Politically, that
 probably never had a chance because of concerns for not breaking
 existing applications and implementations.

Robert says

 Nothing political about this. We discussed this possibility, and decided
 it was too implementation dependent to expose (on many systems, the concept
 of time zone is meaningless).

Ted said

 | 1: What should Split do for a date in the range October
 | 27th from 1am to 2am, where there are two different possible
 | time values?

 The existence of this problem already depends on an implementation
 choice to make Split and Time_Of (rather than Clock) depend on the
 time zone.  Therefore, it makes sense that the implementor return
 either of the two sensible values.  Given the effects of Split and
 Time_Of are already explictly deeply implementation-dependent, I
 don't think the ARG could benefit anyone by trying to specify more
 here.

 | 2: What should Time_Of do for the range of date between 1am
 | and 2am the day we lose one hour of sleep?

 This seems to be answered in the ARM, where it says "The exception
 Time_Error is raised by the function Time_Of it the actual
 parameters do not form a proper date."

Robert replies:

 In practice I think all implementations where time zones make sense will
 choose to do things as GNAT does, i.e. to introduce the time zone in the
 split and time_of routines and keep the type time in canonical form.
 Certainly this is something that the ARA might want to discuss as part of
 the ACE.

 As to the recommendations that Ted makes, I am not happy with that half
 way house. The easy thing to do in an implementation in a Unix library
 environment is to use mktime and local_time as in the code I quoted from
 GNAT.

 If you follow the requirement to raise Time_Error, then you are requiring
 an implementation to do all its own time handling anyway (since the Unix
 routines apparently do not meet this requirement). But in that case, why
 leave the other part implementation dependent.

 Split and Time_Of are NOT "deeply implementation dependent". There are simply
 two choices. As I say above, I think all implementations will choose one way
 or the other, and I think we should also try to standardize the behavior.
 I really don't care whether this is done by the ARG, URG, or ACE!

 I think there are two ways to standardize:

   1. say that it is the same as mktime and local_time where this makes sense
      which is nearly everywhere.

   2. specify exactly the semantics that is desired.

 I would go with 1. it's really much easier, but if we go with 1, then we
 are saying the ARG should do nothing, and it should be left up to ACE.
 So, in short, I agree with Ted that the ARG should do nothing here.

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

!section 9.6(24)
!subject Daylight savings & Ada.Calendar
!reference RM95-9.6(24)
!reference 96-5664.a Laurent Guerby  96-8-29
!reference 96-5672.a Ted Baker  96-8-31
!reference 96-5678.a Robert A Duff 96-9-3>>
|reference 96-5670.a Robert Dewar 96-8-30
!reference 96-5677.a Ted Baker  96-9-2
!from Bob Duff
!keyword daylight savings, calendar
!discussion

> It is appropriate that on UNIX systems Ada programs be able to
> obtain the same time and date information as C programs.

It seems to me way too late to be adding time-zone functionality to the
Ada language.

Meanwhile, on Unix, people can pragma Import the desired functionality.
On other systems, such functionality isn't available anyway.
And if you want a standard Ada interface to Unix-specific functionality,
it seems to me that POSIX is the right place for it.  (Well, I guess
*some* non-Unix systems support it.  But still, we shouldn't be in
the business of adding little bells and whistles to the Ada language,
unless there's a hugely important hole in the language.)

IMHO, the answer to the original question should be "implementation
dependent".

- Bob

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

!section 9.6(24)
!subject Daylight savings & Ada.Calendar
!reference RM95-9.6(24)
!reference 96-5664.a Laurent Guerby  96-8-29
!reference as: 96-5672.a Ted Baker  96-8-31
!reference as: 96-5675.a Robert Dewar 96-9-2
!reference 96-5680.a Randy Brukardt  96-9-3>>
|reference 96-5670.a Robert Dewar 96-8-30
!from Randy Brukardt 96-09-03
!keyword daylight savings, calendar
!discussion

Robert says:

 In practice I think all implementations where time zones make sense will
 choose to do things as GNAT does, i.e. to introduce the time zone in the
 split and time_of routines and keep the type time in canonical form.
 Certainly this is something that the ARA might want to discuss as part of
 the ACE.

 As to the recommendations that Ted makes, I am not happy with that half
 way house. The easy thing to do in an implementation in a Unix library
 environment is to use mktime and local_time as in the code I quoted from
 GNAT.

 If you follow the requirement to raise Time_Error, then you are requiring
 an implementation to do all its own time handling anyway (since the Unix
 routines apparently do not meet this requirement). But in that case, why
 leave the other part implementation dependent.

Randy replies:

 As usual, Robert's "obvious way to do things" is not what R.R. Software's
compiler does.  (I'll leave the determination of the wisdom of that to others).

 Our Unix implementation of Calendar does indeed do time zone handling
only in Clock.  Split and Time_Of have no special code to handle time zones.

 That implementation was done years ago, so I cannot tell for sure why it
was done that way.  My best guesses would be that we believed the need
to raise Time_Error for bad times was absolutely required, and secondarily,
we didn't have access to "local_time" (it is not a kernel function, and we did
not have pragma Interface support at the time).  Therefore, most of the time
processing is local to Calendar.

 Obviously, I would prefer that the ARG (and any other quasi-standard) did not
make a ruling which (to me at least) complicates the implementation, and
offers no user benefit that I can detect.  The decision that Calendar returns
the local (computer) time means that it is mainly defined by the machine;
if the time was changed for any reason, Calendar will start returning
discontiguous answers.  The difference between an Unix implementation
(where time zone processing is part of the run-time library) and Windows 95
(which automatically adjusts the computer's time for time zones and
daylight savings time) fro a user perspective is non-existent.  Why should we
be in the business of defining the behavior in one case and leaving it
implementation-defined in the other??

                        Randy.

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

!section 9.6(24)
!subject Daylight savings & Ada.Calendar
!reference RM95-9.6(24)
!reference 96-5664.a Laurent Guerby  96-8-29
!reference 96-5672.a Ted Baker  96-8-31
!reference as: 96-5678.a Robert A Duff 96-9-3
!reference 96-5681.a Robert Dewar 96-9-4>>
|reference 96-5670.a Robert Dewar 96-8-30
!reference 96-5677.a Ted Baker  96-9-2
!from Robert Dewar
!keyword daylight savings, calendar
!discussion

I agree that it is too late to add time-zone functionality to Ada.
I think what is needed here is an AI that points out problem. Note
that there is one important issue to be resolved. In the case of the
conversion of times during the non-existent hour, Ted Baker reads
the RM to require Time_Error to be generated. This is extremely
onerous, since it means that you cannot use the system provided
functionality, but instead have to completely reproduce it, just
to generate Time_Error for this case. I would prefer that the AI
make this implementation dependent also.

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

!section 9.6(24)
!subject Daylight savings & Ada.Calendar
!reference RM95-9.6(24)
!reference 96-5664.a Laurent Guerby  96-8-29
!reference as: 96-5672.a Ted Baker  96-8-31
!reference as: 96-5675.a Robert Dewar 96-9-2
!reference as: 96-5680.a Randy Brukardt  96-9-3
!reference 96-5683.a Robert Dewar 96-9-4>>
|reference 96-5670.a Robert Dewar 96-8-30
!from Robert Dewar
!keyword daylight savings, calendar
!discussion

Randy said

 Our Unix implementation of Calendar does indeed do time zone handling
 only in Clock.  Split and Time_Of have no special code to handle time zones.

 That implementation was done years ago, so I cannot tell for sure why it
 was done that way.  My best guesses would be that we believed the need
 to raise Time_Error for bad times was absolutely required, and secondarily,
 we didn't have access to "local_time" (it is not a kernel function, and we did
 not have pragma Interface support at the time).  Therefore, most of the time
 processing is local to Calendar.

 Obviously, I would prefer that the ARG (and any other quasi-standard) did not
 make a ruling which (to me at least) complicates the implementation, and
 offers no user benefit that I can detect.

Robert replies

 It is perfectly reasonable that an old Ada 83 implementation of Calendar
 work the way Randy describes, because this (undesirable) behavior was
 required in the Ada 83 standard. The Ada 95 standard was deliberately
 changed to allow either approach.

 No one here has suggested that the ARG mandate this approach, so I don't
 know what Randy is objecting to. Of course the existing Ada 83 approach
 is valid. The RM was carefully written to ensure this.

 The discussion is what to do with the strange cases that arise if you
 use the Posix/Unix approach of representing times in GMT. Since RR does
 not use this approach, the discussion is irrelevant to them.

 I do not know what a quasi-standard might be, but I am sure it has nothing
 to do with the formal status of the Ada 95 standar, which is the only topic
 of discussion in this group. My point was merely that the Ada 95 style
 implementation in which the time zones are introduced in split and time_of
 will be common in Ada 95 implementations, and it is reasonable to ask if
 the RM should mandate the behavior.

 In fact the following is the sitution (I am agreeing with Ted's reading)

   o  For the times where two possible GMT values correspond, it is not
      specified which of the two times you obtain.

   o  For the times where no possible GMT value corresponds, Time_Error
      is to be raised.

 For Randy, neither predicate can possibly be true, so he can stop reading
 if he wants.

 I think what we want is that both cases be implementation dependent, with
 an additional requirement in Annex M to document the implementation
 behavior in these two cases (if they arise).

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

!section 9.6(24)
!subject Daylight savings & Ada.Calendar
!reference RM95-9.6(24)
!reference 96-5664.a Laurent Guerby  96-8-29
!reference as: 96-5672.a Ted Baker  96-8-31
!reference as: 96-5675.a Robert Dewar 96-9-2
!reference as: 96-5680.a Randy Brukardt  96-9-3
!reference 96-5670.a Robert Dewar 96-8-30
!from Robert I. Eachus 96-9-4
!keyword daylight savings, calendar
!reference 96-5684.a Robert I. Eachus 96-9-4>>
!discussion

  > Obviously, I would prefer that the ARG (and any other
  > quasi-standard) did not make a ruling which (to me at least)
  > complicates the implementation, and offers no user benefit that I
  > can detect.  The decision that Calendar returns the local
  > (computer) time means that it is mainly defined by the machine; if
  > the time was changed for any reason, Calendar will start returning
  > discontiguous answers.  The difference between an Unix
  > implementation (where time zone processing is part of the run-time
  > library) and Windows 95 (which automatically adjusts the
  > computer's time for time zones and daylight savings time) fro a
  > user perspective is non-existent.  Why should we be in the
  > business of defining the behavior in one case and leaving it
  > implementation-defined in the other??

    I think that it is becoming clear that the "right" solution is to
leave the behavior of Clock, Split, and Time_Of as implementation
defined in this area, and to define a child package of Ada.Calendar
that exports versions of Split and Time_Of that are sensitive to time
zones and daylight savings.

   Who promugates this package is a very different question.  It might
be the first URG action for Ada 95, it could be left until the next
revision of Ada, or it could remain as a de facto standard with no
official force.  (A.2(4) only prohibits the compilation of a (direct)
child of Ada in standard mode, and in any case implementations are
certainly allowed to provide additional child packages of children of
Ada, even in standard mode.)

   My recommendation is that, whether issued as an AI or a UI, we
should have a recommended package to be provided by all
implementations where the underlying systems support time zones.  (Of
course, this will probably common for all operating systems well
before Ada 0X, so the package should be folded into the next
implementation.)

   Having gotten this far out on a limb, I had better include a
suggested package specification:

   package Ada.Calendar.Time_Zones is

     type Time_Zone is private;

     function Offset(Zone: Time_Zone) return Duration;
     function Offset(Date: Time) return Duration;
     function Offset return Duration;
     -- offset from IAT.  If the offset is not stored in values of
     -- type Clock, then the second function returns the current
     -- Offset for the partition. The last version returns the same
     -- value as Offset(Clock).

     function Time_Zone_Of(Date: Time) return Time_Zone;
     -- returns the Time_Zone associated with the value of Date, or
     -- the current Time_Zone for this partition if the Time_Zone is
     -- not part of Date values.

     function Zone(Name: in String) return Time_Zone;

     function Get return Time_Zone;
     -- Get the time zone of the current partition.

     function Get return String;
     -- The name of the current time zone as a string.  While there
     -- may be many strings recognized by an implementation as the
     -- name of a particular zone, which of those names is returned by
     -- Zone is implementation defined.  Preferred is to return the
     -- name used in creating the value if possible.

     procedure Set(Zone: in Time_Zone);
     procedure Set(Zone_Name: in String);
     -- Set the time zone for the current partition.  If the String in
     -- the second call is not recognized by the implementation it
     -- will raise Constraint_Error.

     function Year    (Date: Time; Zone: Time_Zone) return Year_Number;
     function Month   (Date: Time; Zone: Time_Zone) return Month_Number;
     function Day     (Date: Time; Zone: Time_Zone) return Day_Number;
     function Seconds (Date: Time; Zone: Time_Zone) return Day_Duration;

     procedure Split  (Date    : in  Time;
                       Zone    : in  Time_Zone;
                       Year    : out Year_Number;
                       Month   : out Month_Number;
                       Day     : out Day_Number;
                       Seconds : out Day_Duration);

     function Time_Of (Year    : Year_Number;
                       Month   : Month_Number;
                       Day     : Day_Number;
                       Seconds : Day_Duration := 0.0;
                       Zone    : Time_Zone)
     return Time;

     -- All of the above as in Ada.Calendar, but with the addition of
     -- Zone information.  If values of type time do not contain the
     -- zone information, then the value for the current partition is
     -- used.

   private
     -- Implementation Defined
   end Ada.Time_Zones;

   Writing the body of this (and testing it) should be a day's work
for most implementations.  Of course there are some for which it is
still not appropriate.

                                        Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...

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

Questions? Ask the ACAA Technical Agent