# 9.6 Delay Statements, Duration, and Time

This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue

[ A `delay_statement`

is used to block further execution until a specified *expiration time* is reached. The expiration time can be specified either as a particular point in time (in a `delay_until_statement`

), or in seconds from the current time (in a `delay_relative_statement`

). The language-defined package Calendar provides definitions for a type Time and associated operations, including a function Clock that returns the current time. ]

#### Syntax

2`delay_statement`

` ::= `

`delay_until_statement`

| `delay_relative_statement`

3`delay_until_statement`

` ::= `

**delay until** *delay_*`expression`

;

4`delay_relative_statement`

` ::= `

**delay** *delay_*`expression`

;

#### Name Resolution Rules

5The expected type for the *delay_*`expression`

in a `delay_relative_statement`

is the predefined type Duration. The *delay_*`expression`

in a `delay_until_statement`

is expected to be of any nonlimited type.

#### Legality Rules

6/3There can be multiple time bases, each with a corresponding clock, and a corresponding *time type*. The type of the *delay_*`expression`

in a `delay_until_statement`

shall be a time type — either the type Time defined in the language-defined package Calendar (see below), the type Time in the package Real_Time (see D.8), or some other implementation-defined time type.

#### Static Semantics

7[There is a predefined fixed point type named Duration, declared in the visible part of package Standard;] a value of type Duration is used to represent the length of an interval of time, expressed in seconds. [The type Duration is not specific to a particular time base, but can be used with any time base.]

A value of the type Time in package Calendar, or of some other time type, represents a time as reported by a corresponding clock.

The following language-defined library package exists:

```
package Ada.Calendar
with Nonblocking, Global => in out synchronized is
type Time is private;
11/2subtype Year_Number is Integer range 1901 .. 2399;
subtype Month_Number is Integer range 1 .. 12;
subtype Day_Number is Integer range 1 .. 31;
subtype Day_Duration is Duration range 0.0 .. 86_400.0;
```

```
function Clock return Time;
13function Year (Date : Time) return Year_Number;
function Month (Date : Time) return Month_Number;
function Day (Date : Time) return Day_Number;
function Seconds(Date : Time) return Day_Duration;
14procedure Split (Date : in Time;
Year : out Year_Number;
Month : out Month_Number;
Day : out Day_Number;
Seconds : out Day_Duration);
15function Time_Of(Year : Year_Number;
Month : Month_Number;
Day : Day_Number;
Seconds : Day_Duration := 0.0)
return Time;
16function "+" (Left : Time; Right : Duration) return Time;
function "+" (Left : Duration; Right : Time) return Time;
function "-" (Left : Time; Right : Duration) return Time;
function "-" (Left : Time; Right : Time) return Duration;
17function "<" (Left, Right : Time) return Boolean;
function "<="(Left, Right : Time) return Boolean;
function ">" (Left, Right : Time) return Boolean;
function ">="(Left, Right : Time) return Boolean;
18Time_Error : exception;
19private
... -- not specified by the language
end Ada.Calendar;
```

#### Dynamic Semantics

20For the execution of a `delay_statement`

, the *delay_*`expression`

is first evaluated. For a `delay_until_statement`

, the expiration time for the delay is the value of the *delay_*`expression`

, in the time base associated with the type of the `expression`

. For a `delay_relative_statement`

, the expiration time is defined as the current time, in the time base associated with relative delays, plus the value of the *delay_*`expression`

converted to the type Duration, and then rounded up to the next clock tick. The time base associated with relative delays is as defined in D.9, “Delay Accuracy” or is implementation defined.

The task executing a `delay_statement`

is blocked until the expiration time is reached, at which point it becomes ready again. If the expiration time has already passed, the task is not blocked.

`delay_relative_statement`

, this case corresponds to when the value of the *delay_*

`expression`

is zero or negative.If an attempt is made to *cancel* the `delay_statement`

[(as part of an `asynchronous_select`

or abort — see 9.7.4 and 9.8)], the statement is cancelled if the expiration time has not yet passed, thereby completing the `delay_statement`

.

`asynchronous_select`

where the `triggering_statement`

is a `delay_statement`

, an attempt to cancel the delay when the `abortable_part`

completes is ignored if the expiration time has already passed, in which case the optional statements of the `triggering_alternative`

are executed. The time base associated with the type Time of package Calendar is implementation defined. The function Clock of package Calendar returns a value representing the current time for this time base. [The implementation-defined value of the named number System.Tick (see 13.7) is an approximation of the length of the real-time interval during which the value of Calendar.Clock remains constant.]

