Version 1.1 of ai12s/ai12-0336-1.txt

Unformatted version of ai12s/ai12-0336-1.txt version 1.1
Other versions for file ai12s/ai12-0336-1.txt

!standard 9.6.1(40/2)          19-06-04 AI12-0336-1/01
!standard 9.6.1(42/3)
!class binding interpretation 19-06-04
!status work item 19-06-04
!status received 19-05-30
!priority Low
!difficulty Easy
!qualifier Omission
!subject
!summary
UTC_Time_Offset means Calendar time - UTC time.
Time_Zone = 0 means the time zone of Calendar.
!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
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 (-) Coordinated Universal Time (abbreviated UTC).} Type Time_Offset represents the number of minutes difference between the implementation-defined time zone used by Calendar and another time zone.{Redundant[ The zero value of type Time_Offset represents the implementation-defined time zone of Calendar.]}
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.
!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.
!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.

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

!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?

<time_zone.adb>

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 <calendar-time> - UTC, 
rather than UTC - <calendar-time>, 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 
><calendar-time> - UTC, rather than UTC - <calendar-time>, 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?

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


Questions? Ask the ACAA Technical Agent