Version 1.6 of ais/ai-00160.txt
!standard 09.06 (24) 00-01-25 AI95-00160/03
!class confirmation 96-09-04
!status Response 2000 00-01-25
!status WG9 approved 99-06-12
!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
!qualifier Clarification
!subject Daylight savings & Ada.Calendar
!summary
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
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
9.6(24,26) say:
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.
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.
!ACATS test
This ruling is not practically testable. It leaves some behavior
implementation-defined. Even without this problem, a test could only be run
at a particular time twice a year, which would not be appropriate.
!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