The functions Year, Month, Day, and Seconds return the corresponding values for a given value of the type Time, as appropriate to an implementation-defined time zone; the procedure Split returns all four corresponding values. Conversely, the function Time_Of combines a year number, a month number, a day number, and a duration, into a value of type Time. The operators "+" and "–" for addition and subtraction of times and durations, and the relational operators for times, have the conventional meaning.

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. The value returned by the function Seconds or through the Seconds parameter of the procedure Split is always less than 86_400.0.

{*8652/0030*} The exception Time_Error is raised by the function Time_Of if the actual parameters do not form a proper date. This exception is also raised by the operators "+" and "–" if the result is not representable in the type Time or Duration, as appropriate. This exception is also raised by the functions Year, Month, Day, and Seconds and the procedure Split if the year number of the given date is outside of the range of the subtype Year_Number.

**To be honest:**{

*8652/0106*} By "proper date" above we mean that the given year has a month with the given day. For example, February 29th is a proper date only for a leap year. We do not mean to include the Seconds in this notion; in particular, we do not mean to require implementations to check for the “missing hour” that occurs when Daylight Savings Time starts in the spring.

*8652/0030*} We allow Year and Split to raise Time_Error because the arithmetic operators are allowed (but not required) to produce times that are outside the range of years from 1901 to 2399. This is similar to the way integer operators may return values outside the base range of their type so long as the value is mathematically correct. We allow the functions Month, Day and Seconds to raise Time_Error so that they can be implemented in terms of Split.

#### Implementation Requirements

27The implementation of the type Duration shall allow representation of time intervals (both positive and negative) up to at least 86400 seconds (one day); Duration'Small shall not be greater than twenty milliseconds. The implementation of the type Time shall allow representation of all dates with year numbers in the range of Year_Number[; it may allow representation of other dates as well (both earlier and later).]

#### Implementation Permissions

28/3An implementation may define additional time types.

An implementation may raise Time_Error if the value of a *delay_*`expression`

in a `delay_until_statement`

of a `select_statement`

represents a time more than 90 days past the current time. The actual limit, if any, is implementation-defined.

`select_statement`

timeouts using a representation that does not support the full range of a time type. In particular 90 days of seconds can be represented in 23 bits, allowing a signed 24-bit representation for the seconds part of a timeout. There is no similar restriction allowed for stand-alone `delay_until_statement`

s, as these can be implemented internally using a loop if necessary to accommodate a long delay. #### Implementation Advice

30Whenever possible in an implementation, the value of Duration'Small should be no greater than 100 microseconds.

*small*of 2.0**(–14) — that is, 61 microseconds — and a range of ± 2.0**17 — that is, 131_072.0.

The time base for `delay_relative_statement`

s should be monotonic; it can be different than the time base as used for Calendar.Clock.

`delay_relative_statement`

s should be monotonic.`delay_relative_statement`

with a negative value of the *delay_*

`expression`

is equivalent to one with a zero value.`delay_statement`

can be executed by the environment task; consequently `delay_statement`

s can be executed as part of the elaboration of a `library_item`

or the execution of the main subprogram. Such statements delay the environment task (see 10.2).`delay_statement`

is an abort completion point and a potentially blocking operation, even if the task is not actually blocked.*small*of type Duration).

`delay_statement`

has no relation to System.Tick. In particular, it is possible that the clock used for the `delay_statement`

is less accurate than Calendar.Clock.#### Examples

37*Example of a relative delay statement:*

`delay 3.0; -- delay 3.0 seconds`

*Example of a periodic task:*

`declare`

use Ada.Calendar;

Next_Time : Time := Clock + Period;

-- Period is a global constant of type Duration

begin

loop -- repeated every Period seconds

delay until Next_Time;

... -- perform some actions

Next_Time := Next_Time + Period;

end loop;

end;

#### Inconsistencies With Ada 83

#### Extensions to Ada 83

#### Inconsistencies With Ada 95

#### Wording Changes from Ada 95

## 9.6.1 Formatting, Time Zones, and other operations for Time

#### Static Semantics

1/2The following language-defined library packages exist:

```
package Ada.Calendar.Time_Zones
with Nonblocking, Global => in out synchronized is
3/2-- Time zone manipulation:
4/2type Time_Offset is range -28*60 .. 28*60;
```

