!standard 9.6(24) 08-10-17 AI05-0119-1/00 !standard 9.6.1(41/2) !standard 9.6.1(42/2) !class Amendment 08-10-17 !status work item 08-10-17 !status received 08-08-05 !priority Medium !difficulty Hard !subject Package Calendar, Daylight Savings Time, and UTC_Offset !summary (See proposal.) !problem Ada.Calendar time is not well-defined in the presence of daylight saving time adjustments. 1. Ada.Calendar.Time_Of is ill-defined within the hour when the clock is adjusted backwards. The same year-month-day-seconds quadruple may denote two different dates. For example: year => 2008, month => 10, day => 26, seconds => 2.5 * 3600.0 may refer in Central Europe to 02:30 before the clock adjustment (02:30 CEST) or else a date 1 hour later, after the clock adjustment (02:30 CET). 2. The semantics of Ada.Calendar.Time is not defined. The following example illustrates the case: T0, T1, T2 : Time; begin T0 := Time_Of -– 01:30 CEST ( Year => 2008, Day => 26, Month => 10, Seconds => 1.5 * 3600.0 ); T1 := T0 + 3600.0; -- +1h T2 := T0 + 2.0 * 3600.0; -- +2h The Standard does not clarify whether T1 = T2 or not. A similar question can be asked about the time retrieved by Ada.Calendar.Clock at the times T1 and T2. (The answer may not be the same.) 3. Ada.Calendar.Time_Zones.UTC_Offset function is ill-defined because of the issue of 2. If T1 = T2, then UTC_Offset is broken because T1 is CEST and T2 is CET. These have different offsets to the UTC time, +2h and +1h correspondingly. !proposal ** TBD ** !wording ** TBD ** !discussion [Editor's note: To think about this in the US, use the time November 02, 2008 01:30 AM as the clock will be adjusted at 2:00 AM that day.] The basic problem is that a number of characteristics of Ada.Calendar were left unspecified. This is problematical, because it means that applications that depend on the clock (especially those that require UTC time) are not portable and may break occassionally when the clock is adjusted (depending on the implementation model). A number of fixes are possible: (1) Confirm the standard that these things are undefined. This surely won't break anything, but it also means that there is no way to write some applications in Ada (Ada.Real_Time does not have sufficient range to be used as a replacement). (2) Change the definition of Ada.Calendar.Time to ensure that some indication of the time zone and adjustment is included. Then operations like these can be defined unambigously. But that changes the representation of Ada.Calendar.Time on many implementations. (3) Define that Ada.Calendar.Time is UTC_Time, and provide a function to get local time. That's what Ada 83 ought to have done, but it seems too incompatable to change now. (4) Add wording to 9.6.1(41/2) to specify which result is returned in ambiguous cases. But that really doesn't help much, because there is then an hour of UTC time that can never occur. (5) Create a parallel universe of a UTC_Time package which works right. But that seems amazingly heavy. (6) A simplified proposal like the one found in the e-mail attached here. But that means that for most operations, UTC.Time has to be converted to Calendar.Time (since UTC.Time does not have constructors or splitters), which would clutter programs. There probably are even more approaches necessary. But first we have to decide whether to actually fix this problem. !example !ACATS test !appendix From: Dmitry A. Kazakov Date: Tuesday, August 5, 2008 3:57 AM 1. What is the result (according to the language reference manual) of: UTC_Time_Offset (Ada.Calendar.Time_Of (2008, 26, 10, 2.5*60.0*60.0)); called on a machine with the time zone Amsterdam, Berlin, Bern... Note. 26.10.2008 is the day when the clock will be adjusted 1h backward at 03:00. 2. What is the result of Ada.Calendar.Split applied to Ada.Calendar.Clock called: 2.a. at 26.10.2008 02:30 before clock adjustment; 2.b. one hour later (at 26.10.2008 02:30 after clock adjustment). ------------------- UTC_Time_Offset and Time_Of are ambiguous as defined in the RM. RM 9.6.1 42/2: "Returns, as a number of minutes, the difference between the implementation-defined time zone of Calendar, and UTC time, at the time Date." It is not a function. RM 9.6 24/2: "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 time zone; 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." Split cannot be "converse," because it is irreversible. **************************************************************** From: Jeffrey R. Carter Date: Wednesday, August 6, 2008 2:16 PM > 1. What is the result (according to the language reference manual) of: > > UTC_Time_Offset (Ada.Calendar.Time_Of (2008, 26, 10, > 2.5*60.0*60.0)); > > called on a machine with the time zone Amsterdam, Berlin, Bern... This depends on the definition of the user-defined procedure UTC_Time_Offset. Presuming "use Ada.Calendar.Time_Zones;" and no user-defined procedure UTC_Time_Offset, a compiler error message, since Ada.Calendar.Time_Zones.UTC_Time_Offset is a function, and this is a procedure call. Presuming further that this is a fragment and does represent a function call, Constraint_Error should be raised at the point of the call, because 26 is not a value of Ada.Calendar.Month_Number. **************************************************************** From: Christoph Grein Date: Wednesday, August 6, 2008 11:47 PM I think your answer is a bit saucy, at least a bad joke. The question is absolute clear for any non-malevolent person :-( The RM is unclear about this, and the AARM (42.b/2, c/2) admits this. **************************************************************** From: Jeffery R. Carter Date: Thursday, August 7, 2008 2:09 PM > I think your answer is a bit saucy, at least a bad joke. > The question is absolute clear for any non-malevolent person :-( Perhaps. Is it unreasonable to expect precision from someone who is asking the ARG for precision? > The RM is unclear about this, and the AARM (42.b/2, c/2) admits this. I'm working on an application that deals with times in different time zones, though we never have to deal with times when the clock changes. I've found that understanding and reasoning about the definitions for dealing with time zones in the ARM requires careful attention, but the conclusions I've reached have agreed with the GNAT implementation so far. **************************************************************** From: Pascal Leroy Date: Thursday, August 7, 2008 3:06 AM > RM 9.6.1 42/2: > "Returns, as a number of minutes, the difference between the > implementation-defined time zone of Calendar, and UTC time, at the time > Date." > > It is not a function. I think that 42/2 is fine because UTC_Time_Offset *is* a function. But 44/2 could be worded better because Difference is *not* a function. Perhaps "Computes the difference between...". > RM 9.6 24/2: > > "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 time zone; 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." > > Split cannot be "converse," because it is irreversible. I think you are reading too much in the word "conversely". I don't believe that it was intended to imply reversibility. **************************************************************** From: Dmitry A. Kazakov Date: Thursday, August 7, 2008 3:30 PM > I think that 42/2 is fine because UTC_Time_Offset *is* a function. > But 44/2 could be worded better because Difference is *not* a > function. Perhaps "Computes the difference between...". That does not compute either. Because "the difference" implies that there is exactly one result for each argument, which is equivalent of being a mathematical function. ... > I think you are reading too much in the word "conversely". I don't > believe that it was intended to imply reversibility. If that is true, then the text becomes meaningless: "four corresponding values" of what? How they correspond etc. Basically the texts are inconsistent. Either: 1. Ada.Calendar.Time is defined to have different values (in the sense of the operation "=") at 26.10.2008 02:30 before the clock skew and after it. In this case Time_Of cannot be defined as it was, without specifying with of two dates is meant. 2. Ada.Calendar.Time has same values at both times, then Time_Of is well-defined but UTC_Time_Offset is not a function of the argument. Now which variant is mandatory? And what is the semantics of ill-defined things? P.S. As for existing implementations. GNAT under Windows seems to use the variant 1, with Time_Of returning the time after the skew. **************************************************************** From: Adam Beneschan Date: Thursday, August 7, 2008 7:01 PM > > I think that 42/2 is fine because UTC_Time_Offset *is* a function. > > But 44/2 could be worded better because Difference is *not* a > > function. Perhaps "Computes the difference between...". > > That does not compute either. Because "the difference" implies that > there is exactly one result for each argument, which is equivalent of > being a mathematical function. But there *is* one "difference". The part that returns "the difference" is a mathematical function. The result of this function is then broken into three parts and returned as three OUT parameters. I don't see the problem---it seems clear to me. And Ada-Comment regulars are aware that I'm a major nit-picker whenever I see wording in the RM that I think doesn't say what it means, or is ambiguous. But this paragraph doesn't bother me at all, although I can see why "Returns the difference" appears a little odd since Difference isn't an Ada function. ... > > I think you are reading too much in the word "conversely". I don't > > believe that it was intended to imply reversibility. > > If that is true, then the text becomes meaningless: "four > corresponding values" of what? How they correspond etc. It means that Split returns four OUT parameters, "Year", "Month", "Day", and "Seconds"; and these OUT parameters are set to the same values that the functions of the same names would return. Thus, Split (Date, Y, M, D, S) sets Y := Year(Date), M := Month(Date), and so on. That's what "corresponding" means. It has nothing whatsoever to do with the second sentence of paragraph 24, nor of the Time_Of function. Your issues regarding how this package works around Daylight Savings Time changes point out a real problem. But the questions about wording that you're asking above don't have anything to do with this issue. **************************************************************** From: Dmitry A. Kazakov Date: Friday, August 8, 2008 3:09 AM ... >> That does not compute either. Because "the difference" implies that >> there is exactly one result for each argument, which is equivalent of >> being a mathematical function. > > But there *is* one "difference". No, I meant UTC_Time_Offset, which depends on the definition of the political time. The customary, naive, definition seen in texts refers to "clock adjustment." This reads to me as 26.10.2008 02:30 would be exactly the same Berlin time before and after the clock skew. Otherwise, I don't know what the [political] clock does show. In my previous post it was denoted as the variant 2. The variant 1 referred to a hidden UTC clock which is inconsistent with Time_Of. [As well as with political time, in general. I greatly welcome GNAT's implementation dumping political time, but was it the intention of RM? I thought it wished to preserve political time...] ... > It means that Split returns four OUT parameters, "Year", "Month", > "Day", and "Seconds"; and these OUT parameters are set to the same > values that the functions of the same names would return. Thus, Split > (Date, Y, M, D, S) sets Y := Year(Date), M := Month(Date), and so on. > That's what "corresponding" means. It has nothing whatsoever to do > with the second sentence of paragraph 24, nor of the Time_Of function. How so? The wording is: "The functions Year, Month, Day, and Seconds return the corresponding values for a given value of the type Time ..." -- 9.6 24/2 I.e. the "correspondence" is to be between Year, Month, Day, Seconds and Time. Now, do the quadruple (y, m, d, s) unambiguously denote a political time date or not? RM is silent about that, though the wording let suggest that it does [=variant 2!]. Observe, that the quadruple does not [always] denote an UTC time [because seconds there are "political"], which is inconsistent with "the difference" allegedly returned by UTC_Time_Offset, etc. > Your issues regarding how this package works around Daylight Savings > Time changes point out a real problem. But the questions about > wording that you're asking above don't have anything to do with this > issue. My question was about the semantics. Actually, I don't care much about wording so long I can understand the meaning. Reading RM I was perplexed what is the expected behavior of UTC_Time_Offset, Time_Of and Split. P.S. The problem is quite technical. How to convert Time to UTC time and reverse? **************************************************************** From: Adam Beneschan Date: Friday, August 8, 2008 2:24 PM > How so? The wording is: > > "The functions Year, Month, Day, and Seconds return the > corresponding values for a given value of the type Time ..." -- 9.6 > 24/2 > > I.e. the "correspondence" is to be between Year, Month, Day, Seconds > and Time. Now, do the quadruple (y, m, d, s) unambiguously denote a > political time date or not? OK, I see. The word "corresponding" appears twice in this paragraph, and I thought you were asking about the use of the word in the phrase "four corresponding values", not the other use of the word. I'm beginning to think the RM is using this word too much, especially since a different issue that came up on this list today also involves how that same word is interpreted. I suggest that "corresponding" be added to the Glossary (Annex N), with the definition "We assume you know what we mean". :) :) Anyway, I was answering the question I thought you were asking, but I don't have an answer for the question you really wanted to know about. I'll have to leave that to others, for now. **************************************************************** From: Dmitry A. Kazakov Date: Thursday, August 14, 2008 10:31 AM !summary The proposal is to define the semantics of political time and to add UTC time. The proposal reuses as much as possible of the existing packages descending from Ada.Calendar. Ada.Calendar.Clock can be derived from UTC clock. !problem In presence of daylight saving: 1. Ada.Calendar.Time_Of is ill-defined within the hour when the clock is adjusted backwards. The same year-month-day-seconds quadruple may denote two different dates. For example: year => 2008, month => 10, day => 26, seconds => 2.5 * 3600.0 may refer in Central Europe to 02:30 before the clock adjustment (02:30 CEST) or else a date 1 hour later, after the clock adjustment (02:30 CET). 2. The semantics of Ada.Calendar.Time is not defined. The following example illustrates the case: T0, T1, T2 : Time; begin T0 := Time_Of – 01:30 CEST ( Year => 2008, Day => 26, Month => 10, Seconds => 1.5 * 3600.0 ); T1 := T0 + 3600.0; -- +1h T2 := T0 + 2.0 * 3600.0; -- +2h RM does not clarify whether T1 = T2 or not. 3. Ada.Calendar.Time_Zones.UTC_Offset function is ill-defined because of the issue of 2. If T1 = T2, then UTC_Offset is broken because T1 is CEST and T2 is CET. These have different offsets to the UTC time, +2h and +1h correspondingly. !proposal 1. Ada.Calendar.Time is defined as a political time. In the example: T0, T1, T2 : Time; begin T0 := Time_Of -- 01:30 CEST ( Year => 2008, Day => 26, Month => 10, Seconds => 1.5 * 3600.0 ); T1 := T0 + 3600.0; -- +1h T2 := T0 + 2.0 * 3600.0; -- +2h It is required T1 = T2. The time arithmetic is defined to satisfy this requirement. In particular, if a difference is calculated between two times of which one belongs to the overlapping hour, then this time is treated as having the same UTC offset as another. For example: T0, T1, T2 : Time; begin T0 := Time_Of – 01:30 CEST ( Year => 2008, Day => 26, Month => 10, Seconds => 1.5 * 3600.0 ); T1 := Time_Of – 02:30 CEST or CET ( Year => 2008, Day => 26, Month => 10, Seconds => 2.5 * 3600.0 ); T2 := Time_Of – 03:30 CET ( Year => 2008, Day => 26, Month => 10, Seconds => 3.5 * 3600.0 ); T2 – T1 = 3600.0, here T1 is considered CET as T2 is. T1 – T0 = 3600.0, T1 here is considered CEST. 2. Ada.Calendar.Time_Zones.UTC_Offset propagates Time_Error when the argument is ambiguous, like: Time_Of – 02:30 CEST or CET? ( Year => 2008, Day => 26, Month => 10, Seconds => 2.5 * 3600.0 ); 3. The following package is introduced: package Ada.UTC is type Time is private; function Clock return Time; function "+" (Left : Time; Right : Duration) return Time; function "+" (Left : Duration; Right : Time) return Time; function "-" (Left : Time; Right : Duration) return Time; function "-" (Left : Time; Time : Time) return Duration; function "<" (Left, Right : Time) return Boolean; function "<="(Left, Right : Time) return Boolean; function ">" (Left, Right : Time) return Boolean; function ">="(Left, Right : Time) return Boolean; end Ada.UTC; The package provides UTC clock, time and operations on it. 4. The package Ada.Calendar.Time_Zones contains four new functions: 4.a. function UTC_Time_Offset (Date : Ada.UTC.Time := Ada.UTC.Clock) return Time_Offset; This function returns the difference between the political time and the UTC time for its argument. The function is well-defined for each its argument. 4.b. function To_Calendar_Time (Time : Ada.UTC.Time; Time_Zone : Time_Offset) return Time; This function returns Ada.Calendar.Time corresponding to the argument for the time zone offset defined by the parameter Time_Zone. 4.c. function To_UTC (Time : Ada.UTC.Time) return Time; This function is equivalent to: To_UTC (Time, UTC_Time_Offset (Time)); 4.d. function To_UTC (Time : Ada.UTC.Time; Time_Zone : Time_Offset) return Time; This function converts UTC time to the political time with the time offset specified by the parameter Time_Zone. 5. Implementation. Ada.Calendar.Time and Ada.UTC.Time can be implemented as the same type. In which case Ada.Calendar.Clock could be directly derived from Ada.UTC.Clock: function Ada.Calendar.Clock return Ada.Calendar.Time is T : Ada.UTC.Time := Ada.UTC.Clock; begin return Ada.Calendar.Time (T + Ada.Calendar.Time_Zones.UTC_Time_Offset (T)); end Ada.Calendar.Clock; !examples 1. Conversion to UTC time: T : Ada.Calendar.Time := Ada.Calendar.Time_Of – 02:30 CEST or CET ( Year => 2008, Day => 26, Month => 10, Seconds => 2.5 * 3600.0 ); T_CEST : Ada.UTC.Time := Ada.Calendar.Time_Zones.To_UTC (T, 60); T_CET : Ada.UTC.Time := Ada.Calendar.Time_Zones.To_UTC (T, 2*60); 2. Conversion from UTC. Assuming the declarations above: Ada.Calendar.Time_Zones.To_Calendar_Time (T_CEST) = T Ada.Calendar.Time_Zones.To_Calendar_Time (T_CET) = T 3. Composition of UTC time from year-month-day-seconds: Ada.Calendar.Time_Zones.To_UTC ( Ada.Calendar.Formatting.Time_Of ( Year => 2008, Day => 26, Month => 10, Seconds => 2.5 * 3600.0, Time_Offset => 0 ), Time_Offset => 0 ); 4. Splitting UTC time into year-month-day-seconds: Ada.Calendar.Formatting.Split ( Date => Ada.Calendar.Time_Zones.To_Calendar_Time (T, 0), Year => Year, Month => Month, Day => Day, Seconds => Seconds, Leap_Second => Leap_Second, Time_Zone => 0 ); **************************************************************** From: Pascal Leroy Date: Thursday, August 28, 2008 6:02 AM >1. Ada.Calendar.Time is defined as a political time. In the example: > T0, T1, T2 : Time; >begin > T0 := Time_Of -- 01:30 CEST > ( Year => 2008, > Day => 26, > Month => 10, > Seconds => 1.5 * 3600.0 > ); > T1 := T0 + 3600.0; -- +1h > T2 := T0 + 2.0 * 3600.0; -- +2h > >It is required T1 = T2. The time arithmetic is defined to satisfy this >requirement. Taken at face value, this statement doesn't make any sense. If T1 = T2 then presumably T1 + 3600.0 = T2 + 3600.0, but since T1 + 3600.0 is T2, then T2 = T2 + 3600.0. I don't think that you imply this, but then it would be good to present an implementation model for your proposal, since it seems to require that the time values "remember" how they were obtained. (And that seems fairly horrendous.) > In particular, if a difference is calculated between two times of which one > belongs to the overlapping hour, then this time is treated as having the > same UTC offset as another. For example: This doesn't help if both times belong to the overlapping hour. And it is not clear that this is what you want in the other cases anyway. It seems to me that you are just trying to infer a timezone that was never provided to Time_Of in the first place. You might guess right some of the time, but that's not better than the current state of affairs. The only sound way to address the issues you are mentioning would be to have variants of Time_Of et al. that take the designation of a timezone (not only a time offset) and keep track of all the time changes that take place in that timezone. That was rejected long ago, because it seems absurd to have the Ada runtime know about all this timezone stuff, which changes periodically anyway. This is especially true in an embedded environment, where no-one cares about timezones. **************************************************************** From: Dmitry A. Kazakov Date: Friday, August 29, 2008 4:16 AM ... > Taken at face value, this statement doesn't make any sense. If T1 = > T2 then presumably T1 + 3600.0 = T2 + 3600.0, but since T1 + 3600.0 is > T2, No, T1 + 3600.0 /= T2. You assumed associativity of "+", which does not hold for the political time. In general: (T + D1) + D2 /= T + (D1 + D2) This is the case when T = T0 and D1, D2 = 3600.0. > then T2 = T2 + 3600.0. T1 + 3600.0 = T2 + 3600.0 > I don't think that you imply this, but then it would be good to > present an implementation model for your proposal, since it seems to > require that the time values "remember" how they were obtained. (And > that seems fairly horrendous.) The semantics of Time + Duration is well-defined: A straightforward implementation of is: 1. Time is converted to UTC. This operation is unambiguous when Time is outside the overlapping hours. When Time is in such an hour, then for positive Duration Time is converted to the UTC after time skew. When Duration is negative it is converted to the UTC before it. 2. Duration is added 3. Result is converted back to the political time. This operation is always unambiguous. >> In particular, if a difference is calculated between two times of >> which one belongs to the overlapping hour, then this time is treated >> as having the same UTC offset as another. For example: > > This doesn't help if both times belong to the overlapping hour. In this case the difference is calculated directly considering the UTC offsets equal. > And it is > not clear that this is what you want in the other cases anyway. It > seems to me that you are just trying to infer a timezone that was > never provided to Time_Of in the first place. It is true that arithmetic of political time cannot be consistently defined without knowing the timezone. It should not surprise anyone. Political time is garbage. The problem is not in the timezone, it is whether the time zone offset should be derivable from the values of Time. My proposal (T1=T2) is that it should not. Yet, an implementation is free to choose UTC, internally and then mangle +, -, =, in accordance to the "political will" (:-))... > The only sound way to address the issues you are mentioning would be > to have variants of Time_Of et al. that take the designation of a > timezone (not only a time offset) and keep track of all the time > changes that take place in that timezone. That would not define the semantics of Time. My proposal does it, by defining the political time in terms of UTC. This is how the political time is defined in the real world. > That was rejected long ago, because it seems absurd to have the Ada > runtime know about all this timezone stuff, which changes periodically > anyway. This is especially true in an embedded environment, where > no-one cares about timezones. Right, my proposal provides a way to define Time on the platform where UTC is unavailable. On these Time_Offset is considered constant 0. **************************************************************** From: Jeffery R. Carter Date: Sunday, February 15, 2009 10:03 PM I have to disagree with the proposal to add political time information to Ada.Calendar. It would break a great deal of my company's code because it is not backwards compatible. Ada.Calendar knows nothing of time zones, political time, or daylight savings time. This is clear from its definition in the ARM, from Ada 83 through Ada 95 and on to the current standard. A possible representation of type Time could be simply a record of the 4 components. Time_Of checks that the day is legal for the year and month, and handles the case of the seconds being Day_Duration'Last, but that is all. Split simply returns the 4 components. Whether the resulting time is meaningful in any specific political entity is unknown to the package. Clock returns some "system time", probably external to the language. This system time may know about some political entity and jump forward or backward, as the ARM specifically allows. In the case where the "system time" jumps backwards, Clock may return the same value twice. The meaning of those values is not something that Calendar does or can know about. The new packages added in 9.6.1 know about the system clock's UTC offset, and how to convert times from a given offset to and from the system clock's offset, but those offsets have no meaning relating to political time. How could they when arbitrary offsets with no political meaning may be specified? For example, the various Time_Of functions treat the time as having the specified offset and return the Time value for the time converted to the system clock's offset (a time of 12:00:00.00 with Time_Zone => 0 and UTC_Time_Offset = -420 [MST, -0700] would give a time of 05:00:00.00). The various Split procedures with Time_Zone parameters treat the Date as having the system clock's offset, and return the components of the Date converted to the specified offset. (Calling the parameter Time_Zone seems a bit misleading, since "time zone" usually refers to a political concept, and the parameter is really an arbitrary offset unrelated to any such concept.) If we want to have operations that know about political time in various political entities and their offsets, then we really need to deal with time zones specified as strings (since this is a malleable definition and cannot be represented by arbitrary numeric values or an enumeration type), such as "US/Mountain" and "Europe/Dublin". Clearly such operations do not belong in the existing packages. **************************************************************** From: Tucker Taft Date: Thursday, May 20, 2010 6:06 PM On our phone call today, we had a somewhat mind-bending discussion of calendar, time zones, and daylight-savings/summer time. We recognized that there are two distinct strategies for representing Calendar.Time, one where the time is kept in UTC internally, and Calendar.Split and Calendar.Time_Of worry about the "local" time zone. The other is that Time is represented in local time, and Calendar.Time_Of and Calendar.Split are trivial. Here are some interesting questions: What does "-"(Time, Time) return for times that cross a daylight/summer timezone change? Clearly if Time is represented internally as UTC time, this is very straightforward. If Time is represented as a local time that reflects daylight-savings/summer time, but with no internal bit indicating whether daylight/summer time was in effect when the local time was stored, then it seems clear that "-" will necessarily return a value of Duration that corresponds to 3600.0 seconds more or 3600.0 seconds less than the actual number of seconds that pass between the two times. This seems highly undesirable. This leads me to suggest that for an implementation that stores local time, during a single execution of an Ada program, all times should use the same time zone, even if daylight/summer time begins or ends during the execution. This also means that UTC_Time_Offset should return the same value independent of the Date parameter, reflecting the time zone at the moment when program execution began. This means that Clock will have to undo the effects of any change in daylight savings/summer time since the program execution began, if the underlying O/S reflects the change immediately. Similarly Split and Time_Of will presume the program-start timezone, even if they represent times when the timezone would be different due to daylight/summer time. Alternatively, if Calendar.Time is represented as UTC time, then it would be feasible for UTC_Time_Offset to give different values depending on the Date parameter, and for Calendar.Time_Of and Calendar.Split to reflect the different UTC_Time_Offset based on the Time value represented by the parameters. However, Time_Of would be ambiguous for 2AM-3AM on the day daylight/summer time ends, and the implementation would need to pick one or the other. To be consistent with the implementations using local time, we would want to specify that when ambiguous, a UTC_Time_Offset is used by Time_Of that corresponds to its value when program execution began. Of course even more consistent would be to have both implementation approaches always presume the time zone when program execution begins, and have UTC_Time_Offset always return the same value, independent of the Date parameter. However, that seems to fly in the face of the description of UTC_Time_Offset. The other solution is to effectively require implementations to use UTC time internally, or at least an indication of whether a given "local" time is or is not a daylight/summer time, so that "-", "<", Difference, etc., can properly reflect the true difference in time. This would then allow UTC_Time_Offset to depend on the Date parameter, as implied by it RM definition. Uggh... **************************************************************** From: Randy Brukardt Date: Thursday, May 20, 2010 6:39 PM ... > If Time is represented as a local time that reflects > daylight-savings/summer time, but with no internal bit indicating > whether daylight/summer time was in effect when the local time was > stored, then it seems clear that "-" will necessarily return a value > of Duration that corresponds to 3600.0 seconds more or 3600.0 seconds > less than the actual number of seconds that pass between the two > times. > This seems highly undesirable. Nevertheless, it's been the case in at least some Ada implementations for decades. (It causes interesting effects in long-running programs that happen to running when the time zone changes. For example, the heartbeat monitor on our webserver fails each March because it waits 61 minutes (instead of 1 minute) to send the heartbeat signal to the hardware -- so the hardware monitor assumes the computer failed and does a reboot. Didn't see worth fixing.) We could try to adopt rules to change that, but they would be inconsistent with actual practice on Windows. > This leads me to suggest that for an implementation that stores local > time, during a single execution of an Ada program, all times should > use the same time zone, even if daylight/summer time begins or ends > during the execution. > This also means that UTC_Time_Offset should return the same value > independent of the Date parameter, reflecting the time zone at the > moment when program execution began. This means that Clock will have > to undo the effects of any change in daylight savings/summer time > since the program execution began, if the underlying O/S reflects the > change immediately. > Similarly Split and Time_Of will presume the program-start timezone, > even if they represent times when the timezone would be different due > to daylight/summer time. That sounds fine, except that it isn't implementable on Windows. Windows has two time functions: GetSystemTime (which is UTC time) and GetLocalTime (which gets the current local time). To do this, you would have to use the System (UTC) time and do conversions after the fact -- at which point you might was well abandon the entire local time model. It also should be noted that the time zone model isn't even supported on Windows 95/98/ME, which is one reason that we never considered using it. (While you can retrieve the current time zone on Windows 95/98/ME, the conversion from SystemTime (UTC) to a specific local time is missing.) This isn't a big deal anymore, although I would still continue to support at least Windows 98 (because my home computer is still Windows 98 and there is no reason to update a computer that doesn't connect to the Internet, especially as that would require replacing my bookkeeping and database software - and I still want to use Ada at home). > Alternatively, if Calendar.Time is represented as UTC time, then it > would be feasible for UTC_Time_Offset to give different values > depending on the Date parameter, and for Calendar.Time_Of and > Calendar.Split to reflect the different UTC_Time_Offset based on the > Time value represented by the parameters. However, Time_Of would be > ambiguous for 2AM-3AM on the day daylight/summer time ends, and the > implementation would need to pick one or the other. To be consistent > with the implementations using local time, we would want to specify > that when ambiguous, a UTC_Time_Offset is used by Time_Of that > corresponds to its value when program execution began. Sounds painful, as you would have to remember whether or not daylight savings was active when the program started. For something that happens once per year, I'd probably suggest just requiring one or the other results. > Of course even more consistent would be to have both implementation > approaches always presume the time zone when program execution begins, > and have UTC_Time_Offset always return the same value, independent of > the Date parameter. > However, that seems to fly in the face of the description of > UTC_Time_Offset. It also would be inconsistent with current practice on Windows (at least). You have to work hard on Windows to avoid reflecting the daylight saving change immediately, and I don't think anyone does that. (Use Ada.Real_Time for delays!) > The other solution is to effectively require implementations to use > UTC time internally, or at least an indication of whether a given > "local" time is or is not a daylight/summer time, so that "-", "<", > Difference, etc., can properly reflect the true difference in time. > This would then allow UTC_Time_Offset to depend on the Date parameter, > as implied by it RM definition. I think this is what is required, as your other schemes end up working this way on Windows anyway. So why bother defining them? But note that this is definitely inconsistent with current practice on Windows. The change is not a big deal (probably would fix more bugs than it causes), but clearly more than a pure BI (that is, this is something that I would prefer to be clearly different between Ada 2005 and Ada 2012 so that implementations can determine where to put the pain for their customers). > Uggh... Well, now you have a better appreciation of why I've been frustrated talking to you (and others) on this topic. **************************************************************** From: Tucker Taft Date: Thursday, May 20, 2010 8:32 PM So it sounds like you agree we should require "Calendar.Time" to preserve enough information so that UTC_Time_Offset can be computed properly, by, for example, having a bit indicating whether or not the value corresponds to daylight/summer time. Or by using UTC time internally. **************************************************************** From: Bob Duff Date: Thursday, May 20, 2010 8:36 PM > On our phone call today, we had a somewhat mind-bending discussion of > calendar, time zones, and daylight-savings/summer time. Mind-bending indeed. The concept of "time" seems simple on the surface, but it is surprisingly complicated! I don't get it. > We recognized that there are two > distinct strategies for representing > Calendar.Time, one where the time is kept in UTC internally, and > Calendar.Split and Calendar.Time_Of worry about the "local" > time zone. The other is that Time is represented in local time, and > Calendar.Time_Of and Calendar.Split are trivial. I think you're mixing up two things: - An implementation might represent Time in UTC, or in local time. - An implementation might represent Time as an integer number of zilliseconds(*) since some epoch, or as a record containing something like (year, month, day, hour, minute, second). But anyway, I think this is all a tempest in a teapot. Hard real-time systems that really care about time don't go around changing the system clock to match whatever some politicians say is the local political time. And those are the kind of systems that really care that X - Y gives exactly 3600.0 for that strange hour during the daylight "savings" transition. Think about a GPS system, which cares about speed-of-light transmissions from some satellites to some earth-bound devices. Those folks aren't going to mess around with political time -- they're going to use some stable standard, like UTC. I'll bet that satellite doesn't have any TIMEZONE or DAYLIGHT_SAVINGS environment variables on it, being modified willy-nilly by the sysadmins or the operating system! (*) zillisecond = zillionth of a second. Could be a nanosecond or a picosecond, or whatever. Some small fraction of a second. And "integer number of zilliseconds" is the same as a fixed-point number of seconds, with 'Small = 1 zillisecond. E.g. Duration. **************************************************************** From: Randy Brukardt Date: Thursday, May 20, 2010 9:00 PM Well, GPS uses its own time which is subtly wrong (it doesn't use leap seconds). But whatever. The point here is that we all agree with your point. There are a lot of systems that can't (or shouldn't) use local time and need access to a stable timebase like UTC time. The whole idea behind adding UTC_Offset was to provide *within Ada* a *portable* way to access the stable UTC time (since the popular systems all maintain a version of UTC time). And the problem here is that solution *does not work* in some corner cases. Now, clearly there are going to be some very hard real-time applications that will need their own custom timebase (GPS seems to be a good example). But this Ada solution is intended for the middle ground of applications that need reliable access to UTC time to the accuracy provided by the host system (for Windows and Unix that can be pretty good, as both systems can be hooked up to use NTP to sync their time), but don't want to hack around with local time and daylight savings time. One example is my web server, which is supposed to use UTC time in its timestamps - this isn't too critical, but I'd like a portable way to get it right. Unless you are saying that no application should ever use the host system version of UTC time, or anyone whose system ever runs an Ada program should have their system timezone set to UTC time, we need to fix this problem. Or don't you care about portable solutions any more?? P.S. There aren't any TIMEZONE or DAYLIGHT_SAVINGS environment variables on my system either. :-) Doesn't mean anything; there is a TZ record that can be queried with a function, and surely the local time depends on it. **************************************************************** From: Randy Brukardt Date: Thursday, May 20, 2010 9:02 PM > So it sounds like you agree we should > require "Calendar.Time" to preserve enough information so that > UTC_Time_Offset can be computed properly, by, for example, having a > bit indicating whether or not the value corresponds to daylight/summer > time. > > Or by using UTC time internally. Right. That's what I said during the call, that's what it says in the minutes that I have an action item to try to do, and that's what my research into Windows system calls after the call shows is the best plan. **************************************************************** !topic Clarification of UTC_Time_Offset !reference 9.6.1(42) !from Adam Beneschan 10-06-29 !discussion I don't know if this should be added to AI05-119, or if this a simple enough editorial comment to just go ahead and fix it now... 9.6.1(42) says UTC_Time_Offset "Returns ... the difference between the implementation-defined time zone of Calendar, and UTC time". To me, the English phrase "the difference between" is somewhat ambiguous as to the sign of the "difference". May I suggest that a phrase like "This value is negative for time zones west of Greenwich, and positive for time zones east of Greenwich, when daylight savings time is not involved", or the reverse if that's what is really intended, be added? Or something to that effect? Perhaps the sign is obvious to people who have worked a lot with Internet or Unix standards or the like, but I have a feeling someone will get tripped up by it. **************************************************************** From: Dmitry A. Kazakov Date: Wednesday, June 30, 2010 9:34 PM It is unambiguous, provided "difference" means "-". The offset is exactly Local_Time - UTC. There is though a problem that the result does not tell if this difference is now "regular" or else of the daylight saving time. With the meaning "difference" is "-", UTC_Time_Offset depends on the current time. An alternative meaning could be the "regular", standard offset independent on the current time. E.g. GMT+02:00 In both cases daylight saving time active flag is necessary to have UTC_Time_Offset useful. Even more important is a clear statement on whether Ada.Calendar.Time is a local political time (i.e. suffering large forward and backward jumps) or else an UTC + constant offset time. **************************************************************** From: Randy Brukardt Date: Wednesday, June 30, 2010 10:41 PM It's surely true in all existing versions of Ada that Ada.Calendar.Time is subject to jumps. That was decided early for Ada 83: see AI83-00195 (http://archive.adaic.com/standards/83com/ai-00195-ra.wj). Note that this AI was considered a "Ramification". Nothing in Ada 95 or Ada 2005 changed that interpretation. It's not clear that anything *can* change that; if the operator manually changes the system time (including when a correction is applied automatically to resync the time with a time-base), most Ada implementations will immediately reflect that change. To avoid that, Ada implementations would have to maintain their own clock, which seems way out of bounds (and actively harmful on systems where the time is resynced to a supposedly more accurate time-base). The more interesting question is whether Ada 2012 will require that Ada.Calendar.Time include enough information to recover the UTC time from a value produced by Ada.Calendar.Clock. We believe that is enough to be able to reliably recover the UTC time (a variety of wording changes will be needed, which I am supposed to be working out in my copious spare time). It appears impossible to completely fix this problem for values produced from Time_Of, since there is never a way to know which of the two values is intended during the "ambiguous time". That is generally only one hour per year, so it probably not a serious problem. **************************************************************** From: Adam Beneschan Date: Thursday, July 1, 2010 10:05 AM > It is unambiguous, provided "difference" means "-". The offset is > exactly Local_Time - UTC. (1) My main point is that I don't think "difference" (and in particular the phrase "difference between") means "-" in English. I mean, it does, but not in a consistent way. When I talk about the difference between A and B, I could mean A-B, B-A, or abs(A-B), and I don't think it's clear without context. (Suppose someone were to ask me, referring to my two sons, "What's the height difference between Mike and Steve", or "What's the height difference between Steve and Mike"? I guarantee you I will give the same answer to both questions---"about 3 inches"; I will not answer "three inches" to one question and "negative three inches" to the other.) I'm talking about normal English usage; if there were a standard mathematical usage, that usage would take precedence, but I don't think there is one and I don't believe mathematicians normally use this sort of phrasing. In any event, I don't think it's obvious, and can envision someone interpreting this wording to mean "the amount that must be added to time in the implementation-defined time zone of Calendar to get the UTC time", which would be a value of the opposite sign. (2) Another reason I don't think your point is quite sufficient: even if difference means "-", then the wording of 9.6.1(42) means (The implementation-defined time zone of Calendar) - (UTC time). Unless there's some other definition I'm unaware of, a time zone is not a number, but is ... well I don't know, a geographical subset of the Earth's surface area? This is a less important point, I suppose, because if the meaning of "difference between" were clear, I think it would be clear what is meant here even though the wording is slightly sloppy. Anyway, I realize that there are issues about daylight saving time (AI05-119), but this question of mine is independent of that issue. **************************************************************** From: Adam Beneschan Date: Thursday, July 1, 2010 10:29 AM > It appears impossible to completely fix this problem for values > produced from Time_Of, since there is never a way to know which of the > two values is intended during the "ambiguous time". That is generally > only one hour per year, so it probably not a serious problem. I've been wondering whether Time_Of needs to be aware that the U.S. laws about when Daylight Savings Time starts and ends changed in 2007---or whether programs running in parts of Indiana need to be aware that there was no DST before 2007 and there is now---or whether Time_Of on a computer running in Moscow needs to be aware that dates before 1918 are 13 days off? OK, I'm joking about that last (I think it was resolved by AI95-351) but to what extent does Time_Of need to know about the history of DST regulation changes? Or is this just covered by 9.6(24)'s statement that "time zone" is implementation-defined, which means that implementations can do whatever they want (i.e. either take historical changes into account or ignore them as they choose)? I'm guessing that the latter is the case---is that correct? **************************************************************** From: Randy Brukardt Date: Thursday, July 1, 2010 10:29 AM The practical answer is "whatever the host system does". There is no intent that Ada runtimes need to do their own time-zone manipulations, and thus whether or not Time_Of can do historical calculations depends solely on what the OS provides. (For Windows, Indiana was (is?) a separate time zone, so that sort of issue depends on whether or not the Indiana resident set their computer to use it. I hope the Ada standard isn't going to start telling people how to set their timezone settings!) Note that it doesn't matter if all that is done with the Time_Of value is to Split it later in the same (default) timezone: you'll have to get the same answers. The issue only comes up when you start using other timezones to extract values. It doesn't appear that anything portable can be mandated there. OTOH, values derived from Clock, we probably can mandate that that UTC can be reliably determined (since the timezone is known when the value is created, and there is no historical concerns). But Time_Of is always going to be a guess at best. **************************************************************** From: Dmitry A.. Kazakov Date: Thursday, July 1, 2010 11:46 AM > It's surely true in all existing versions of Ada that > Ada.Calendar.Time is subject to jumps. That was decided early for Ada > 83: see AI83-00195 > (http://archive.adaic.com/standards/83com/ai-00195-ra.wj). Note that > this AI was considered a "Ramification". Nothing in Ada 95 or Ada 2005 > changed that interpretation. It's not clear that anything *can* change > that; if the operator manually changes the system time (including when > a correction is applied automatically to resync the time with a time-base), most Ada implementations will immediately reflect that change. I think that this is an independent issue. The source of clock whether it be machine's quartz or a user chaotically setting the system time is of no matter to Ada. It is given. There is no other source, we don't care how reliable it is. The actual problem is the semantics of how this source is treated within Ada. I see no other way than to treat it as UTC (or astronomical time, or similar). Political time requires too much overhead to implement. By this I mean precisely the following: declare T : Time := Clock; begin delay 60.0 * 10.0; Put_Line (Boolean'Image (Clock > T)); when executed at 31. Oct 2010, 2:59, a computer located in Central Europe shall print "FALSE." Is there any Ada compiler, which indeed implements this broken semantics? Does RM mandate this idiocy? Note, this unrelated to how Split and Time_Of are supposed to work. They can continue to use political time, no problem with that, if Ada.Calendar.Time meant to be UTC. If that were accepted, then the only addition needed would be a package with Split_Into_UTC and UTC_Of in it. **************************************************************** From: Randy Brukardt Date: Thursday, July 1, 2010 5:52 PM > I think that this is an independent issue. The source of clock whether > it be machine's quartz or a user chaotically setting the system time > is of no matter to Ada. It is given. > There is no other source, we don't care how reliable it is. It's not at all an independent issue. You seem to be saying that the *reason* for a time jump is significant. But that makes no sense. Back in the days of MS-DOS, the way time zone changes were reflected was the same as in your wall clock: you changed the time twice a year. Saying that changing the time to reflect the time zone manually is somehow different than doing it automatically makes no sense. Similarly, whether the jumps occur "automatically" or "manually" is irrelevant. If your system is connected to a time base via NTP, it probably automatically adjusts the time periodically. How is this different (especially in terms of the Standard) than the automatic change that occurs when Daylight Savings Time changes? There is no practical difference. > The actual problem is the semantics of how this source is treated > within Ada. I see no other way than to treat it as UTC (or > astronomical time, or similar). That makes no sense as well. There is no requirement for an OS to even have a way to get UTC time or turn off automatic adjustments, and even if there is, Ada programs are likely to run on systems with those settings wrong. > Political time requires too much overhead to implement. By this I mean > precisely the following: > > declare > T : Time := Clock; > begin > delay 60.0 * 10.0; > Put_Line (Boolean'Image (Clock > T)); > > when executed at 31. Oct 2010, 2:59, a computer located in Central > Europe shall print "FALSE." No, this is clearly "implementation-defined". In fact, it ought to be "unspecified", in that it isn't even that practical to explain when the answer might be counter-intuitive. I have no idea when NTP is used to reset the time on my Windows systems, for instance, only that I set it up to do so. So I can't even "document" when the time might change, other than the useless advice that it will happen any time the system's clock is changed. (Duh!) If you want an monotonically-increasing time source, you need to use Ada.Real_Time. There can be no guarantees with Calendar. > Is there any Ada compiler, which indeed implements this broken > semantics? 9.6(40.c) points out that Ada 83 pretty much required a direct mapping of Clock to the results of Split. I suspect that virtually all Ada 83 compilers had this "feature" (it's not a bug, as it is expected behavior). Compilers that haven't changed their implementations much from the Ada 83 ones (in order to keep upward compatibility) probably have the behavior. The IBM Rational compiler followed an Ada 83-style model back when we were discussing this the last time, and it probably still does. And I know Janus/Ada follows this model. Indeed, the heartbeat monitor that monitors our web server machine fails every November (as it waits 61 minutes instead of 1 minute). That's not worth fixing, given that the effect is to reboot the machine for no important reason once per year. > Does RM mandate this idiocy? Note, this unrelated to how Split and > Time_Of are supposed to work. They can continue to use political time, > no problem with that, if Ada.Calendar.Time meant to be UTC. If that > were accepted, then the only addition needed would be a package with > Split_Into_UTC and UTC_Of in it. This would be a royal pain on Windows. The basic Win32 time functions only provide a means to retrieve "local time" and "system time" (the latter is essentially UTC). There is no mechanism to convert one to the other. You can get the local time zone information and try to figure it out, but that is complex and error-prone. There are some newer APIs that would help, but they would mean that no Ada code could not run on older versions of Windows. Calendar is present in every Ada program, so anything it requires is required of all programs (unlike, say CPU affinities or CPU timing, which are only present if you use them). While it makes sense to only support Ada development tools on recent systems, it doesn't make sense to have such requirements on generated programs (there are a lot of perfectly useful old computers out there). Also, you are requiring a complete re-implementation of Ada.Calendar. That clearly will have other effects: files are no longer binary-compatible (the reason the year range was changed the way it was was so that could be maintained between Ada 95 and Ada 2005), indeed, Ada.Calendar.Time will be larger (it will have to include time zone information), which will break representation clauses. So, even if such a change is mandated, it would have to be only for Ada 2012; older versions will remain as they are. Personally, the only thing I care about is the ability to reliably get UTC time from Ada.Calendar.Clock. It doesn't make sense to complain about comparisons in this one case when there are many other cases that happen just as often that will not have an guaranteed result. (Without a guarantee for monotonically increasing time, like the one in Ada.Real_Time, you are always building on a house of sand.) Moreover, I don't recall any user that ever has complained about the comparisons of Ada.Calendar, and changing it would be a substantial expense. Use Ada.Real_Time if this is critical. Period. **************************************************************** From: Dmitry A. Kazakov Date: Friday, July 2, 2010 3:28 AM > It's not at all an independent issue. You seem to be saying that the > *reason* for a time jump is significant. But that makes no sense. Back > in the days of MS-DOS, the way time zone changes were reflected was > the same as in your wall clock: you changed the time twice a year. > Saying that changing the time to reflect the time zone manually is > somehow different than doing it automatically makes no sense. Surely it does. The question is the model of clock Ada implementation represents. The mandated one seem to be: Ideal-UTC-clock + [noise' +] Political skew + noise -> Ada.Calendar.Time The proper one, must be Ideal-UTC-clock + noise -> Ada.Calendar.Time Your argument seems to be that because *some* noise is always added, then it is no matter whether it be just noise or Political skew + noise. That is wrong, because in reality the statistical behavior of the noise and Political skew are greatly different in all aspects. > Similarly, whether the jumps occur "automatically" or "manually" is > irrelevant. If your system is connected to a time base via NTP, it > probably automatically adjusts the time periodically. How is this > different (especially in terms of the Standard) than the automatic > change that occurs when Daylight Savings Time changes? There is no practical difference. The practical difference is that NTP adjustments are small and well distributed. Adding the Political skew upon them changes everything. >> The actual problem is the semantics of how this source is treated >> within Ada. I see no other way than to treat it as UTC (or >> astronomical time, or similar). > > That makes no sense as well. See the models above. ... > No, this is clearly "implementation-defined". In fact, it ought to be > "unspecified", in that it isn't even that practical to explain when > the answer might be counter-intuitive. I have no idea when NTP is used > to reset the time on my Windows systems, for instance, only that I set > it up to do so. So I can't even "document" when the time might change, > other than the useless advice that it will happen any time the system's clock is changed. > (Duh!) No NTP client would do 10 minutes adjustments. It makes no sense to consider totally malfunctioning installation, like if you smashed the onboard quartz with the hammer. > If you want an monotonically-increasing time source, you need to use > Ada.Real_Time. There can be no guarantees with Calendar. That is impossible, because Ada.Real_Time.Time is not a real time in the sense, that it is not linked to a reliable external [real] time source. As such it is unusable for most networking/distributed/real-time applications. > And I know Janus/Ada follows this model. Indeed, the heartbeat monitor > that monitors our web server machine fails every November (as it waits > 61 minutes instead of 1 minute). That's not worth fixing, given that > the effect is to reboot the machine for no important reason once per year. I better leave that uncommented. (:-)) >> Does RM mandate this idiocy? Note, this unrelated to how Split and >> Time_Of are supposed to work. They can continue to use political >> time, no problem with that, if Ada.Calendar.Time meant to be UTC. If >> that were accepted, then the only addition needed would be a package >> with Split_Into_UTC and UTC_Of in it. > > This would be a royal pain on Windows. The basic Win32 time functions > only provide a means to retrieve "local time" and "system time" (the > latter is essentially UTC). There is no mechanism to convert one to > the other. You can get the local time zone information and try to > figure it out, but that is complex and error-prone. I see no problem. GetSystemTime and GetSystemTimeAsFileTime do the job. The actual problem under Windows and many other OSes is an awful clock accuracy (even when GetSystemTimeAsFileTime is used, FILETIME was 100ns resolution). I suppose this is because Windows does not use the high-resolution CPU clock. So if you want to get a decent implementation of Clock under Windows, you have to use performance counters instead and periodically synchronize them with the readings of GetSystemTime in a background task. But all this has no connection to political vs physical time controversy. However, considering modern CPUs, I think it is time advise Ada compilers to use CPU clocks (ns resolution) as one of the time sources. > Also, you are requiring a complete re-implementation of Ada.Calendar. They must be, because the standard is broken. Once fixed, it will inevitably break some existing implementations. **************************************************************** From: Randy Brukardt Date: Friday, July 2, 2010 5:03 PM > Sent: Saturday, July 03, 2010 3:28 AM Speaking of time issues, your computer is sending messages a day ahead of time. We received this message at about 8:30 UTC on Friday. If we were running Spam Assassin here, we would never have seen it (SA treats messages dated in the future as almost certain spam). I hope you're not using an Ada program for sending mail... > Your argument seems to be that because *some* noise is always added, > then it is no matter whether it be just noise or Political skew + > noise. That is wrong, because in reality the statistical behavior of > the noise and Political skew are greatly different in all aspects. But you are claiming that there is some difference between "Political skew" as added by a computer operating system and that added by the end user. I don't see this difference. I have known a number of people who reset the times on their Windows machines by hand twice a year. (I even have to do that on some of the dual-boot systems here.) On such systems, any information about "political skew" is going to be completely wrong. (Similarly, a heck of a lot of Windows 98 and Windows 2000 computers have the old time zone information for the US and change the time on the wrong days. People using such old computers will manually correct the time 4 times a year.) And I also don't see any difference between the automatic changes made by time zone information and the automatic changes made by NTP clock resets (or for that matter, because of clock drift, see below). > > Similarly, whether the jumps occur "automatically" or "manually" is > > irrelevant. If your system is connected to a time base via NTP, it > > probably automatically adjusts the time periodically. How is this > > different (especially in terms of the Standard) than the automatic > > change that occurs when Daylight Savings Time changes? > There is no practical difference. > > The practical difference is that NTP adjustments are small and well > distributed. Adding the Political skew upon them changes everything. This is clearly not true, at least on Windows systems, because of the use of the high-performance counter. See below. > >> The actual problem is the semantics of how this source is treated > >> within Ada. I see no other way than to treat it as UTC (or > >> astronomical time, or similar). > > > > That makes no sense as well. > > See the models above. It still doesn't make any sense, especially from a Standards perspective. You want the language to ban using one particular reason for time jumps while allowing all others, even though the others cause more damage to running programs (as they aren't predictable in time nor size). That is impossible to do, especially when there is no way to separate such changes from any other (given that manual changes may be used to effect daylight savings changes). ... > No NTP client would do 10 minutes adjustments. It makes no sense to > consider totally malfunctioning installation, like if you smashed the > onboard quartz with the hammer. Actually, the implementation that you want for Windows essentially requires that (see below). > > If you want an monotonically-increasing time source, you need to use > > Ada.Real_Time. There can be no guarantees with Calendar. > > That is impossible, because Ada.Real_Time.Time is not a real time in > the sense, that it is not linked to a reliable external [real] time > source. As such it is unusable for most > networking/distributed/real-time applications. If you need true external time, you need to get it from a true external source. No computer time is accurate enough for that, and certainly Ada.Calendar.Time is not intended for that purpose. When I was a student, I learned that time is *never* the same on two different computers, and it should *never* be used in a communication algorithm. If it is used at all, it should be in an advisory/debugging function. And indeed, that is how it is used in protocols like SMTP and HTTP -- the time is passed, but it doesn't really matter. (Case in point, the message I'm replying to whose clock is a day off. If the time was really significant, it couldn't have been delivered.) Ada.Calendar is good enough for that. Perhaps there are situations that do really need careful time information, but those are clearly not those that computer clocks and Ada.Calendar are intended for. I'd suggest using an NTP library for that purpose. > > And I know Janus/Ada follows this model. Indeed, the heartbeat > > monitor that monitors our web server machine fails every November > > (as it waits > > 61 minutes instead of 1 minute). That's not worth fixing, given that > > the effect is to reboot the machine for no important reason once per year. > > I better leave that uncommented. (:-)) Two weeks work to fix one glitch per year makes no sense. It's the same reason that I stopped doing updates to my spam filter -- the 5-10 extra messages that would be blocked take only a couple of minutes per day to process and discard -- spending two weeks or more of work time to save 2 minutes per day would be senseless. ... > > This would be a royal pain on Windows. The basic Win32 time > > functions only provide a means to retrieve "local time" and "system > > time" (the latter is essentially UTC). There is no mechanism to > > convert one to the other. You can get the local time zone > > information and try to figure it out, but that is complex and error-prone. > > I see no problem. GetSystemTime and GetSystemTimeAsFileTime do the > job. My point is that there is no sane way to get the local time from the SystemTime. Your claim that Split without a time zone parameter should still work as it does currently implies that is possible and necessary (since it has to return the local time, not the system time). ... > However, considering modern CPUs, I think it is time advise Ada > compilers to use CPU clocks (ns resolution) as one of the time > sources. I don't think this can be done in the Standard, as this is a quality of implementation problem. Moreover, I doubt that most readers of Implementation Advice would have a clue what "CPU clocks" means. We can't mention specific operating systems in IA. Moreover, I don't think there is any Linux/Unix counterpart to the performance counter of Windows, so I don't think there is a way to even do this on those systems. In any case, all of the Windows implementations that we tested for Claw used the performance counter except for the Rational compiler (and the Windows version of the Rational compiler no longer exists anyway - even if you had a copy, the license keys wouldn't work and it wouldn't run). Note that using the performance counter has the effect of causing large jumps at random intervals. The way the Janus/Ada implementation works is that we "base" the performance counter with the local time at start up. When clock is called, we use the base plus the performance counter in order to produce the result time. However, if that result differs more than 5 minutes from the local time as returned from the OS, we then "rebase" the clock and return the local time instead. We do this so that clock drift, NTP adjustments, manual adjustments, and daylight saving time changes are all reflected in the result time. This is important for long running programs - Ada.Calendar needs to reflect the correct (as seen by the computer) time. The net effect of this means that there will be random jumps of at least 5 minutes periodically for a long running program. (We do have a minimum time between checks for rebasing, in order to improve the performance of Ada.Calendar.Clock. So programs that only run a few minutes - like ACATS tests - will never see a rebasing.) Obviously, the 5 minute number is arbitrary. It could be more or less, but you have to have such a number. If you rebased always, of course the effect would be to ignore the performance counter completely. If you never rebased, long-running programs like our web server (which is intended to run months at a time) would never get the effect of NTP clock settings and also could get far away from the actual time. Our experiments on Windows 98 and Windows 2000 systems back when this was implemented showed that clock drift was a serious problem; we saw machines where rebasing happened ever few hours as the local time and the performance counters drifted apart rapidly. Not sure if more modern machines are any better in this respect, but I would guess not (and NTP clock resets could make the problem even more severe). The rules you are suggesting would make it impossible to use the performance counter, as programs that run more than a few hours have to be able to rebase the clock. But that rebasing would by definition violate the model that you set out. Wording to require the model that you want would almost certainly make rebasing wrong as well -- which would be very bad. > > Also, you are requiring a complete re-implementation of Ada.Calendar. > > They must be, because the standard is broken. Once fixed, it will > inevitably break some existing implementations. OK, but then it is necessary to consider the impact on customers. For instance, if rebasing of times is banned, then long-running applications cannot depend on Ada.Calendar to retrieve local or UTC time. (The time could drift too far away to be meaningful - I have a temperature gauge that includes a clock that I never change - it has drifted 40 minutes away from the correct time in just over a year of operation. Most computer clocks are about that accurate in the long haul -- that's why we have NTP.) In any case, this discussion with you has been very enlightening. I was in fact in favor of some sort of fix to allow retrieving of UTC time reliably. But this discussion has convinced me that that is a fool's game - it is impossible to make a meaningful requirement that also does not prevent important implementation strategies. As such, I don't plan to waste time attempting to write language to mandate anything, and will recommend No Action on AI05-0119-1. **************************************************************** From: Dmitry A. Kazakov Date: Saturday, July 3, 2010 4L57 AM > Speaking of time issues, your computer is sending messages a day ahead > of time. We received this message at about 8:30 UTC on Friday. It happens sporadically, I don't know why and when. > ... >>> It's not at all an independent issue. You seem to be saying that the >>> *reason* for a time jump is significant. But that makes no sense. >>> Back in the days of MS-DOS, the way time zone changes were reflected >>> was the same as in your wall clock: you changed the time twice a year. >>> Saying that changing the time to reflect the time zone manually is >>> somehow different than doing it automatically makes no sense. >> >> Surely it does. The question is the model of clock Ada implementation >> represents. The mandated one seem to be: >> >> Ideal-UTC-clock + [noise' +] Political skew + noise -> >> Ada.Calendar.Time >> >> The proper one, must be >> >> Ideal-UTC-clock + noise -> Ada.Calendar.Time >> >> Your argument seems to be that because *some* noise is always added, >> then it is no matter whether it be just noise or Political skew + >> noise. That is wrong, because in reality the statistical behavior of >> the noise and Political skew are greatly different in all aspects. > > But you are claiming that there is some difference between "Political skew" > as added by a computer operating system and that added by the end user. Certainly yes. The end user is responsible for setting the clock. Whatever he does this is *the* UTC source the program must deal with. Political skew per definition and intent is a *different* time. > And I also don't see any difference between the automatic changes made > by time zone information and the automatic changes made by NTP clock > resets (or for that matter, because of clock drift, see below). As above, these are different times, apples and oranges. ... >>> That makes no sense as well. >> >> See the models above. > > It still doesn't make any sense, especially from a Standards perspective. > You want the language to ban using one particular reason for time > jumps while allowing all others, even though the others cause more > damage to running programs (as they aren't predictable in time nor size). Not at all. What I want is time to be defined in terms of UTC. If you want to keep it political you must either throw away time arithmetic because it is inconsistent. Note that any alternative, like to add some fields to Time object in order to fix arithmetic, would mean making it UTC. ... > If you need true external time, you need to get it from a true > external source. No computer time is accurate enough for that, and > certainly Ada.Calendar.Time is not intended for that purpose. > > When I was a student, I learned that time is *never* the same on two > different computers, and it should *never* be used in a communication > algorithm. If it is used at all, it should be in an advisory/debugging > function. And indeed, that is how it is used in protocols like SMTP > and HTTP > -- the time is passed, but it doesn't really matter. (Case in point, > the message I'm replying to whose clock is a day off. If time is different, how do you know that it was day off? (:-)) Though any two asynchronous agents have different time, at the same time (no pun intended), any two communicating agents cannot have arbitrary times. > Perhaps there are situations that do really need careful time > information, but those are clearly not those that computer clocks and > Ada.Calendar are intended for. I'd suggest using an NTP library for that > purpose. I see no reason why Ada.Calendar should not use the best available time source. >>> And I know Janus/Ada follows this model. Indeed, the heartbeat >>> monitor that monitors our web server machine fails every November >>> (as it waits >>> 61 minutes instead of 1 minute). That's not worth fixing, given that >>> the effect is to reboot the machine for no important reason once per year. >> >> I better leave that uncommented. (:-)) > > Two weeks work to fix one glitch per year makes no sense. It makes a lot of sense for industrial system, for which Ada must be the language of choice. I cannot remember any system we installed, which didn't use UTC stamps. Political time is no starter. ... >> I see no problem. GetSystemTime and GetSystemTimeAsFileTime do the >> job. > > My point is that there is no sane way to get the local time from the > SystemTime. Why should you care? Your point seem to be that Clock may deliver any rubbish. > Your claim that Split without a time zone parameter should still work > as it does currently implies that is possible and necessary (since it > has to return the local time, not the system time). I see no problem with that. As you said earlier, Ada RTL would use system services, the way how they work or do not work is not our business. As for Windows, Split from UTC can be implemented as FileTimeToLocalFileTime + FileTimeToSystemTime. > Note that using the performance counter has the effect of causing > large jumps at random intervals. The way the Janus/Ada implementation > works is that we "base" the performance counter with the local time at > start up. When clock is called, we use the base plus the performance > counter in order to produce the result time. However, if that result > differs more than 5 minutes from the local time as returned from the > OS, we then "rebase" the clock and return the local time instead. We > do this so that clock drift, NTP adjustments, manual adjustments, and > daylight saving time changes are all reflected in the result time. > This is important for long running programs - Ada.Calendar needs to reflect the correct (as seen by the computer) time. > The net effect of this means that there will be random jumps of at > least 5 minutes periodically for a long running program. (We do have a > minimum time between checks for rebasing, in order to improve the > performance of Ada.Calendar.Clock. So programs that only run a few > minutes - like ACATS tests - will never see a rebasing.) We do it differently. Basically it is a digital filter with takes performance counter readings and the system time (UTC). The filter is run each second or so. It has a window of at least 100 weighted readings. The output of the filter is the base to add to the performance counter in order to get FILETIME. So far we didn't experienced jumps. > Obviously, the 5 minute number is arbitrary. It could be more or less, > but you have to have such a number. If you rebased always, of course > the effect would be to ignore the performance counter completely. If > you never rebased, long-running programs like our web server (which is > intended to run months at a time) would never get the effect of NTP > clock settings and also could get far away from the actual time. Right, this is because the quartz has poor quality. We measured its drift using the above technique, it was about 5 microseconds per second between two identical machines. Note that even if the CPU and BIOS quartz were perfect, you could not use your technique, because during reading performance counter and system time the Ada task might get preempted. In our filter we read performance counter twice and use the difference as the weight to the reading (which itself is a mean of two). It is a bit complicated, but doable. >>> Also, you are requiring a complete re-implementation of Ada.Calendar. >> >> They must be, because the standard is broken. Once fixed, it will >> inevitably break some existing implementations. > > OK, but then it is necessary to consider the impact on customers. For > instance, if rebasing of times is banned, Not at all. I would mandate periodical rebasing if the implementation uses more than one time source, e.g. CPU and BIOS clocks. ****************************************************************