BasicTime.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Andrew Birrell August 8, 1983 10:56 am
Levin, September 22, 1983 11:40 am
Russ Atkinson (RRA) February 1, 1985 5:53:24 pm PST
Beach, February 27, 1985 10:17:35 am PST
DIRECTORY
PrincOps USING [aRCLK, zMISC];
BasicTime: CEDAR DEFINITIONS
= BEGIN
Errors
OutOfRange: ERROR;
Some conversion was given a time which could not be converted. The valid ranges are:
Alto: 1901 to 2036 (232 seconds)
NS: 1968 to 2103 (Alto offset to 1968)
GMT: 1968 to 2036 (231 seconds, same expiry date as Alto)
Unpacked: approximately forever
TimeNotKnown: ERROR;
Raised by "Now" if we don't know the time.
TimeParametersNotKnown: ERROR;
Raised by "Unpack" if we don't know the time zone or daylight savings time information.
Part I: Fine-grain timer
Pulses: TYPE = LONG CARDINAL;
Pulses are a machine dependent measure of elapsed time. One pulse is somewhere between 1 microseconds and 100 microseconds long. The actual pulse frequency is processor dependent. See the ProcessorFace comments.
GetClockPulses: PROC RETURNS[Pulses]
= TRUSTED MACHINE CODE { PrincOps.zMISC, PrincOps.aRCLK };
Returns the current value of the fine-grain clock
PulsesToMicroseconds: PROC[Pulses] RETURNS[LONG CARDINAL];
Returns the number of microseconds. The calculation is careful to avoid unnecessary loss of precision. Undefined if the result would exceed 232-1 microseconds (about one hour).
PulsesToSeconds: PROC[Pulses] RETURNS[REAL];
Returns the number of seconds. Beware: reals have only 24 bits of precision, so the fractional part of the result is not as accurate as calling PulsesToMicroseconds. However, the result never overflows.
MicrosecondsToPulses: PROC[LONG CARDINAL] RETURNS[Pulses];
Part II: Packed times
GMT: TYPE[2];
"GMT" provides a compact representation of a time, specified in seconds, which is efficient to obtain, to compare, and to modify.
nullGMT: GMT = LOOPHOLE[LAST[INT]];
A value such that ~(nullGMT IN [earliestGMT..latestGMT]). Illegal as argument to most procedures.
earliestGMT: GMT;
the earliest possible value of GMT (beginning of 1968)
latestGMT: GMT;
the latest possible value of GMT (sometime in 2036)
Now: PROC RETURNS [GMT];
The present time, if known. Raises "TimeNotKnown" if the time isn't known.
Period: PROC[from, to: GMT] RETURNS [INT];
The number of seconds between the times. Positive iff "to" is later than "from". Since the range of GMT is only 31 bits, the interval can always be represented in an INT.
Update: PROC[base: GMT, period: INT] RETURNS [GMT];
Returns the time "period" seconds later than "base" (earlier iff "period" is negative). Raises "OutOfRange" if the result would be before 1968 or after 2036.
ToPupTime: PROC[GMT] RETURNS[LONG CARDINAL];
Returns time according to the Alto/Pup time standard. No errors.
ToNSTime: PROC[GMT] RETURNS [LONG CARDINAL];
Returns time according to the Xerox NS protocol time standard. No errors.
FromPupTime: PROC[LONG CARDINAL] RETURNS[GMT];
Accepts time according to the Alto/Pup time standard. Raises "OutOfRange" for times earlier than 1968.
FromNSTime: PROC[LONG CARDINAL] RETURNS[GMT];
Accepts time according to the Xerox NS protocol time standard. Raises "OutOfRange" for times beyond about 2036.
Part III: Unpacked times
Unpacked: TYPE = RECORD[
"Unpacked" provides a representation of a time, specified in seconds, which is easy to interpret in ways meaningful to humans, such as years/months/days/etc. Each field has an default "unspecified" value for use by Time.SmartPack.
year: [0..2050] ← 0,
month: MonthOfYear ← unspecified,
day: [0..daysPerMonth] ← 0, -- first day of the month is 1
hour: [0..hoursPerDay] ← 24,
minute: [0..minutesPerHour] ← 60,
second: [0..secondsPerMinute] ← 60,
When calling "Pack": "zone" and "dst" are either ignored or override local time parameters
zone: Zone ← unspecifiedZone,
dst: {yes, no, unspecified} ← unspecified,
Remaining fields are redundant, and are always ignored by "Pack"
weekday: DayOfWeek ← unspecified,
secondsThisYear: INTLAST[INT],
daysThisYear: [0..daysPerYear] ← daysPerYear
];
MonthOfYear: TYPE = {January, February, March, April, May, June, July, August, September, October, November, December, unspecified};
DayOfWeek: TYPE = {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday, unspecified};
Zone: TYPE = [-720..+721]; -- California is +60*8. 721 means unspecified.
unspecifiedZone: Zone = +721;
daysPerMonth: INT = 31;
hoursPerDay: INT = 24;
minutesPerHour: INT = 60;
secondsPerMinute: INT = 60;
daysPerYear: INT = 366;
secondsPerYear: INT = secondsPerMinute * minutesPerHour * hoursPerDay * daysPerYear;
Unpack: PROC[time: GMT] RETURNS[Unpacked];
If the local zone isn't known, assumes zone 0 and non-DST (GMT).
Pack: PROC[unpacked: Unpacked] RETURNS[GMT];
Raises "TimeParametersNotKnown" if the time zone or DST info aren't sufficiently specified; raises "OutOfRange" for times before 1968 or after 2036. If unpacked.zone = unspecifiedZone, then the "zone" field of "unpacked" is ignored and the local time parameters are used; if unpacked.dst = unspcified, then DST is calculated using the local time parameters; otherwise the values from "unpacked" are used and the local values are ignored.
Part IV: Finding and setting time and zone/dst information
ZoneAndDST: TYPE = RECORD[
zone: Zone,
beginDST, endDST: [0..366] -- DST starts/stops at 2 a.m.
];
SetZoneAndDST: PROC[ZoneAndDST];
Asserts that these are the local time zone and DST parameters. Not a call for mere mortals: the package usually does an adequate job of determining these parameters for itself.
GetZoneAndDST: PROC RETURNS[ZoneAndDST];
Returns the currently believed local zone and DST parameters. "unspecifiedZone" is returned if they aren't currently known.
SetTime: PROC;
Make best efforts to set the correct time from suitable sources (e.g. Pup or NS time servers). If the ZoneAndDST parameters are currently unknown, also sets them. Not a call for mere mortals: the effect of this call usually happen automatically when needed.
END.