```
Unknown_Zone_Error : exception;
6/5function Local_Time_Offset (Date : Time := Clock) return Time_Offset;
6.1/5function UTC_Time_Offset (Date : Time := Clock) return Time_Offset
renames Local_Time_Offset;
7/2end Ada.Calendar.Time_Zones;
8/5
package Ada.Calendar.Arithmetic
with Nonblocking, Global => in out synchronized is
9/2-- Arithmetic on days:
10/2type Day_Count is range
-366*(1+Year_Number'Last - Year_Number'First)
..
366*(1+Year_Number'Last - Year_Number'First);
11/2subtype Leap_Seconds_Count is Integer range -2047 .. 2047;
```

```
procedure Difference (Left, Right : in Time;
Days : out Day_Count;
Seconds : out Duration;
Leap_Seconds : out Leap_Seconds_Count);
13/2function "+" (Left : Time; Right : Day_Count) return Time;
function "+" (Left : Day_Count; Right : Time) return Time;
function "-" (Left : Time; Right : Day_Count) return Time;
function "-" (Left, Right : Time) return Day_Count;
14/2end Ada.Calendar.Arithmetic;
15/5
with Ada.Calendar.Time_Zones;
package Ada.Calendar.Formatting
with Nonblocking, Global => in out synchronized is
16/2-- Day of the week:
17/2type Day_Name is (Monday, Tuesday, Wednesday, Thursday,
Friday, Saturday, Sunday);
18/2function Day_of_Week (Date : Time) return Day_Name;
19/2-- Hours:Minutes:Seconds access:
20/2subtype Hour_Number is Natural range 0 .. 23;
subtype Minute_Number is Natural range 0 .. 59;
subtype Second_Number is Natural range 0 .. 59;
subtype Second_Duration is Day_Duration range 0.0 .. 1.0;
21/2function Year (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Year_Number;
22/2function Month (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Month_Number;
23/2function Day (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Day_Number;
24/2function Hour (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Hour_Number;
25/2function Minute (Date : Time;
Time_Zone : Time_Zones.Time_Offset := 0)
return Minute_Number;
26/2function Second (Date : Time)
return Second_Number;
27/2function Sub_Second (Date : Time)
return Second_Duration;
28/2function Seconds_Of (Hour : Hour_Number;
Minute : Minute_Number;
Second : Second_Number := 0;
Sub_Second : Second_Duration := 0.0)
return Day_Duration;
29/2procedure Split (Seconds : in Day_Duration;
Hour : out Hour_Number;
Minute : out Minute_Number;
Second : out Second_Number;
Sub_Second : out Second_Duration);
30/2function Time_Of (Year : Year_Number;
Month : Month_Number;
Day : Day_Number;
Hour : Hour_Number;
Minute : Minute_Number;
Second : Second_Number;
Sub_Second : Second_Duration := 0.0;
Leap_Second: Boolean := False;
Time_Zone : Time_Zones.Time_Offset := 0)
return Time;
31/2function 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;
32/2procedure 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);
33/2procedure 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);
34/2procedure 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);
35/2-- Simple image and value:
function Image (Date : Time;
Include_Time_Fraction : Boolean := False;
Time_Zone : Time_Zones.Time_Offset := 0) return String;
35.1/5function Local_Image (Date : Time;
Include_Time_Fraction : Boolean := False)
return String is
(Image (Date, Include_Time_Fraction,
Time_Zones.Local_Time_Offset (Date)));
36/2function Value (Date : String;
Time_Zone : Time_Zones.Time_Offset := 0) return Time;
37/2function Image (Elapsed_Time : Duration;
Include_Time_Fraction : Boolean := False) return String;
38/2function Value (Elapsed_Time : String) return Duration;
39/2end Ada.Calendar.Formatting;
```

40/5Type 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] .

`function Local_Time_Offset (Date : Time := Clock) return Time_Offset;`

Returns, as a number of minutes, the Time_Offset of the implementation-defined time zone of Calendar , at the time Date. If the time zone of the Calendar implementation is unknown, then Unknown_Zone_Error is raised.

`procedure Difference (Left, Right : in Time;`

Days : out Day_Count;

Seconds : out Duration;

Leap_Seconds : out Leap_Seconds_Count);

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).

`function "+" (Left : Time; Right : Day_Count) return Time;`

function "+" (Left : Day_Count; Right : Time) return Time;

Adds a number of days to a time value. Time_Error is raised if the result is not representable as a value of type Time.

`function "-" (Left : Time; Right : Day_Count) return Time;`

Subtracts a number of days from a time value. Time_Error is raised if the result is not representable as a value of type Time.

