162 lines
6.5 KiB
Plaintext
162 lines
6.5 KiB
Plaintext
|
Scsh time interface
|
||
|
Olin Shivers
|
||
|
November, 1994
|
||
|
|
||
|
* Discussion
|
||
|
|
||
|
Jargon:
|
||
|
"UTC" and "UCT" stand for "universal coordinated time," which is the
|
||
|
official name for what is colloquially referred to as "Greenwich Mean
|
||
|
Time."
|
||
|
|
||
|
Posix allows a single time zone to specify *two* different offsets from
|
||
|
UTC: one standard one, and one for "summer time." Summer time is frequently
|
||
|
some sort of daylight savings time.
|
||
|
|
||
|
The scsh time package consistently uses this jargon: we never say
|
||
|
"gmt" or "dst;" we always say "utc" and "summer time."
|
||
|
|
||
|
We have two types: time and date.
|
||
|
|
||
|
A TIME specifies an instant in the history of the universe.
|
||
|
It is location and time-zone independent. A time is specified
|
||
|
by giving the number of elapsed seconds since the Unix "epoch"
|
||
|
(Midnight, January 1, 1970 UTC).
|
||
|
|
||
|
A DATE is a name for an instant in time that is specified
|
||
|
relative to some location/time-zone in the world, for example
|
||
|
Friday October 31, 1994 3:47:21 pm
|
||
|
What instant this date specifies depends on where you are. If I phone a Hong
|
||
|
Kong friend from Cambridge, Massachusetts, then the current TIME is the same
|
||
|
for both of us, but it has different DATES -- Hong Kong is 12 hours ahead
|
||
|
of Cambridge.
|
||
|
|
||
|
(define-record date ; A Posix tm struct
|
||
|
seconds ; Seconds after the minute (0-59)
|
||
|
minute ; Minutes after the hour (0-59)
|
||
|
hour ; Hours since midnight (0-23)
|
||
|
month-day ; Day of the month (1-31)
|
||
|
month ; Months since January (0-11)
|
||
|
year ; Years since 1900
|
||
|
summer? ; Summer (e.g., Daylight Savings) time in effect?
|
||
|
week-day ; Days since Sunday (0-6) These two fields
|
||
|
year-day) ; Days since Jan. 1 (0-365) are redundant.
|
||
|
|
||
|
(make-date seconds minute hour month-day month year
|
||
|
[summer? week-day year-day])
|
||
|
When making a DATE, the last three elements of the record are optional,
|
||
|
and default to #f, 0, and 0 respectively. This is useful when creating
|
||
|
a DATE record to pass to TIME->DATE.
|
||
|
|
||
|
Notice that the value of SUMMER? resolves amiguous boundary cases. For
|
||
|
example, on the morning of the Fall daylight savings change-over, 1:00am -
|
||
|
2:00am happens twice. Hence the date 1:30:00 on this morning can specify two
|
||
|
different seconds; the SUMMER? flag says which one.
|
||
|
|
||
|
Specifying time zones:
|
||
|
Several time procedures time time zones as arguments. When optional,
|
||
|
the time zone defaults to local time zone. Otherwise the time zone
|
||
|
can be one of:
|
||
|
#f Local time
|
||
|
Integer Seconds of offset from UTC. For example,
|
||
|
New York City is -18000 (-5 hours), San Francisco
|
||
|
is -28800 (-8 hours).
|
||
|
String A Posix time zone string understood by the OS
|
||
|
(i.e., the sort of time zone assigned to the $TZ
|
||
|
environment variable).
|
||
|
An integer time zone gives the number of seconds you must add to UTC
|
||
|
to get time in that zone. It is *not* "seconds west" of UTC -- that flips
|
||
|
the sign.
|
||
|
|
||
|
To get UTC time, use a time zone of either 0 or "UCT0".
|
||
|
|
||
|
|
||
|
* Procedures
|
||
|
|
||
|
(utime) -> [secs usecs]
|
||
|
The current time. UTIME provies micro-second resolution.
|
||
|
Sub-second resolution is not provided by Posix, but is in BSD.
|
||
|
If the OS does not support sub-second resolution, the USECS value
|
||
|
is always 0.
|
||
|
|
||
|
(date) -> date
|
||
|
The current date, in the local time zone.
|
||
|
(date [time tz]) -> date
|
||
|
Converts the time to the date as specified by the time zone TZ.
|
||
|
TIME defaults to the current time; TZ defaults to local time,
|
||
|
and is as described above.
|
||
|
|
||
|
(time) -> int
|
||
|
The current time.
|
||
|
(time [date tz]) -> int
|
||
|
Converts a date to a time as specified by the time zone TZ.
|
||
|
DATE defaults to the current date; TZ defaults to local time,
|
||
|
and is as described above.
|
||
|
|
||
|
A DATE record is overconstrained; TIME ignores the DATE's
|
||
|
WEEK-DAY and YEAR-DAY fields.
|
||
|
|
||
|
When passed to TIME, the SUMMER? field has the following meaning:
|
||
|
#f Resolve an ambiguous time in favor of non-summer time.
|
||
|
#t Resolve an ambiguous time in favor of summer time.
|
||
|
This is useful in boundary cases during the change-over. For example,
|
||
|
in the Fall, when US daylight savings time changes over at 2:00 am,
|
||
|
1:30 am happens twice -- it names two instants in time, an hour apart.
|
||
|
|
||
|
Outside of these boundary cases, the SUMMER? flag is *ignored*. For
|
||
|
example, if the standard/summer change-overs happen in the Fall and the
|
||
|
Spring, then the value of SUMMER? is ignored for a January or July date.
|
||
|
A January date would be resolved with standard time, and a July date with
|
||
|
summer time, regardless of the SUMMER? value.
|
||
|
|
||
|
The SUMMER? flag is also ignored if the time zone doesn't have a summer
|
||
|
time -- for example, an integer time zone, or simple UTC.
|
||
|
|
||
|
|
||
|
(date->string date) -> string
|
||
|
(time->string time [tz]) -> string
|
||
|
(format-date fmt date [tz]) -> string
|
||
|
These have Posix analogs. FORMAT-DATE's time zone argument is only
|
||
|
used when one requests the time zone in the formatted string.
|
||
|
|
||
|
(utc-offset [time tz])
|
||
|
Returns the offset from UTC of time zone TZ at instant TIME.
|
||
|
TIME defaults to the current time; TZ defaults to local time,
|
||
|
and is as specified above.
|
||
|
|
||
|
The offset is the number of seconds you add to UTC time to get
|
||
|
local time.
|
||
|
|
||
|
Note: Be aware that other time interfaces (e.g., the BSD C interface)
|
||
|
give offsets as seconds *west* of UTC, which flips the sign. The scsh
|
||
|
definition is chosen for arithmetic simplicity. It's easy to remember
|
||
|
the definition of the offset: what you add to UTC to get local.
|
||
|
|
||
|
(time-zone [summer? tz])
|
||
|
Returns the name of the time zone as a string. SUMMER? is
|
||
|
used to choose between the summer name and the standard name (e.g.,
|
||
|
"EST" and "EDT"). SUMMER? is interpreted as follows:
|
||
|
Integer A TIME value. The variant in use at that time
|
||
|
is returned.
|
||
|
#f The standard time name is returned.
|
||
|
Otherwise The summer time name is returned.
|
||
|
SUMMER? defaults to the case that pertains at the time of the call.
|
||
|
It is ignored if the time zone doesn't have a summer variant.
|
||
|
|
||
|
We need a general date/time parser.
|
||
|
|
||
|
DATE has two more fields: tz-secs and tz-name.
|
||
|
TIME->DATE: These are set.
|
||
|
tz-secs is the offset from UTC for the instant this date specifies.
|
||
|
It includes summer time adjustments.
|
||
|
|
||
|
TZ=#f: tz-name is constructed from tzname[] and tz-secs.
|
||
|
TZ string: tz-name is constructed from tzname[] and tz-secs.
|
||
|
TZ int: tz-name is of form UTChh:mm:ss ?? or #f ??
|
||
|
|
||
|
DATE->TIME:
|
||
|
tz-secs integer: It is used for conversion.
|
||
|
summer? is ignored.
|
||
|
otw: time zone taken from tz-name, with #f meaning "local time."
|
||
|
summer? is used, if the time zone is a dual one.
|