!standard 9.6.1(6/2) 19-07-03 AI12-0336-1/03 !standard 9.6.1(35/2) !standard 9.6.1(40/2) !standard 9.6.1(41/2) !standard 9.6.1(42/3) !standard 9.6.1(90/2) !standard 9.6.1(91/2) !class binding interpretation 19-06-04 !status Amendment 1-2012 19-07-03 !status ARG Approved 9-0-1 19-06-14 !status work item 19-06-04 !status received 19-05-30 !priority Low !difficulty Easy !qualifier Omission !subject Meaning of Time_Offset !summary Time_Offset means the time difference from UTC time. Local_Time_Offset means Calendar time - UTC time. Time_Zone = 0 means the time offset of UTC. !question (1) 9.6.1(42/3) says the return value of UTC_Time_Offset is a number of minutes, the result of subtracting the implementation-defined time zone of Calendar from UTC time, at [a specific time]. This is in direct contradiction to the second paragraph of the !discussion in AI05-0119: "The intent is that UTC_Time_Offset means local-time - UTC-time.". It's also contrary to the ramification of 9.6.1(42.a.1/3). Is the normative wording correct? (No.) !recommendation (See Summary.) !wording Replace 9.6.1(6/2) with: function Local_Time_Offset (Date : Time := Clock) return Time_Offset; function UTC_Time_Offset (Date : Time := Clock) return Time_Offset renames Local_Time_Offset; Add after 9.6.1(35/2): function Local_Image (Date : Time; Include_Time_Fraction : Boolean := False) return String is (Image (Date, Include_Time_Fraction, Local_Time_Offset (Date))); Modify 9.6.1(40/2): Type Time_Offset represents {for a given locality at a given moment} the number of minutes {the local time is, at that moment, ahead (+) or behind (-) Coordinated Universal Time (abbreviated UTC). Redundant[ The Time_Offset for UTC is zero]} [difference between UTC the implementation-defined time zone used by Calendar and another time zone]. Modify 9.6.1(41/2): function {Local_Time_Offset}[UTC_Time_Offset] (Date : Time := Clock) return Time_Offset; Modify 9.6.1(42/3): Returns, as a number of minutes, {the Time_Offset of}[the result of subtracting] the implementation-defined time zone of Calendar [from UTC time], at the time Date. If the time zone of the Calendar implementation is unknown, then Unknown_Zone_Error is raised. Delete the second sentence of AARM 9.6.1(42.a/2). Modify 9.6.1(90/2): The implementation-defined time zone of package Calendar may, but need not, be the local time zone. {Local}[UTC]_Time_Offset always returns the difference relative to the implementation-defined time zone of package Calendar. If {Local}[UTC]_Time_Offset does not raise Unknown_Zone_Error, UTC time can be safely calculated (within the accuracy of the underlying time-base). Modify 9.6.1(91/2): Calling Split on the results of subtracting Duration({Local}[UTC]_Time_Offset*60) from Clock provides the components (hours, minutes, and so on) of the UTC time. In the United States, for example, {Local}[UTC]_Time_Offset will generally be negative. !discussion As the questioner states, AI05-0119-1 clearly states that UTC_Time_Offset means local-time - UTC-time. The wording change from that AI resulted in "...the result of subtracting the implementation-defined time zone of Calendar, and UTC time". During Ada 2005 review, Canada noted that the wording was still ambigious, so ", and" was changed to "from". But apparently no one noticed that this is backwards of the intent. Note that Ada is strongly typed, and so should the definition of Ada: a "time" and a "time zone" are not the same thing. Subtracting time zones is not well-defined, so we have to talk about subtracting times in particular time zones. ---- In researching this question, we tried a program provided by the questioner on all of the Ada 2005 compilers that we are aware of. All of the compilers that implement Ada.Calendar.Formatting except one (the least used one, still in beta) treated Time_Offset = 0 as UTC time. Enforcing the RM as written would therefore break any existing code that uses Ada.Calendar.Formatting (with the exception of the author's program that triggered this discussion). We therefore redefine Time_Offset to match the compilers, and add versions of some of the functions that provide the originally intended functionality. We used the prefix "Local_" to represent times for the "implementation-defined time zone of Calendar". Formally, since the time zone of Calendar need not be local, the correct name would be something like: Implementation_Defined_Time_Zone_of_Calendar_Image (...) But this appears to have a small usability problem. :-) The original intent was that Image would do this, and we don't want to have to write too much more to get that original intent. We renames UTC_Time_Offset to Local_Time_Offset, as that better represents the meaning of the function with the change in the definition of Time_Offset. This name is used throughout 9.6.1 Note that the actual result of the function is unchanged. For compatibility, a renaming of Local_Time_Offset named UTC_Time_Offset is also added. We also added Local_Image, to provide the image of the Ada.Calendar time without having to call Local_Time_Offset. We considered defining Local_xxx versions of all of the other subprograms in Ada.Calendar.Formatting that take Time_Zone parameters. For Value and Time_Of, there is a problem: the correct time zone to use could depend on the result of the function -- which of course depends on the time zone passed in. For most uses, this is unlikely to be an issue, so we could define a version based on the current time zone, but that could get incorrect answers near a time zone change. (To get certain correct answers, one could iterate until the result was the same for two successive iterations, but such an iteration is not guaranteed to terminate, so it's impractical to use it in the language definition). We did not define new versions of Split in part because we aren't defining most of the other routines (as noted above), and simply because there are three versions with a bunch of parameters each, so these definitions would add quite a bit of text to the package. Local_Year, Local_Month, and so on don't seem useful enough to define. ====== Note again that this change is inconsistent with the Ada 2012 definition. So far as we are aware, only the beta 3.2.1 Janus/Ada follows the Ada 2012 definition, so this inconsistency is not going to arise in practice. !corrigendum 9.6.1(6/2) @drepl @xcode< @b UTC_Time_Offset (Date : Time := Clock) @b Time_Offset;> @dby @xcode< @b Local_Time_Offset (Date : Time := Clock) @b Time_Offset;> @xcode< @b UTC_Time_Offset (Date : Time := Clock) @b Time_Offset @b Local_Time_Offset;> !corrigendum 9.6.1(35/2) @dinsa @xcode< @b Image (Date : Time; Include_Time_Fraction : Boolean := False; Time_Zone : Time_Zones.Time_Offset := 0) @b String;> @dinst @xcode< @b Local_Image (Date : Time; Include_Time_Fraction : Boolean := False; Time_Zone : Time_Zones.Time_Offset := 0) @b String @b (Image (Date, Include_Time_Fraction, Local_Time_Offset (Date)));> !corrigendum 9.6.1(40/2) @drepl Type Time_Offset represents the number of minutes difference between the implementation-defined time zone used by Calendar and another time zone. @dby Type Time_Offset represents for a given locality at a given moment the number of minutes the local time is, at that moment, ahead (+) or behind (-) Coordinated Universal Time (abbreviated UTC). The Time_Offset for UTC is zero. !corrigendum 9.6.1(41/2) @drepl @xcode<@b UTC_Time_Offset (Date : Time := Clock) @b Time_Offset;> @dby @xcode<@b Local_Time_Offset (Date : Time := Clock) @b Time_Offset;> !corrigendum 9.6.1(42/2) @drepl @xindent @dby @xindent !corrigendum 9.6.1(90/2) @drepl @xindent<@s9> @dby @xindent<@s9> !corrigendum 9.6.1(91/2) @drepl @xindent<@s9<37 Calling Split on the results of subtracting Duration(UTC_Time_Offset*60) from Clock provides the components (hours, minutes, and so on) of the UTC time. In the United States, for example, UTC_Time_Offset will generally be negative.>> @dby @xindent<@s9<37 Calling Split on the results of subtracting Duration(Local_Time_Offset*60) from Clock provides the components (hours, minutes, and so on) of the UTC time. In the United States, for example, Local_Time_Offset will generally be negative.>> !ASIS No ASIS effect. !ACATS test An ACATS C-Test should be constructed to check that Time_Zone = 0 means Calendar time. One way to do that is to compare the result of Ada.Calendar.Split to Ada.Calendar.Formatting.Split with Time_Zone = 0, as well as Ada.Calendar.Image with Time_Zone = 0. !appendix !topic Confusing definition of UTC Time !reference Ada 2012 AARM 9.6.1 (42/3) !from Simon Wright 2019-05-30 !keywords UTC !discussion First off, let me clarify I'm not addressing the complex questions of the changeover to/from daylight-saving or leap seconds, addressed at length in AI05-0119. (42/3) says the return value of UTC_Time_Offset is a number of minutes, the result of subtracting the implementation-defined time zone of Calendar from UTC time, at [a specific time]. This is in direct contradiction to the second paragraph of the !discussion in AI05-0119: "The intent is that UTC_Time_Offset means local-time - UTC-time.". It's also contrary to the ramification of (42.a.1/3). At the moment, I'm on British Summer Time, and the time is 18:01. In GMT that would be 17:01. GNAT thinks the UTC_Time_Offset is +60, which makes sense to me since we put the clocks forward in March. As a side issue, aren't "implementation-defined time zone of Calendar" and "UTC Time" incommensurate? I'm pretty sure I know what is meant, "the time returned by Calendar.Clock (whose time zone is implementation-defined)". **************************************************************** From: Tucker Taft Sent: Thursday, May 30, 2019 1:55 PM Interesting! This appears to be due to an "editorial" shift in wording as part of AI05-0269-1 from "subtracting A and B" to "subtracting A from B" which inverts the meaning. It would be interesting to know what most compilers do here (at least the ones that don't always return zero!). **************************************************************** From: Randy Brukardt Sent: Friday, May 31, 2019 12:07 AM Janus/Ada, at least, returns a negative number here in Wisconsin. I would hope that implementers read the AARM note and match that (sounds like GNAT does that, anyway). But the wording does seem backwards. Sigh - another AI. **************************************************************** From: Tucker Taft Sent: Friday, May 31, 2019 6:43 AM Actually, I described the change incorrectly. It went from "the difference between A and B" to "subtracting A from B." Unfortunately "difference between" is itself somewhat ambiguous, but in any case, the final wording is unambiguous, but wrong ... ;-) **************************************************************** From: Randy Brukardt Sent: Tuesday, June 4, 2019 8:59 PM ... > As a side issue, aren't "implementation-defined time zone of Calendar" > and "UTC Time" incommensurate? I'm pretty sure I know what is meant, > "the time returned by Calendar.Clock (whose time zone is > implementation-defined)". I think any good Ada compiler would reject an expression between two different types. Unfortunately, there's no ARM compiler. Anyway, the better question is how to repair it. My first thought was to describe it as the difference between two time zones: Modify 9.6.1(42/3): Returns, as a number of minutes, the result of subtracting {the time zone of UTC time from} the implementation-defined time zone of Calendar[ from UTC time], at the time Date. If the time zone of the Calendar implementation is unknown, then Unknown_Zone_Error is raised. ...but this is a bit weird because most of us think of time zones as names like UTC or BST or CDT. What is the result of subtracting "UTC" - "CDT"? (-300 is the intended answer, but there doesn't seem to be an operator). So it seems like we need a bigger change: Modify 9.6.1(42/3): Returns, as a number of minutes, the result of subtracting {the UTC time corresponding to Date from} the {time in} the implementation-defined time zone of Calendar[, at the time]{ corresponding to} Date. If the time zone of the Calendar implementation is unknown, then Unknown_Zone_Error is raised. [Recall that "Date" is the parameter to UTC_Time_Offset.] Is this latter wording OK, or should we do something else??? **************************************************************** From: Tucker Taft Sent: Tuesday, June 4, 2019 9:26 PM > Is this latter wording OK, or should we do something else??? This doesn't work for me. You are implying that the value of time is time-zone dependent. That is not true on any Unix-like system. The value of "time" is the same on all Unix systems at any given moment, being defined as the number of seconds since some particular moment in history (e.g. Jan 1, 1970, GMT). I think we need to talk about the number of minutes since the local midnight, say, and do the computation in terms of that value, perhaps modulo 24*60. We probably should start by defining what we mean by "time zone" since the term is used repeatedly. If that definition is described, for the purposes of this section, as a number of minutes the local time is ahead of (+) or behind (-) UTC, then I think the rest becomes trivial. Here is my attempt: Modify 9.6.1(40/2): {For the purposes of this subclause, the /time zone/ for a given locality is defined in terms of the number of minutes the local time is ahead (+) or behind (-) UTC.} Type Time_Offset represents the number of minutes difference between the implementation-defined time zone used by Calendar and another time zone. Now we can modify 9.6.1(42/3): Returns, as a number of minutes, [the result of subtracting] the implementation-defined time zone of Calendar [from UTC time], at the time Date. If the time zone of the Calendar implementation is unknown, then Unknown_Zone_Error is raised. **************************************************************** From: Randy Brukardt Sent: Tuesday, June 4, 2019 10:50 PM ... > This doesn't work for me. You are implying that the value of time is > time-zone dependent. That is not true on any Unix-like system. The > value of "time" is the same on all Unix systems at any given moment, > being defined as the number of seconds since some particular moment in > history (e.g. Jan 1, 1970, GMT). I've never understood this argument. We can say "time" is whatever we want it to be, it doesn't necessarily have anything to do with how it is represented on a particular system. Moreover, even on systems that use a raw counter, you still have to know what time zone the counter represents, or you couldn't possibly split the value properly. 1042 seconds since a base date is not a time, 1042 since some date in UTC is a time. Put another way, the time zone for a time value might be implicit, or it might be determined some other way, but there has to be one for any value of time. Be that as it may, I know that this argument is non-terminating, so let's move on. > I think we need to talk about the number of minutes since the local > midnight, say, and do the computation in terms of that value, perhaps > modulo 24*60. > > We probably should start by defining what we mean by "time zone" since > the term is used repeatedly. If that definition is described, for the > purposes of this section, as a number of minutes the local time is > ahead of (+) or behind (-) UTC, then I think the rest becomes trivial. > > Here is my attempt: > > Modify 9.6.1(40/2): > > {For the purposes of this subclause, the /time zone/ for a given > locality is defined in terms of the number of minutes the local time > is ahead (+) or behind (-) UTC.} Type Time_Offset represents the > number of minutes difference between the implementation-defined time > zone used by Calendar and another time zone. The (minor) problem here is that type Time_Offset and the virtual type time zone are very different for no obvious reason. Obviously, whomever read this at AdaCore interpreted it to be the former (which one can read fairly easily on Linux) and never really looked at the actual words (or decided the apply the Dewar rule without telling anyone). One has to wonder if we really should have these two separate declarations, especially since it appears that only Janus/Ada does this right (that is, following the RM definition). Times would work slightly better if UTC was the default time zone (getting UTC wouldn't depend on the time zone, which is error-prone). Of course, the practical results wouldn't change much (whatever the underlying system does would still be used). A second question is whether we need to define UTC. I presume we're using the term from some other standard, but here it just appears out of the blue. We don't ever define it in the AARM notes. An undefined term is supposed to be in the dictionary or the mathematical reference. I can't check the dictionary (don't have that one), but it's not in the mathematical reference. It's of course defined in Wikipedia, but we can't use that in the RM. At a minimum, we ought to use the full English name "Coordinated Universal Time" once, so people can look it up. > Now we can modify 9.6.1(42/3): > > Returns, as a number of minutes, [the result of subtracting] the > implementation-defined time zone of Calendar [from UTC time], at the > time Date. If the time zone of the Calendar implementation is unknown, > then Unknown_Zone_Error is raised. I guess I don't like that this definition no longer has any (obvious) relationship to UTC. OTOH, if we changed Time_Offset to the GNAT definition, this would always return 0 (and we'd need to add Local_Time_Offset to the spec). But I don't have a better idea, so I suppose I should shut up. **************************************************************** From: Joey Fish Sent: Wednesday, June 5, 2019 4:03 AM >This doesn't work for me. You are implying that the value of time is >time-zone dependent. That is not true on any Unix-like system. Why is this an issue? Why should the Ada standard's notion of time be at all linked to Unix? [or Windows, or VMS, or anything?] In fact, some of the biggest warts are due to importing and accommodating unix/c follies, with anonymous access types leading the charge. >I think we need to talk about the number of minutes since the local >midnight, say, and do the computation in terms of that value, perhaps >modulo 24*60. I'm not sure that is a good idea. (I'm currently working night-shift, so I come in and work before midnight and finish after midnight; so while it's simple to say "I worked 10 hours" denoting them in "minutes since [local] midnight" wouldn't be very nice.) I do know ISO 8601 was recently updated, perhaps looking at that would be helpful. **************************************************************** From: Thomas Quinot Sent: Wednesday, June 5, 2019 4:27 AM > Modify 9.6.1(40/2): > > {For the purposes of this subclause, the /time zone/ for a given locality > is defined in terms of the number of minutes the local time is ahead (+) > or behind (-) UTC.} Type Time_Offset represents the number of minutes > difference between the implementation-defined time zone used by Calendar > and another time zone. However keep in mind that if you understand time zone as a single UTC offset then this depends not just on the locality but also on the specific point in time, due to daylight saving time issues. (IOW the UTC offset is a function of both the locality **and the point in tiem**). **************************************************************** From: Tucker Taft Sent: Wednesday, June 5, 2019 7:12 AM >> Modify 9.6.1(40/2): >> >> {For the purposes of this subclause, the /time zone/ for a given locality >> is defined in terms of the number of minutes the local time is ahead (+) >> or behind (-) UTC.} Type Time_Offset represents the number of minutes >> difference between the implementation-defined time zone used by Calendar >> and another time zone. > > However keep in mind that if you understand time zone as a single UTC > offset then this depends not just on the locality but also on the > specific point in time, due to daylight saving time issues. (IOW the > UTC offset is a function of both the locality **and the point in > tiem**). Good point. That should probably be more explicit, as it is in the definition of UTC_Time_Offset. Perhaps: {For the purposes of this subclause, the /time zone/ for a given locality at a given moment is defined in terms of the number of minutes the local time is, at that moment, ahead (+) or behind (-) UTC.} **************************************************************** From: Dirk Craeynest Sent: Wednesday, June 5, 2019 4:32 AM > > We probably should start by defining what we mean by "time > > zone" since the term is used repeatedly. If that definition > > is described, for the purposes of this section, as a number > > of minutes the local time is ahead of (+) or behind (-) UTC, > > then I think the rest becomes trivial. > > > > Here is my attempt: > > > > Modify 9.6.1(40/2): > > > > {For the purposes of this subclause, the /time zone/ for a > > given locality is defined in terms of the number of minutes > > the local time is ahead (+) or behind (-) UTC.} Type > > Time_Offset represents the number of minutes difference > > between the implementation-defined time zone used by Calendar > > and another time zone. > The (minor) problem here is that type Time_Offset and the virtual > type time zone are very different for no obvious reason. [...] The definition proposed above is not what is commonly understood by "time zone" (a region with uniform time), but is a value: the time offset in that region versus UTC. Hence using UTC_Time_Offset or UTC_Offset for this value is probably more appropriate. And that value could then be of type Time_Offset... (See also https://en.wikipedia.org/wiki/List_of_UTC_time_offsets.) About: > Times would work slightly better if UTC was the default time zone Note that strictly speaking UTC is not a time zone: it is a time standard (Coordinated Universal Time). **************************************************************** From: Tucker Taft Sent: Wednesday, June 5, 2019 3:00 PM > Hence using UTC_Time_Offset or UTC_Offset for this value is probably > more appropriate. And that value could then be of type Time_Offset... I was trying to minimize wording changes here, since we are just fixing a bug. The existing wording uses the term "time zone" without defining it, and that has led to some confusion. We could reword this whole section probably, but I don't think that is justified to just fix this current bug. **************************************************************** !topic Time_Zone parameter to Calendar.Formatting subprograms !reference Ada 2012 AARM 9.6.1 !from Simon Wright 2019-05-30 !keywords UTC !discussion Many of the subprograms (e.g. Hour) take a Time_Zone parameter which defaults to 0. It's been suggested that this default means "in the local time zone". GNAT's treatment is to regard 0 as meaning "in UTC". This seems reasonable, since Time_Offset'(0) is what you get when calling UTC_Time_Offset in time zone GMT. Neither ARM nor AARM seem to define the behaviour. **************************************************************** From: Tucker Taft Sent: Thursday, May 30, 2019 1:49 PM Doesn't 9.6.1(40/2) answer this question? Here it is: Type Time_Offset represents the number of minutes difference between the implementation-defined time zone used by Calendar and another time zone. If a value of this type is zero, that implies you are interested in an answer that is relevant to the time zone used by Calendar. And as you suggest, that is determined by calling UTC_Time_Offset. So what additional words would you expect to see in the RM? **************************************************************** From: Simon Wright Sent: Thursday, May 30, 2019 3:18 PM >Doesn't 9.6.1(40/2) answer this question? Here it is: > > Type Time_Offset represents the number of minutes difference between > the implementation-defined time zone used by Calendar and another time > zone. > >If a value of this type is zero, that implies you are interested in an answer >that is relevant to the time zone used by Calendar. And as you suggest, that >is determined by calling UTC_Time_Offset. Given the first sentence, not sure the second is relevant? I do see what you mean, eventually, but both I and GNAT's implementors seem to have got it wrong. In my case, perhaps because being in BST at the moment, the 60 minutes difference between BST and UTC is the same as the 60 minutes added when we went to daylight savings. Or perhaps, UTC being universal, I convinced myself that a Time_Zone parameter of 0 must mean UTC. If I run the attached program on GNAT (macOS & Linux) I get $ date Thu 30 May 2019 20:55:48 BST $ ./time_zone UTC_Time_Offset: 60 Time_Zone default: 2019-05-30 19:55:52 Time_Zone offset: 2019-05-30 20:55:52 so to get local time I had to use Time_Zone => UTC_Time_Offset (Now). >So what additional words would you expect to see in the RM? Add to 9.6.1(40/2) "Thus, when 0 is passed as the Time_Zone parameter in subprograms below, this means to use the time zone used by Calendar." Alternatively, add to 9.6.1(53/2) "When 0 is passed as the Time_Zone parameter in this and in subprograms below, this means to use the time zone used by Calendar." --- Attached program: with Ada.Calendar.Formatting; with Ada.Calendar.Time_Zones; with Ada.Text_IO; procedure Time_Zone is Now : constant Ada.Calendar.Time := Ada.Calendar.Clock; Offset : constant Ada.Calendar.Time_Zones.Time_Offset := Ada.Calendar.Time_Zones.UTC_Time_Offset (Now); begin Ada.Text_IO.Put_Line ("UTC_Time_Offset: " & Offset'Image); Ada.Text_IO.Put_Line ("Time_Zone default: " & Ada.Calendar.Formatting.Image (Now)); Ada.Text_IO.Put_Line ("Time_Zone offset: " & Ada.Calendar.Formatting.Image (Now, Time_Zone => Offset)); end Time_Zone; **************************************************************** From: Tucker Taft Sent: Thursday, May 30, 2019 5:16 PM >>Doesn't 9.6.1(40/2) answer this question? Here it is: >> >> Type Time_Offset represents the number of minutes difference between >> the implementation-defined time zone used by Calendar and another time >> zone. >> >>If a value of this type is zero, that implies you are interested in an answer >>that is relevant to the time zone used by Calendar. And as you suggest, that >>is determined by calling UTC_Time_Offset. > >Given the first sentence, not sure the second is relevant? I am not sure what the above refers to. There are three sentences above, one copied from the reference manual, and two that were my conclusions based on that. What did you think was not relevant? >I do see what you mean, eventually, but both I and GNAT's implementors seem to >have got it wrong. In my case, perhaps because being in BST at the moment, the >60 minutes difference between BST and UTC is the same as the 60 minutes added >when we went to daylight savings. Or perhaps, UTC being universal, I convinced >myself that a Time_Zone parameter of 0 must mean UTC. But it seems pretty clear from the description that a time zone parameter of 0 means "Calendar's timezone." Of course, what does it mean to talk about Calendar's timezone if time (as returned by Calendar.Clock) is internally *always* number of seconds since some absolute time in the past? Well it is defined by what "Calendar.Split" does. An invariant should be that Calendar.Split and Calendar.Formatting.Split return essentially the same thing when the Time_Offset parameter is zero. >If I run the attached program on GNAT (macOS & Linux) I get > > >$ date >Thu 30 May 2019 20:55:48 BST >$ ./time_zone >UTC_Time_Offset: 60 >Time_Zone default: 2019-05-30 19:55:52 >Time_Zone offset: 2019-05-30 20:55:52 > >so to get local time I had to use Time_Zone => UTC_Time_Offset (Now). That seems a bit weird. Of course what the system "date" program does is another question -- it need not match what Calendar.Split does. But based on your program, it looks like Calendar.Formatting.Image when given an offset of zero gives UTC, even though the UTC_Time_Offset indicates that Calendar.Split gives BST. So somebody is lying! >So what additional words would you expect to see in the RM? > >Add to 9.6.1(40/2) "Thus, when 0 is passed as the Time_Zone parameter in >subprograms below, this means to use the time zone used by Calendar." So, to be clear, this is formally redundant with what is there now -- you just are suggesting it would help clarify the meaning? >Alternatively, add to 9.6.1(53/2) "When 0 is passed as the Time_Zone >parameter in this and in subprograms below, this means to use the time zone >used by Calendar." So again, you are not saying there is anything wrong, but are suggesting that this extra wording would be helpful for understanding. Am I understanding you correctly? There does seem to be a bug in the RM 9.6.1(42/3) (from your other Ada Comment) about the definition of UTC_Time_Offset which should be - UTC, rather than UTC - , and perhaps also a bug in GNAT, in that if Time_Zone => 0, then you should be getting the same info as returned by Calendar.Split when you call Calendar.Formatting.Image/Split/etc. Clearly not too many folks are using this Calendar.Formatting package! **************************************************************** From: Randy Brukardt Sent: Friday, May 31, 2019 12:05 AM > That seems a bit weird. Of course what the system "date" program does >is another question -- it need not match what Calendar.Split does. But >based on your program, it looks like Calendar.Formatting.Image when >given an offset of zero gives UTC, even though the UTC_Time_Offset >indicates that Calendar.Split gives BST. So somebody is lying! This is indeed the exact problem. This came up with Simon was trying to use my GNAT grading tools on his Linux box. One of the tools is called "Tstamp" which just outputs a formatted time stamp to Standard Output. Simon was having problems because the time reported by the tests (via the ACATS Report package didn't match that of Tstamp. The ACATS Report package originated in Ada 83 and thus uses Ada.Calendar.Split to display a time value. When I wrote Tstamp, since it only needed to work with GNAT, I simplified my life and used Ada.Calendar.Formatting.Image. On Windows, I got the same result for each (although I'm not certain which *compiler* I used to compile Tstamp). But that isn't true on Linux, apparently. >>> So what additional words would you expect to see in the RM? >>Add to 9.6.1(40/2) "Thus, when 0 is passed as the Time_Zone parameter >>in subprograms below, this means to use the time zone used by Calendar." >So, to be clear, this is formally redundant with what is there now -- >you just are suggesting it would help clarify the meaning? I couldn't convince myself that it was "formally redundant" as you claim, and I obviously failed to convince Simon. In any event, someone didn't understand it and it would help to say this. Note that this case could be (and should be!) tested by an ACATS test, but I would want to be sure that we all agree that the RM says Time_Zone => 0 means Calendar's time zone before spending the effort on it. (Essentially, call Calendar.Split on a time, and make sure that Calendar.Formatting.Split with the default time zone of 0 gets the same answers, as well as Calendar.Formatting.Image.) ... >There does seem to be a bug in the RM 9.6.1(42/3) (from your other Ada >Comment) about the definition of UTC_Time_Offset which should be > - UTC, rather than UTC - , and perhaps >also a bug in GNAT, in that if Time_Zone => 0, then you should be >getting the same info as returned by Calendar.Split when you call >Calendar.Formatting.Image/Split/etc. > >Clearly not too many folks are using this Calendar.Formatting package! The ACATS grading tools do use it. It would be good for it to work the same on all compilers (and certainly on all GNATs), else the grading tools will be wonky. **************************************************************** From: Simon Wright Sent: Friday, May 31, 2019 7:50 AM ... >>>If a value of this type is zero, that implies you are interested in an answer >>>that is relevant to the time zone used by Calendar. And as you suggest, that >>>is determined by calling UTC_Time_Offset. >> >>Given the first sentence, not sure the second is relevant? > >I am not sure what the above refers to. There are three sentences above, one >copied from the reference manual, and two that were my conclusions based on >that. What did you think was not relevant? I meant the 2nd and 3rd sentences, sorry. I think the conclusion of the discussion (so far) is that if (2nd sentence) I want answers relevant to Calendar's time zone I just supply an offset of 0, (3rd sentence) no need to invoke UTC_Time_Offset at all. ... >So again, you are not saying there is anything wrong, but are suggesting that >this extra wording would be helpful for understanding. Am I understanding >you correctly? Yes, exactly. >Clearly not too many folks are using this Calendar.Formatting package! Or maybe GNAT users, including myself, are being lazy & adopting a "suck it and see" approach. **************************************************************** From: Tucker Taft Sent: Friday, May 31, 2019 3:11 PM ... >I meant the 2nd and 3rd sentences, sorry. I think the conclusion of the >discussion (so far) is that if (2nd sentence) I want answers relevant to >Calendar's time zone I just supply an offset of 0, (3rd sentence) no need >to invoke UTC_Time_Offset at all. No need to do so, but if you wanted to find out what was the timezone of package Calendar, you could use UTC_Time_Offset to do so, ... >>So again, you are not saying there is anything wrong, but are suggesting >>that this extra wording would be helpful for understanding. Am I >>understanding you correctly? >Yes, exactly. OK, thanks for clarifying. >>Clearly not too many folks are using this Calendar.Formatting package! >Or maybe GNAT users, including myself, are being lazy & adopting a "suck it >and see" approach. Could be! **************************************************************** From: Randy Brukardt Sent: Tuesday, June 4, 2019 9:36 PM > If I run the attached program on GNAT (macOS & Linux) I get > > $ date > Thu 30 May 2019 20:55:48 BST > $ ./time_zone > UTC_Time_Offset: 60 > Time_Zone default: 2019-05-30 19:55:52 > Time_Zone offset: 2019-05-30 20:55:52 > > so to get local time I had to use Time_Zone => UTC_Time_Offset (Now). If I run this program on Janus/Ada on Windows, I get: D:\Testing\Win\console>time The current time is: 21:11:22.97 Enter the new time: D:\Testing\Win\console>tz UTC_Time_Offset: -300 Time_Zone default: 2019-06-04 21:11:28 Time_Zone offset: 2019-06-05 02:11:28 But if I run the program using GNAT, I get: D:\Testing\Win\console>time The current time is: 21:15:00.35 Enter the new time: D:\Testing\Win\console>tz UTC_Time_Offset: -300 Time_Zone default: 2019-06-05 02:15:02 Time_Zone offset: 2019-06-04 21:15:02 Wonder what ObjectAda does? **************************************************************** From: Randy Brukardt Sent: Wednesday, June 5, 2019 6:31 PM > Wonder what ObjectAda does? I sent PTC and Irvine this program (being the only other Ada 2005 compilers I know of). Irvine responded that they don't implement Ada.Calendar.Formatting. PTC sent a bunch of test results (in pretty screen grabs that I can't reasonably reproduce here). They pointed out that Simon had used the Object'Image, which is only a Ada 2012/TC1 feature. After fixing that problem, they reported the following results (hand keyed from the graphics, so if they don't make sense, blame me, not PTC). For ObjectAda 10.1: [...]> date Wed Jun 5 10:29:48 PDT 2019 [...]> time_zone.exe UTC_Time_Offset: -420 Time_Zone default: 2019-06-05 17:29:52 Time_Zone offset: 2019-06-05 10:29:52 ---- For ApexAda v5.2: [...]$ date Wed Jun 5 12:49:48 EDT 2019 [...]$ ./timezone UTC_Time_Offset: -480 Time_Zone default: 2019-06-05 12:49:55 Time_Zone offset: 2019-06-05 04:49:55 They also ran a copy of the ObjectAda program in France, giving: [...]> date Wed Jun 5 10:29:48 PDT 2019 [...]> time_zone.exe UTC_Time_Offset: 120 Time_Zone default: 2019-06-05 08:49:07 Time_Zone offset: 2019-06-05 10:49:07 ========================================================= Conclusion: I'm apparently the only one that actually read the RM definition and implemented it exactly. Everyone else implemented the Time_Zone value as being an offset from UTC, or didn't implement it at all. Given the disruption inherent in forcing almost every compiler to change to the intended definition (which would break any existing code that is expecting a particular result, other than mine!), I think we have no choice but to revise the definition of Time_Offset to match that Tucker called "time zone". This is annoying in that the intent was that the default for Image would be the local time (not UTC). Short of adding additional routines, though, I don't see a way to do that and also change the RM meaning of Time_Offset. So, I would propose the following changes: (1) Change the definition of Time_Offset to match that Tucker used for "time zone". We probably could drop that definition. (2) Add a renaming of UTC_Time_Offset called Local_Time_Offset (which is a better name for this concept after the inversion of the meaning of Time_Offset). (3) Add Local_Image, which would be defined to be Image (Time, Include_Time_Fraction, Local_Time_Offset(Time)); Perhaps we should add a matching Local_Value, but that's problematical to define as the time offset to use possibly depends on the result. (It's much less likely to be a problem in practice, so maybe some English definition is enough.) I don't think it pays to add Local_ versions of all of the Time_Of and Split routines, as there are five of them (and the definition of Local_Time_Of would have the same problem as Local_Value). What do you all think??? **************************************************************** From: Joey Fish Sent: Thursday, June 6, 2019 3:49 AM > This is annoying in that the intent was that the default for Image would be > the local time (not UTC). Short of adding additional routines, though, I > don't see a way to do that and also change the RM meaning of Time_Offset. I think the image should be in local time, isn't that [messing around with UTC and such] what the formatting/time_zones/conversion children of Ada.Calendar are about? **************************************************************** From: Tucker Taft Sent: Thursday, June 6, 2019 12:53 PM Perhaps we could add a default for UTC_Time_Offset/Local_Time_Offset to be Calendar.Clock? Then you can just write "Local_Time_Offset" and use it as a default on a renaming of some of these routines to be Local_*. Too bad this was so unclear to begin with, but it sounds like there couldn't have been much use of these features so far, given the semi-random results that are produced. **************************************************************** From: Randy Brukardt Sent: Thursday, June 6, 2019 3:10 PM > Perhaps we could add a default for > UTC_Time_Offset/Local_Time_Offset to be Calendar.Clock? That *is* the default to UTC_Time_Offset. > Then > you can just write "Local_Time_Offset" and use it as a default on a > renaming of some of these routines to be Local_*. I thought of that, but it would be wrong for Local_Image and the like, as it wouldn't take into account time zone changes (i.e. summer/daylight saving time) for some times. For *inbound* times, it seems nasty to get the time zone wrong just so we can write a renaming. After all, the reason for having a time parameter is to avoid that sort of glitch. (And since Clock is relatively expensive, it probably would be faster to use the passed in time -- not that that would often matter.) We could do that for *outbound* items (Value and Time_Of), should we try to support those. > Too bad this was so unclear to begin with, but it sounds like there > couldn't have been much use of these features so far, given the > semi-random results that are produced. Well, all of the compilers 'cept mine do the same thing (and mine hasn't been released yet), so its probably the case that most users got a surprising answer once, changed their code, and moved on. This probably never would have shown up had I not created a library that actually followed the RM and then used it in a publicly posted program. When someone (Simon) tried to use the program on GNAT, then the difference showed up, and Simon was good enough to raise it here (I don't know that I would have). So it's quite possible this stuff is used a decent amount, just with a different expectation than the RM has. **************************************************************** From: Randy Brukardt Sent: Thursday, June 6, 2019 8:33 PM >>This is annoying in that the intent was that the default for Image would be >>the local time (not UTC). Short of adding additional routines, though, >>I don't see a way to do that and also change the RM meaning of Time_Offset. >I think the image should be in local time, isn't that [messing around >with UTC and such] what the formatting/time_zones/conversion children >of Ada.Calendar are about? True, but we also have an obligation to standardize existing practice when possible. Do we want to break everyone's code in this area? I'm suggesting that we split the baby by defining Local_Image to give the Calendar result and leave the existing Image to do what it does on all of the existing compilers except mine. (And note that Image is already in the "formatting/time_zones/conversion children of Ada.Calendar"; we're not talking about any change to Ada.Calendar.) It's not perfect but it is the least disruptive option. (It also would allow Ada runtimes to represent Time primarily in UTC time internally; I suspect that is the cause of this confusion.) **************************************************************** From: Joey Fish Sent: Friday, June 7, 2019 8:37 PM >>>This is annoying in that the intent was that the default for Image would be >>>the local time (not UTC). Short of adding additional routines, though, I >>>don't see a way to do that and also change the RM meaning of Time_Offset. >>I think the image should be in local time, isn't that [messing around with >>UTC and such] what the formatting/time_zones/conversion children of >>Ada.Calendar are about? >True, but we also have an obligation to standardize existing practice when >possible. Do we want to break everyone's code in this area? Given the ARG's stance on backwards-compatibility, to the point of not eliminating features which were absolutely mistakes, yes. One of the big failings of the SQL standard is they made so many of the features optional —in the name of existing implementations— so as to make the standard useless WRT portability for any non-trivial construction. Given the ARG's goal of correctness, yes. That implementations made a mistake is regrettable, and something that should be clarified to avoid in the future, but that is not the fault of the standard, is it? (I mean if X many people misread "you shall not paint your truck red", dropping the 'not' and painting the truck red — is that the fault of the instructions?) >I'm suggesting that we split the baby by defining Local_Image to give the >Calendar result and leave the existing Image to do what it does on all of >the existing compilers except mine. (And note that Image is already in the >"formatting/time_zones/conversion children of Ada.Calendar"; we're not >talking about any change to Ada.Calendar.) It's not perfect but it is the >least disruptive option. (It also would allow Ada runtimes to represent Time >primarily in UTC time internally; I suspect that is the cause of this >confusion.) Is there anything preventing that now? I mean it could be represented internally as a monotonic time-stamp, with adjustments done in the image function, right? *************************************************************** From: Tucker Taft Sent: Saturday, June 8, 2019 7:58 AM >>... (It also would allow Ada runtimes to represent Time >>primarily in UTC time internally; I suspect that is the cause of this >>confusion.) >Is there anything preventing that now? No, in fact most Ada run-times on Unix-like systems already do exactly that. >I mean it could be represented internally as a monotonic time-stamp, with >adjustments done in the image function, right? Yes, that is how it is done in most Ada run-times that I have ever worked on. *************************************************************** From: Randy Brukardt Sent: Monday, June 10, 2019 11:40 PM >Yes, that is how it is done in most Ada run-times that I have ever >worked on. That doesn't work well on Windows, however, as Windows gives Year:Month:Day:Hr:Min:Sec, and converting that into a "monotonic" value is rather complicated because of leap-years. Doing that on every call to Clock is potentially too expensive. (There's a trade-off between the cost of Clock/Split and the cost of ordering operators; which makes the most sense depends on how often Clock is called vs. the operators.) *************************************************************** From: Joey Fish Sent: Tuesday, June 11, 2019 10:24 AM > That doesn't work well on Windows, however, as Windows gives > Year:Month:Day:Hr:Min:Sec, and converting that into a "monotonic" value is > rather complicated because of leap-years. Doing that on every call to Clock > is potentially too expensive. Indeed, which is why having monotonic time be the default/internal time-format makes more sense. (Though, I suppose you could argue that the PC-clock, which has been part of the PC since its inception, is dedicated hardware with an internal wall-clock format that handles all the messy stuff like leap-year and daylight-saving time and, thus, that provides for a natural internal/default for wall-clock date/time handling.) — Besides the fact that (a) formatting changes dependent on usage [eg "0800" vs "8:00 am"], and (b) things like daylight-savings time are put in place by legislation, and thus can be altered far easier than altering the silicon. >(There's a trade-off between the cost of >Clock/Split and the cost of ordering operators; which makes the most sense >depends on how often Clock is called vs. the operators.) I wonder if anyone's done any real analysis of clock vs. operators usage rates. ***************************************************************