`function "-" (Left, Right : Time) return Day_Count;`

Subtracts two time values, and returns the number of days between them. This is the same value that Difference would return in Days.

`function Day_of_Week (Date : Time) return Day_Name;`

Returns the day of the week for Time. This is based on the Year, Month, and Day values of Time.

`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 offset.

`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 offset.

`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 offset.

`function Hour (Date : Time;`

Time_Zone : Time_Zones.Time_Offset := 0)

return Hour_Number;

Returns the hour for Date, as appropriate for the specified time zone offset.

`function Minute (Date : Time;`

Time_Zone : Time_Zones.Time_Offset := 0)

return Minute_Number;

Returns the minute within the hour for Date, as appropriate for the specified time zone offset.

`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_Duration). The value returned is always less than 1.0.

`function Seconds_Of (Hour : Hour_Number;`

Minute : Minute_Number;

Second : Second_Number := 0;

Sub_Second : Second_Duration := 0.0)

return Day_Duration;

Returns a Day_Duration value for the combination of the given Hour, Minute, Second, and Sub_Second. This value can be used in Calendar.Time_Of as well as the argument to Calendar."+" and Calendar."–". 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.

`procedure Split (Seconds : in Day_Duration;`

Hour : out Hour_Number;

Minute : out Minute_Number;

Second : out Second_Number;

Sub_Second : out Second_Duration);

Splits Seconds into Hour, Minute, Second and Sub_Second in such a way that the resulting values all belong to their respective subtypes. The value returned in the Sub_Second parameter is always less than 1.0. If Seconds = 86400.0, Split propagates Time_Error.

`function Time_Of (Year : Year_Number;`

Month : Month_Number;

Day : Day_Number;

Hour : Hour_Number;

Minute : Minute_Number;

Second : Second_Number;

Sub_Second : Second_Duration := 0.0;

Leap_Second: Boolean := False;

Time_Zone : Time_Zones.Time_Offset := 0)

return Time;

If Leap_Second is False, returns a Time built from the date and time values, relative to the specified time zone offset. If Leap_Second is True, returns the Time that represents the time within the leap second that is one second later than the time specified by the other parameters. Time_Error is raised if the parameters do not form a proper date or time. 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.

`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;

If Leap_Second is False, returns a Time built from the date and time values, relative to the specified time zone offset. If Leap_Second is True, returns the Time that represents the time within the leap second that is one second later than the time specified by the other parameters. Time_Error is raised if the parameters do not form a proper date or time. 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;

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;

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;

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.

`function Image (Date : Time;`

Include_Time_Fraction : Boolean := False;

Time_Zone : Time_Zones.Time_Offset := 0) return String;

Returns a string form of the Date relative to the given Time_Zone. The format is "Year-Month-Day Hour:Minute:Second", where the Year is a 4-digit value, and all others are 2-digit values, of the functions defined in Calendar and Calendar.Formatting, including a leading zero, if needed. The separators between the values are a minus, another minus, a colon, and a single space between the Day and Hour. If Include_Time_Fraction is True, the integer part of Sub_Seconds*100 is suffixed to the string as a point followed by a 2-digit value.

`function Value (Date : String;`

Time_Zone : Time_Zones.Time_Offset := 0) return Time;

Returns a Time value for the image given as Date, relative to the given time zone. Constraint_Error is raised if the string is not formatted as described for Image, or the function cannot interpret the given string as a Time value.

`function Image (Elapsed_Time : Duration;`

Include_Time_Fraction : Boolean := False) return String;

Returns a string form of the Elapsed_Time. The format is "Hour:Minute:Second", where all values are 2-digit values, including a leading zero, if necessary . The separators between the values are colons. If Include_Time_Fraction is True, the integer part of Sub_Seconds*100 is suffixed to the string as a point followed by a 2-digit value. If Elapsed_Time < 0.0, the result is Image (**abs** Elapsed_Time, Include_Time_Fraction) prefixed with a minus sign. If **abs** Elapsed_Time represents 100 hours or more, the result is implementation-defined.

`function Value (Elapsed_Time : String) return Duration;`

Returns a Duration value for the image given as Elapsed_Time. Constraint_Error is raised if the string is not formatted as described for Image, or the function cannot interpret the given string as a Duration value.

#### Implementation Advice

89/2An implementation should support leap seconds if the target system supports them. If leap seconds are not supported, Difference should return zero for Leap_Seconds, Split should return False for Leap_Second, and Time_Of should raise Time_Error if Leap_Second is True.