This chapter describes the facilities for manipulating dates and times, including getting and setting the date and time, and conversions between formats.
Module Time
provides facilites for time stamp and time interval
manipulation.
A time stamp represents a particular instant in time.
A time interval is the duration between two instants read on the same time scale.
Another way to view time stamps and intervals is to consider them in the context of a one-dimensional vector space: A time stamp is a point, a time interval a vector. Seen in this way, some functions perform vector arithmetic on time intervals.
Please note: Date and time modules refer to UTC, which is Coordinated Universal Time (or Universal Time Coordinated). UTC replaces Greenwich Mean Time (GMT) and is recommended for all general timekeeping applications. UTC and GMT are effectively equivalent; the difference being that UTC is adjusted by an integral number of seconds called leap seconds (see http://www.boulder.nist.gov/timefreq/glossary.htm for more precise definitions).
No provision is made for leap seconds in the date and time modules.
The following constants are defined:
Module Time
declares the following types for time intervals and time
stamps:
The maximum number of milliseconds in an interval is the value
msecPerDay
.
The fields are defined as follows:
LONGINT
LONGINT
The following are operations on Interval
:
(VAR int: Interval; days, msecs: LONGINT)
Interval
int with
days days and msecs milliseconds.
Pre-condition: msecs is not negative.
(VAR a: Interval)
Add (b: Interval)
(VAR a: Interval)
Sub (b: Interval)
Example:
VAR int1, int2: Time.Interval; Time.InitInterval(int1, 10, 0); Time.InitInterval(int2, 5, 0); => int2.dayInt = 5, int2.msecInt = 0 int1.Add(int2); (* == int1 = int1 + int2 *) => int1.dayInt = 15, int1.msecInt = 0 int1.Add(int1); (* == int1 = int1 + int1 *) => int1.dayInt = 30, int1.msecInt = 0 int1.Sub(int2); (* == int1 = int1 - int2 *) => int1.dayInt = 25, int1.msecInt = 0 Time.InitInterval(int1, 0, 43200000); (* == 12 hours *) => int1.dayInt = 0, int1.msecInt = 43200000 int1.Add(int1); (* 12 hrs + 12 hrs = 24 hrs == 1 day *) => int1.dayInt = 1, int1.msecInt = 0 Time.InitInterval(int2, 0, 1800000); (* == 30 minutes *) => int2.dayInt = 0, int2.msecInt = 1800000 int2.Add(int2); (* 30 mins + 30 mins = 60 mins == 1 hr *) => int2.dayInt = 0, int2.msecInt = 3600000 int1.Sub(int2); (* 24 hrs - 1 hr = 23 hrs == 82800000 *) => int1.dayInt = 0, int1.msecInt = 82800000
(VAR a: Interval)
Cmp (b: Interval): SHORTINT
Ifa > b
, return1
Ifa = b
, return0
Ifa < b
, return-1
(VAR a: Interval)
Scale (b: LONGREAL)
(VAR a: Interval)
Fraction (b: Interval): LONGREAL
Example:
VAR int1, int2: Time.Interval; result: SHORTINT; frac: LONGREAL; Time.InitInterval(int1, 0, 82800000); (* == 23 hours *) => int1.dayInt = 0, int1.msecInt = 82800000 Time.InitInterval(int2, 0, 3600000); (* == 1 hr *) => int2.dayInt = 0, int2.msecInt = 3600000 result := int1.Cmp(int2); => result = 1 (* == int1 > int2 *) result := int2.Cmp(int1); => result = -1 (* == int2 < int1 *) result := int1.Cmp(int1); => result = 0 (* == int1 = int1 *) int2.Scale(23); (* 1 hr * 23 = 23 hrs *) => int2.dayInt = 0, int2.msecInt = 82800002 (* approximately equal to 23 hrs. *) int2.Scale(2); (* 23 hrs * 2 = 46 hours *) => int2.dayInt = 1, int2.msecInt = 79199997 (* approximately == 1 day and 22 hours *) frac := int2.Fraction(int1); (* 46 hrs / 23 hrs = 2 *) => frac = 2.00000006219615 (* approx. 2 *) frac := int1.Fraction(int2); (* 23 hrs / 46 hrs = 0.5 *) => frac = 4.99999984450962E-1 (* approx. 0.5 *)
Please note: TimeStamp
is in Coordinated Universal Time
(UTC) on systems that support time zones. Without such support, it is
assumed that they refer to the local time zone with an unspecified time zone
offset.
The fields are defined as follows:
LONGINT
LONGINT
The following are operations on TimeStamp
:
(VAR t: TimeStamp; days, msecs: LONGINT)
TimeStamp
t with
days days and msecs milliseconds.
Pre-condition: msecs is not negative.
(VAR a: TimeStamp)
Add (b: Interval)
(VAR a: TimeStamp)
Sub (b: Interval)
(VAR a: TimeStamp)
Delta (b: TimeStamp; VAR c: Interval)
(VAR a: TimeStamp)
Cmp (b: TimeStamp): SHORTINT
Ifa > b
, return1
Ifa = b
, return0
Ifa < b
, return-1
Example:
VAR ts1, ts2: Time.TimeStamp; int1 : Time.Interval; result: SHORTINT; Time.InitTimeStamp(ts1, 40000, 0); => ts1.days = 40000, ts1.msecs = 0 (* == midnight 24 May 1968 *) Time.InitInterval(int1, 10, 3600000); ts1.Add(int1); => ts1.days = 40010, ts1.msecs = 3600000 (* == 1:00 3 Jun 1968 *) Time.InitInterval(int1, 5000, 21600000); (* == 5000 days, 6 hours *) ts1.Sub(int1); => ts1.days = 35009, ts1.msecs = 68400000 (* == 19:00 24 Sep 1954 *) Time.InitTimeStamp(ts2, 50000, 43200000); => ts1.days = 50000, ts1.msecs = 43200000 (* == noon 10 October 1995 *) ts2.Delta(ts1, int1); => int1.dayInt = 14990, int1.msecInt = 61200000 result := ts2.Cmp(ts1); => result = 1 (* == ts2 > ts1 i.e., ts2 occurs after ts1 *)
The module JulianDay
provides facilities for convertion between day/
month/ year and various forms of Julian Days. Julian Days are a standard
convention used for describing dates with the least possible ambiguity.
The Julian Day Number (JDN) is a whole number representing the number of consecutive days since noon 1 January 4713 B.C. (this is Julian Day 0).
The Julian Date (JD) is an extension of Julian Day Number, which includes a fractional part representing the elapsed fraction of a day since the preceding noon.
The Modified Julian Day (MJD) begins instead at midnight (in keeping with more standard conventions) 17 November 1858. This allows the first two digits of the Julian Day to be removed; that is, this date is Julian Day 2400000. So,
MJD = JD - 2400000.5
The Modified Julian Date is the Julian Date minus 2400000.5.
The Truncated Julian Day (TJD) is the Modified Julian Day truncated to four digits. When TJD first came into use, its origin date (i.e., "epoch") was at midnight 24 May 1968 (i.e., JDN 2440000). However, it "recycled" at midnight 10 October 1995 (i.e., JDN 2450000), so currently
TJD = MJD - 50000
Please note: The various Julian Days are integer values and are distinct from Julian Dates, which are real number values. You should keep this in mind when using the facilities in module
JulianDay
.
Several constants are provided for use in Julian Day and Date calculations:
2400000.5D0
.)
The following is provided to test for use of the Gregorian calendar:
The Gregorian Calendar is the calendar system now in general use throughout the world. It was adopted because the Julian Calendar (used in the Roman empire and then by the Roman Catholic Church) accumulated an error of one day every 128 years (thus it is currently 13 days behind the Gregorian Calendar).
The Gregorian Calendar (first prescribed in 1582 by Pope Gregory XIII) adjusts the Julian year to the astronomical year by dropping three leap years every 400 years. That is, at the end of each century, there is no leap year, except in the years 1600, 2000, 2400, and so forth.
TRUE
when the Gregorian Calendar is being
used by module JulianDay
. See also the procedure
SetGregorianStart
.
Conversion facilities are provided as follows:
(day, month: SHORTINT; year: INTEGER): LONGREAL
(jd: LONGREAL; VAR day, month: SHORTINT; VAR year: INTEGER)
Algorithms for DateToJD
and JDToDate
by William H. Jefferys
(with some modifications) at
http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
Example:
VAR date: LONGREAL; day, month: SHORTINT; year: INTEGER; date := JulianDay.DateToJD(10, 10, 1995); => date = 2450000.5 JulianDay.JDToDate(date, day, month, year); => day = 10, month = 10, year = 1995 date := JulianDay.DateToJD(17, 11, 1858); => date = 2400000.5 JulianDay.JDToDate(date, day, month, year); => day = 17, month = 11, year = 1858
(day, month: SHORTINT; year: INTEGER): LONGINT
(jd: LONGINT; VAR day, month: SHORTINT; VAR year: INTEGER)
Example:
VAR days: LONGINT; day, month: SHORTINT; year: INTEGER; days := JulianDay.DateToDays(10, 10, 1995); => days = 50000 JulianDay.DaysToDate(days, day, month, year); => day = 10, month = 10, year = 1995 days := JulianDay.DateToDays(17, 11, 1858); => days = 0 JulianDay.DaysToDate(days, day, month, year); => day = 17, month = 11, year = 1858 days := JulianDay.DateToDays(8, 4, 1513); => days = -126222 JulianDay.DaysToDate(days, day, month, year); => day = 8, month = 4, year = 1513
(day, month: SHORTINT; year: INTEGER): LONGINT
(jd: LONGINT; VAR day, month: SHORTINT; VAR year: INTEGER)
Example:
VAR days: LONGINT; day, month: SHORTINT; year: INTEGER; days := JulianDay.DateToTJD(10, 10, 1995); => days = 0 JulianDay.TJDToDate(days, day, month, year); => day = 10, month = 10, year = 1995 days := JulianDay.DateToTJD(25, 12, 1997); => days = 807 JulianDay.TJDToDate(days, day, month, year); => day = 25, month = 12, year = 1997 days := JulianDay.DateToTJD(17, 11, 1858); => days = -50000 JulianDay.TJDToDate(days, day, month, year); => day = 17, month = 11, year = 1858
(day, month: SHORTINT; year: INTEGER)
The default date used is `3 Sep 1752' (when the Gregorian Calendar was adopted in England). (At that time, the Julian Calendar was 11 days behind the Gregorian Calendar. And so, `3 Sep 1752' according to the Julian Calendar is `14 Sep 1752' according the the Gregorian Calendar.)
Example:
VAR date: LONGREAL; day, month: SHORTINT; year: INTEGER; date := JulianDay.DateToJD(2, 9, 1752); => date = 2361220.5 JulianDay.SetGregorianStart(15, 10, 1582); (* move start date to before `3 Sep 1752' *) JulianDay.JDToDate(date, day, month, year); => day = 13, month = 9, year = 1752 (* When Gregorian start date occurs at an earlier date, Julian Calendar date `2 Sep 1752' is corrected to the Gregorian date `13 Sep 1752'. *)
Module SysClock
provides facilities for accessing a system clock that
records the date and time of day. This includes a DateTime
type,
which represents a system-independent time format. Note that the module
Calendar
provides additional operations for DateTime
.
Please note:
summerTimeFlag
is present for information only. UTC
can always be obtained by subtracting the zone
(time zone) value from
the time data, regardless of the value of the summerTimeFlag
.
However, its presence does allow a program to know whether or not the date
and time data represents standard time for that location, or "summer time".
A program could therefore be written to change the system clock to summer
time automatically on a certain date, provided it had not already been
changed.
The following constants are defined:
The following constants are used as possible time zone values for
zone
:
The following constants are used as possible daylight savings mode values
for
summerTimeFlag
:
INTEGER
SHORTINT
SHORTINT
SHORTINT
SHORTINT
SHORTINT
INTEGER
maxSecondParts
' representing parts of a
second in milliseconds.
INTEGER
zoneMin
..zoneMax
'. This represents
a time zone differential factor, which is the number of minutes to add to
local time to obtain UTC or is set to localTime
when time zones are
inactive.
Please note: `-780..720' is the typical range for zone
.
SHORTINT
unknown
, active
, and inactive
are provided as possible
values.
The following procedures are provided in module SysClock
:
(): BOOLEAN
TRUE
if there is a system clock, which the
program is permitted to read. Otherwise, it returns FALSE
.
(): BOOLEAN
TRUE
if there is a system clock, which the
program is permitted to set. Otherwise, it returns FALSE
.
(d: DateTime): BOOLEAN
TRUE
if the value of d represents a valid
date and time. Otherwise, it returns FALSE
.
(VAR userData: DateTime)
If an error occurs, userData is set to `1 Jan 1970'.
(userData: DateTime)
SetClock
has no effect.
The behavior of SetClock
is undefined if userData represents a
invalid date and time.
(VAR c: DateTime)
summerTimeFlag
and time
zone zone
for calendar date c. This assumes that c
describes a valid local time. The previous values of summerTimeFlag
and zone
are ignored and are overwritten by a call to
MakeLocalTime
.
Please note:
zone
will be set to the unspecified localTime
value
, and summerTimeFlag
will be set to unknown
.
Module Calendar
provides facilities for manipulation of dates and
times. These facilities include procedures to convert between
SysClock.DateTime
and Time.TimeStamp
, as well as conversions
between DateTime
and various string formats.
The following constants are defined for the days of the week:
The following procedures are used to initialize instances of
DateTime
:
(VAR c: SysClock.DateTime; d, m: SHORTINT; y: INTEGER; h, min, s: SHORTINT)
year
y > 0
.
month
day
hour
minute
second
The other fields of c are set as follows:
fractions
is set to 0
.
zone
is set to the number of minutes needed to add to local time to
obtain UTC.
summerTimeFlag
is set to one of active
, inactive
, or
unknown
.
Please note: SetLocalTime
utilizes
SysClock.MakeLocalTime
to obtain time zone and daylight savings mode
information. All restrictions on MakeLocalTime
also apply to
SetLocalTime
.
Example:
VAR c: SysClock.DateTime; Calendar.SetLocalTime(c, 31, 12, 1997, 15, 30, 00); => c = Wednesday, 31 Dec 1997, 15:30:00.0
(VAR c: SysClock.DateTime; d, m: SHORTINT; y: INTEGER; h, min, s: SHORTINT)
SetLocalTime
except for the following differences:
c.zone
is always set to 0
.
c.summerTimeFlag
is always set to inactive
.
The following procedures are used to convert between
SysClock.DateTime
and Time.TimeStamp
:
(VAR c: SysClock.DateTime; s: Time.TimeStamp)
c.zone
and c.summerTimeFlag
are set as in SetLocalTime
).
Example:
VAR c: SysClock.DateTime; ts: Time.TimeStamp; Time.InitTimeStamp(ts, 50000, 43200000); (* == noon 10 October 1995 UTC *) Calendar.GetTimeStamp(c, ts); => c = Tuesday, 10 Oct 1995, 08:00:00 => c.zone = 240 (* i.e., local time is 4 hours behind UTC *)
(c: SysClock.DateTime; VAR t: T.TimeStamp)
c
to a time stamp t.
The following functions provide useful information about a particular
DateTime
value:
(c: SysClock.DateTime): SHORTINT
(c: SysClock.DateTime): BOOLEAN
TRUE
if c occurs within a leap year.
Otherwise, it returns FALSE
.
(c: SysClock.DateTime): SHORTINT
(c: SysClock.DateTime; startday: SHORTINT): INTEGER
(c: SysClock.DateTime): INTEGER
Example:
VAR c: SysClock.DateTime; day, week, dayOfYear, daysInMon: INTEGER; Calendar.SetLocalTime(c, 31, 12, 1996, 12, 00, 00); => c = Tuesday, 31 Dec 1996, 12:00:00 day := Calendar.DayOfWeek(c); => day = Calendar.tuesday week := Calendar.WeekNumber(c, Calendar.sunday); => week = 1 dayOfYear := Calendar.DayOfYear(c); => dayOfYear = 366 IF Calendar.IsLeapYear(c) THEN ... => TRUE Calendar.SetLocalTime(c, 31, 12, 1997, 15, 30, 00); => c = Wednesday, 31 Dec 1997, 15:30:00 day := Calendar.DayOfWeek(c); => day = Calendar.wednesday week := Calendar.WeekNumber(c, Calendar.sunday); => week = 53 dayOfYear := Calendar.DayOfYear(c); => dayOfYear = 365 IF Calendar.IsLeapYear(c) THEN ... => FALSE Calendar.SetLocalTime(c, 1, 2, 1996, 00, 00, 00); => c = Thursday, 1 Feb 1996, 00:00:00 IF Calendar.IsLeapYear(c) THEN ... => TRUE daysInMon := Calendar.DaysPerMonth(c); => daysInMon = 29 Calendar.SetLocalTime(c, 1, 2, 1997, 00, 00, 00); => c = Saturday, 1 Feb 1997, 00:00:00 IF Calendar.IsLeapYear(c) THEN ... => FALSE daysInMon := Calendar.DaysPerMonth(c); => daysInMon = 28
The following procedures are used to convert between
SysClock.DateTime
and time-formatted strings:
(VAR c: SysClock.DateTime; pattern: ARRAY OF CHAR; VAR dateStr: ARRAY OF CHAR)
Normal characters appearing in pattern are copied verbatim to the output string dateStr; this can include multibyte character sequences. Conversion specifiers are introduced by a `%' character, and are replaced in the output string as follows:
Example:
VAR c: SysClock.DateTime; str: ARRAY 256 OF CHAR; (* c initialized to Wednesday, 25 Dec 1996, 15:30:00 *) Calendar.TimeToStr(c, "%A, %D %b %Y, %H:%M:%S", str); => str = "Wednesday, 25 Dec 1996, 15:30:00" Calendar.TimeToStr(c, "%a, %d/%m/%y, %H:%M:%S %Z", str); => str = "Wed, 25/12/96, 15:30:00 UTC-0500" Calendar.TimeToStr(c, "%A, %D %B %Y, %I:%M:%S %p", str); => str = "Wednesday, 25 December 1996, 03:30:00 PM" Calendar.TimeToStr(c, "%b %D, %Y is %A and the %jth day.", str); => str = "Dec 25, 1996 is Wednesday and the 360th day."
(VAR c: SysClock.DateTime; dateStr: ARRAY OF CHAR; pattern: ARRAY OF CHAR): BOOLEAN
TimeToStr
procedure. However,
only date and time components are used in the conversion; any other
information, such as the day of the week and the week number, are ignored.
For names appearing in dateStr, upper and lower-case distinctions are ignored.
Unspecified time or date components are set to the lower-bound value for that component (after adjustment for the current time zone): For example, incomplete times will assume the zero time for missing time elements; and missing date elements will assume the corresponding date element from the reference date `1 Jan 1970'.
If dateStr is successfully parsed into a valid calendar date according
to the pattern, StrToTime
returns TRUE
. Otherwise, it
returns FALSE
.
Example:
VAR c: SysClock.DateTime; IF Calendar.StrToTime(c, "Sunday, Oct 12, 1995", "%A, %b %D, %Y") THEN => TRUE, c = Thursday, 12 Oct 1995, 00:00:00 (* Note that day of week is ignored, and correct value assigned to c *) IF Calendar.StrToTime(c, "jul 4, 1776", "%b %D, %Y") THEN => TRUE, c = Thursday, 4 Jul 1776, 00:00:00 IF Calendar.StrToTime(c, "3:30 pm, 25 December 96", "%i:%M %p, %D %B %y") THEN => TRUE, c = Wednesday, 25 Dec 1996, 15:30:00 IF Calendar.StrToTime(c, "1963 14:15:30", "%Y %H:%M:%S") THEN => TRUE, c = Tuesday, 1 Jan 1963, 14:15:30 IF Calendar.StrToTime(c, "05/30/97", "%m/%d/%y") THEN => TRUE, c = Friday, 30 May 1997, 00:00:00 IF Calendar.StrToTime(c, "31 Feb 1997", "%D %b %Y") THEN => FALSE, c = undefined
Go to the first, previous, next, last section, table of contents.