!standard 9.6.1(1) 05-07-20 AI95-00427/05
!class amendment 05-04-10
!status Amendment 200Y 05-05-05
!status WG9 Approved 06-06-09
!status ARG Approved 11-0-0 05-04-16
!status work item 05-04-10
!status received 05-04-10
!priority High
!difficulty Easy
!subject Default parameters and Calendar operations
!summary
1 The parameters of Split are rearranged so that the parameter
Time_Zone is last.
2 The parameter Time_Zone of Seconds and Sub_Seconds is deleted.
3 Functions Year, Month and Day with a Time Zone parameter are added.
4 The range on the subtype Leap_Seconds_Count is changed to -2047 .. 2048.
5 The AARM note regarding Difference is replaced. A parenthetic remark
is added to the normative text to confirm that Seconds does not include
leap seconds.
6 The range of Time_Offset is increased.
7 The ranges of possible values of the result of the function Sub_Second
and parameters Seconds and Sub_Second of Time_Of, Seconds_Of and Split
are clarified.
8 The second Time_Of in Calendar.Formatting should default Seconds to 0.0.
!problem
A number of improvements to the additional time facilities of AI-351 are
suggested.
The default parameter Time_Zone of three subprograms Split is the second
parameter. This means that if the default is used then all the out
parameters which follow it have to use named notation. Since there are
5, 7 and 8 of these, this is tiresome.
The result of the functions Second and Sub_Second cannot depend upon the
parameter Time_Zone which is therefore superfluous.
There are no functions Year, Month and Day with a time zone parameter,
this forces the use of Split.
The second Time_Of does not default the Seconds parameter; yet this is
the same as the Time_Of in Calendar (with time zones and leap seconds added),
which does default the parameter.
The AARM note regarding difference is peculiar.
The facilities of these packages enable the decomposition of a Time "as
appropriate for the time offset specified". This enables a program running
with a local Clock to decompose a time as UTC. It also enables a program
to decompose a local time as if in some other time zone. Thus in New York
we can get the time decomposed as if in Paris by a Time Offset of -360.
But it won't work for a program running in local time in Tonga and wanting
the time in the Aleutian Islands because of the vagaries of the International
Date Line. The time shift is 25 hours and this exceeds the range of
Time_Offset. Even larger shifts are possible.
The text 9.6 (26) referring to Split and Time_Of in Calendar prescribes
the behavior regarding a Seconds value of 86_400.0. There is no
corresponding text regarding the subprograms in the child package for
Seconds or Sub_Second.
!proposal
(See summary.)
!wording
[Editor's note: The paragraph numbers are from draft 11 of the AARM.]
Change 9.6.1(4/2) to
type Time_Offset is range -28*60 .. 28*60;
Replace 9.6.1(11/2) by
subtype Leap_Seconds_Count is Integer range -2047 .. 2047;
Add after 9.6.1(23/2)
function Year (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Year_Number;
function Month (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Month_Number;
function Day (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Day_Number;
Replace 9.6.1(26/2-27/2) by
function Second (Date : Time)
return Second_Number;
function Sub_Second (Date : Time)
return Second_Duration;
Move 9.6.1(30/2) below.
Replace 9.6.1(32/2-34/2) by [this includes the previous 9.6.1(30/2)]
function Time_Of (Year : Year_Number;
Month : Month_Number;
Day : Day_Number;
Seconds : Day_Duration := 0.0;
Leap_Second: Boolean := False;
Time_Zone : Time_Zones.Time_Offset := 0)
return Time;
procedure Split (Date : in Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Hour : out Hour_Number;
Minute : out Minute_Number;
Second : out Second_Number;
Sub_Second : out Second_Duration;
Time_Zone : in Time_Zones.Time_Offset := 0);
procedure Split (Date : in Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Hour : out Hour_Number;
Minute : out Minute_Number;
Second : out Second_Number;
Sub_Second : out Second_Duration;
Leap_Second: out Boolean;
Time_Zone : in Time_Zones.Time_Offset := 0);
procedure Split (Date : in Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Seconds : out Day_Duration;
Leap_Second: out Boolean;
Time_Zone : in Time_Zones.Time_Offset := 0);
Change 9.6.1 (44/2) thus
Returns the difference between Left and Right.
Days is the number of days of difference, Seconds is the
remainder seconds of difference {excluding leap seconds}, and
Leap_Seconds is the number of leap seconds.
If Left < Right, then Seconds <= 0.0, Days <= 0, and Leap_Seconds <= 0.
Otherwise, all values are nonnegative. {The absolute value of
Seconds is always less than 86_400.0.}
For the returned values, if Days = 0, then
Seconds + Duration(Leap_Seconds) = Calendar."-" (Left, Right).
Change 9.6.1 (44.a/2) thus
[The number of days is calculated midnight-to-midnight.]
Leap_Seconds, if any, are not included in Seconds.
Note: the above remark about leap seconds is really superfluous because it
is now in the normative text but it leads into the next AARM paragraph
neatly.
Insert after 9.6.1 (52/2)
function Year (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Year_Number;
Returns the year for Date, as appropriate for the specified time zone.
function Month (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Month_Number;
Returns the month for Date, as appropriate for the specified time zone.
function Day (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Day_Number;
Returns the day number for Date, as appropriate for the specified time zone.
Replace 9.6.1 (57/2-60/2) by:
function Second (Date : Time)
return Second_Number;
Returns the second within the hour and minute for Date.
function Sub_Second (Date : Time)
return Second_Duration;
Returns the fraction of second for Date (this has the same accuracy as
Day_Durection). The value returned is always less than 1.0.
Add at the end of 9.6.1 (62/2)
If Seconds_Of is called with a Sub_Second value of 1.0, the value
returned is equal to the value of Seconds_Of for the next second with
a Sub_Second value of 0.0.
Add at the end of 9.6.1 (64/2)
The value returned in the Sub_Second parameter is always less
than 1.0.
Move 9.6.1 (65/2-66/2) below.
Add at the end of 9.6.1 (68/2)
If Time_Of is called with a Sub_Second value of 1.0, the value
returned is equal to the value of Time_Of for the next second with
a Sub_Second value of 0.0.
Replace 9.6.1(69/2-74/4) by [this includes the previous 9.6.1(65-66/2)]:
function Time_Of (Year : Year_Number;
Month : Month_Number;
Day : Day_Number;
Seconds : Day_Duration := 0.0;
Leap_Second: Boolean := False;
Time_Zone : Time_Zones.Time_Offset := 0)
return Time;
Returns a Time built from the date and time values, relative to the
specified time zone offset. Time_Error is raised if Leap_Second is True,
and Seconds is not appropriate for a Leap_Second. If Time_Of is called with
a Seconds value of 86_400.0, the value returned is equal to the value of
Time_Of for the next day with a Seconds value of 0.0.
procedure Split (Date : in Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Hour : out Hour_Number;
Minute : out Minute_Number;
Second : out Second_Number;
Sub_Second : out Second_Duration;
Time_Zone : in Time_Zones.Time_Offset := 0);
Splits Date into its constituent parts (Year, Month, Day, Hour, Minute,
Second, Sub_Second), relative to the specified time zone offset. The value
returned in the Sub_Second parameter is always less than 1.0.
procedure Split (Date : in Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Hour : out Hour_Number;
Minute : out Minute_Number;
Second : out Second_Number;
Sub_Second : out Second_Duration;
Leap_Second: out Boolean;
Time_Zone : in Time_Zones.Time_Offset := 0);
If Date does not represent a time within a leap second, splits
Date into its constituent parts (Year, Month, Day, Hour, Minute,
Second, Sub_Second), relative to the specified time zone offset,
and sets Leap_Second to False. If Date represents a time within a leap
second, set the constituent parts to values corresponding to a time one
second earlier than that given by Date, relative to the specified time
zone offset, and sets Leap_Seconds to True. The value returned in the
Sub_Second parameter is always less than 1.0.
procedure Split (Date : in Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Seconds : out Day_Duration;
Leap_Second: out Boolean;
Time_Zone : in Time_Zones.Time_Offset := 0);
If Date does not represent a time within a leap second, splits
Date into its constituent parts (Year, Month, Day, Seconds), relative to
the specified time zone offset, and sets Leap_Second to False. If Date
represents a time within a leap second, set the constituent parts to values
corresponding to a time one second earlier than that given by Date,
relative to the specified time zone offset, and sets Leap_Seconds to True.
The value returned in the Seconds parameter is always less than 86_400.0.
!discussion
Although in parameters are usually given before out parameters, it is
much more convenient for the user for defaulted parameters to be last.
There is an example in the package Interfaces.C. The procedures To_C
and To_Ada have an in parameter with defaults after some out parameters.
It is therefore proposed that the procedures Split be changed.
The functions Second and Sub_Second currently have a parameter
Time_Zone. However, since the time zone is defined by a number of
minutes the values returned by Second and Sub_Second cannot depend upon
the parameter. The parameter should therefore be removed. It has been
argued that these functions are implemented by a call of Split and that
needs a parameter, but the default value of zero can be used.
Functions Hour and Minute are provided with a time zone parameter to
enable the correct values to be returned. However, there are no similar
functions Year, Month and Day. It is of course possible to use Split but
why provide Hour and Minute in that case since they can be done the same
way?
The range on the subtype Leap_Second is -999 .. 999. This is arbitrary.
In practice the values of this subtype that will arise will be less than
100. However, in principle there could be a leap second every quarter and
since there were 32 between 1901 and now the maximum possible value is
32 + 4 * (2399 - 2005 + 1) = 1612
The real advantage in having a range constraint is that it gives some
guidance to an implementation regarding how many bits to allow for this
information. Accordingly the range is made -2047 .. 2047. A nice dozen bits.
The note regarding Difference says "The number of days is calculated
midnight-to-midnight". The draft rationale notes "Maybe it means that if
I take the difference between 1am on Monday and 11pm on Wednesday then I
get just one day (midnight Monday to midnight Tuesday) and then the
seconds would be for 46 hours which could overflow Duration." Clearly this
note must be a hangover from some previous incarnation. It should be removed.
Some clarification might be helpful however. The formula given in 9.6.1(44/2),
namely
if Days = 0 then Seconds + Duration(Leap_Seconds) = Calendar."-"(Left, Right)
sort of does this by implying that the leap seconds are accounted for in
Leap_Sconds) and not in Seconds. An existing AARM note confirms this. This note
has been strengthened by a parenthetic remark in the normative text. Note that
this formula says nothing about what happens if Days /= 0.
It also confirms that Calendar."-" returns 86401 for the difference between
the same time on successive days if there was a leap second. Thus
Calendar."-"(Time_Of(1985, 7, 1, 0.0), Time_Of(1985, 6, 30, 0.0))
for a program in Paris using the local clock returns 86401 seconds because
of the leap second at 10pm local time (heure d'ete) on 30 June 1985.
So we need to add that the absolute value of Seconds produced by Difference
is never 86_400.0.
Also we need to add somewhere that for three functions Split the out
parameter Sub_Second is never 1.0, and for the other Split the out
parameter Seconds is never 86_400.0. Also that if Time_Of or Seconds_Of
is given a parameter 1.0 for Sub_Second then the time constructed is
for the next Second and that if the other Time_Of is given a parameter
86_400.0 for Seconds then the time constructed is for the next day. Finally,
we need to add that the function Sub_Second never returns 1.0. The
corresponding information for the package Calendar is all in 9.6(25). It has
been added to the discussion for each subprogram which is tedious but clear.
As explained in the proposal section, the vagaries of the International
Date Line means that locations can have more than a relative 24 hour time
offset. Moreover, locations in opposite hemispheres can have daylight saving
in opposite directions. The range of Time Offset is therefore increased to 28
hours which is generous but surely enough.
There is one other anomaly that this AI does not address. There is no
procedure Split which delivers Year, Month, Day and Seconds but not
Leap_Seconds and has a parameter Time_Zone. This is perhaps because the
procedure Calendar.Split already has no Leap Seconds parameter. But that
has no Time_Zone and so the combinations are not complete. Yet another
Split could be added making 5 in the package Formatting. It might be an
improvement to change the identifier of the Split acting on Seconds to
something else anyway, say, Split_Seconds. At least that would make some
differentiation.
!example
(See discussion.)
!corrigendum 9.6.1(1)
@dinsc
This is dummy content to force a conflict; the real changes are in the conflict
text.
!ACATS test
!appendix
*************************************************************