!standard 09.06 (24) 97-11-14 AI95-00160/01 !class confirmation 96-09-04 !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 96-09-10 !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 , 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... ****************************************************************