Version 1.6 of ais/ai-00427.txt

Unformatted version of ais/ai-00427.txt version 1.6
Other versions for file ais/ai-00427.txt

!standard 9.6.1(1)          05-07-20 AI95-00427/05
!class amendment 05-04-10
!status Amendment 200Y 05-05-05
!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 non-negative. {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)
Insert new clause:
This is dummy content to force a conflict; the real changes are in the conflict text.
!ACATS test
!appendix

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

Questions? Ask the ACAA Technical Agent