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.