This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. You can access the discussion via the archive of the mailing list.
~D fixed: 2003-05-30A date is a representation of a point in time in the Gregorian calendar, a 24 hour clock (with nanosecond precision) and a time zone offset from UTC. Procedures for converting between time and dates are provided, as well as for reading and writing string representations of dates.
A Time object, which is distinct from all existing types, defines a point in time or a time duration in some standard time system. The standard time systems are:
A time object consists of three components:
TIME-TAI,
  TIME-UTC, TIME-MONOTONIC,
  TIME-THREAD, TIME-PROCESS, and
  TIME-DURATION must be provided for these
  symbols. Implementations should provide constants for time type
  extensions.  
  A Date object, which is distinct from all existing types, represents a point in time as represented by the Gregorian calendar as well as by a time zone. Dates are immutable. A date consists of the following components:
A Julian Day represents a point in time as a real number of days since -4714-11-24T12:00:00Z (November 24, -4714 at noon, UTC).
A Modified Julian Day represents a point in time as a real number of days since 1858-11-17T00:00:00Z (November 17, 1858 at midnight, UTC).
The following constants are required:
time-duration 
  time-monotonic
  time-process
  time-tai
  time-thread
  time-utc
  The following procedures are required:
current-date [tz-offset] -> date
  current-julian-day -> jdn
  current-modified-julian-day -> mjdn
  current-time [time-type] -> time
  time-type system, which defaults to TIME-UTC.
  time-resolution [time-type] -> integer
  time-type system, which defaults to TIME-UTC.
The following procedures are required:
make-time type nanosecond second -> time
  time? object -> boolean
  #t if object is a time object, otherwise, #f.
  time-type time -> time-type
  time-nanosecond time -> integer
  time-second time -> integer
  set-time-type! time time-type
  set-time-nanosecond! time integer
  set-time-second! time integer
  copy-time time1 -> time2
  All of the time comparison procedures require the time objects to
be of the same type. It is an error to use these procedures on time
objects of different types. For the point-in-time measurements (e.g.,
TIME-TAI and TIME-UTC), the semantics are
described in plain text. For durations, (e.g.,
TIME-DURATION, TIME-CPU, the semantics are
described in parentheses.
The following procedures are required:
time<=? time1 time2 -> boolean
  #t if time1 is before or at (less than or equal to) time2, #f otherwise. 
  time<? time1 time2 -> boolean
  #t if time1 is before (less than) time2, #f otherwise. 
  time=? time1 time2 -> boolean
  #t if time1 at (equal) time2, #f otherwise. 
  time>=? time1 time2 -> boolean
  #t if time1 is at or after (greater than or equal to) time2, #f otherwise. 
  time>? time1 time2 -> boolean
  #t if time1 is after (greater than) time2, #f otherwise. 
The following procedures are required.
time-difference time1 time2 -> time-duration
  TIME-DURATION between time1 and time2. It is an error if time1 and time2 are of different time types. A new time object is created.
  time-difference! time1 time2 -> time-duration
  TIME-DURATION between time1 and time2. It is an error if time1 and time2 are of different time types. Time1 may be used to create the resulting TIME-DURATION object.
  add-duration time1 time-duration -> time
  add-duration! time1 time-duration -> time
  subtract-duration time1 time-duration -> time
  subtract-duration! time1 time-duration -> time
  Date objects are immutable once created. The following procedures are required.
make-date nanosecond second minute hour day month year zone-offset -> date
  date? date  -> boolean
  #t if object is a time object, otherwise, #f.
  date-nanosecond date -> integer
  date-second date -> integer
  date-minute date -> integer
  date-hour date -> integer
  date-day date -> integer
  date-month date -> integer
  date-year date -> integer
  date-zone-offset date -> integer
  date-year-day date -> integer
  date-week-day date -> integer
  date-week-number date day-of-week-starting-week -> integer
  date->julian-day date -> jd
  date->modified-julian-day date -> mjd
  date->time-monotonic date -> time-monotonic
  date->time-tai date -> time-tai
  date->time-utc date -> time-utc
  julian-day->date jd  [tz-offset] -> date
  julian-day->time-monotonic jd -> time-monotonic
  julian-day->time-tai jd -> time-tai
  julian-day->time-utc jd -> time-utc
  modified-julian-day->date mjd [tz-offset] -> date
  modified-julian-day->time-monotonic mjd -> time-monotonic
  modified-julian-day->time-tai mjd -> time-tai
  modified-julian-day->time-utc mjd -> time-utc
  time-monotonic->date time-monotonic [tz-offset] -> date
  time-monotonic->julian-day time-monotonic -> jd
  time-monotonic->modified-julian-day time-monotonic -> mjd
  time-monotonic->time-tai time-monotonic -> time-tai
  time-monotonic->time-tai! time-monotonic -> time-tai
  time-monotonic->time-utc time-monotonic -> time-utc
  time-monotonic->time-utc! time-monotonic -> time-utc
  time-tai->date time-tai [tz-offset] -> date
  time-tai->julian-day time-tai -> jd
  time-tai->modified-julian-day time-tai -> mjd
  time-tai->time-monotonic time-tai -> time-monotonic
  time-tai->time-monotonic! time-tai -> time-monotonic
  time-tai->time-utc time-tai -> time-utc
  time-tai->time-utc! time-tai -> time-utc
  time-utc->date time-utc [tz-offset] -> time-utc
  time-utc->julian-day time-utc -> jd
  time-utc->modified-julian-day time-utc -> mjd
  time-utc->time-monotonic time-utc -> time-monotonic
  time-utc->time-monotonic! time-utc -> time-monotonic
  time-utc->time-tai time-utc -> time-tai
  time-utc->time-tai! time-utc -> time-tai
  date->string date [format-string] -> string
  string->date input-string template-string -> date
  The ~? wildcard is specific to the PLT implementation of string->date: it parses 1 and 2 digit years like ~y and 3 and 4 digit years like ~Y.
| Ch | Conversion | 
|---|---|
| ~~ | a literal ~ | 
| ~a | locale's abbreviated weekday name (Sun...Sat) | 
| ~A | locale's full weekday name (Sunday...Saturday) | 
| ~b | locale's abbreviate month name (Jan...Dec) | 
| ~B | locale's full month day (January...December) | 
| ~c | locale's date and time (e.g., "Fri Jul 14 20:28:42-0400 2000") | 
| ~d | day of month, zero padded (01...31) | 
| ~D | date (mm/dd/yy) | 
| ~e | day of month, blank padded ( 1...31) | 
| ~f | seconds+fractional seconds, using locale's decimal separator (e.g. 5.2). | 
| ~h | same as ~b | 
| ~H | hour, zero padded, 24-hour clock (00...23) | 
| ~I | hour, zero padded, 12-hour clock (01...12) | 
| ~j | day of year, zero padded | 
| ~k | hour, blank padded, 24-hour clock (00...23) | 
| ~l | hour, blank padded, 12-hour clock (01...12) | 
| ~m | month, zero padded (01...12) | 
| ~M | minute, zero padded (00...59) | 
| ~n | new line | 
| ~N | nanosecond, zero padded | 
| ~p | locale's AM or PM | 
| ~r | time, 12 hour clock, same as "~I:~M:~S ~p" | 
| ~s | number of full seconds since "the epoch" (in UTC) | 
| ~S | second, zero padded (00...60) | 
| ~t | horizontal tab | 
| ~T | time, 24 hour clock, same as "~H:~M:~S" | 
| ~U | week number of year with Sunday as first day of week (00...53) | 
| ~V | week number of year with Monday as first day of week (01...52) | 
| ~w | day of week (0...6) | 
| ~W | week number of year with Monday as first day of week (01...52) | 
| ~x | week number of year with Monday as first day of week (00...53) | 
| ~X | locale's date representation, for example: "07/31/00" | 
| ~y | last two digits of year (00...99) | 
| ~Y | year | 
| ~z | time zone in RFC-822 style | 
| ~Z | symbol time zone (not-implemented) | 
| ~1 | ISO-8601 year-month-day format | 
| ~2 | ISO-8601 hour-minute-second-timezone format | 
| ~3 | ISO-8601 hour-minute-second format | 
| ~4 | ISO-8601 year-month-day-hour-minute-second-timezone format | 
| ~5 | ISO-8601 year-month-day-hour-minute-second format | 
| Table 1: DATE->STRINGconversion specifiers | |
| Ch | Skip to | Read | Set | 
|---|---|---|---|
| ~~ | any | read literal ~ | nothing | 
| ~a | char-alphabetic? | abbreviated weekday in locale | nothing | 
| ~A | char-alphabetic? | full weekday in locale | nothing | 
| ~b | char-alphabetic? | abbreviated month name in locale | nothing | 
| ~B | char-alphabetic? | full month name in locale | nothing | 
| ~d | char-numeric? | day of month | date-day | 
| ~e | any | day of month, blank padded | date-day | 
| ~h | char-alphabetic? | same as ~b | nothing | 
| ~H | char-numeric? | hour | date-hour | 
| ~k | any | hour, blank padded | date-hour | 
| ~m | char-numeric? | month | date-month | 
| ~M | char-numeric? | minute | date-minute | 
| ~S | char-numeric? | second | date-second | 
| ~y | any | 2-digit year | date-yearwithin 50 years | 
| ~Y | char-numeric? | year | date-year | 
| ~z | any | time zone | date-zone-offset | 
| ~? | char-numeric? | 2-digit or 4-digit year (PLT-specific extension) | date-year | 
| Table 2: STRING->DATEconversion specifiers | |||
CURRENT-TIME. The GNU C function,
gettimeofday might prove useful to implementors. 
The difference between TAI and UTC is not determinate, and implementations must provide some method for getting TAI. A procedure is provided in the accompany implmentation for reading the leap second table provided by the Time Service of the US Naval Observatory (available at ftp://maia.usno.navy.mil/ser7/tai-utc.dat).
The accompanying implementation assumes SRFI 6 Basic String Ports.
The accompanying implementation also assumes an error
procedure.  The accompanying implementation also assumes SRFI 8 RECEIVE: Binding to
multiple values.  which is easy to implement with the following
syntax:
(define-syntax receive
  (syntax-rules ()
    ((receive formals expression body ...)
     (call-with-values (lambda () expression)
                       (lambda formals body ...)))))
Note that it contains TAI-UTC.DAT reader.
The accompanying 
implementation is written in MzScheme.  MzScheme provides the procedure 
current-seconds, which returns the number of seconds (UTC)
since 1970-01-01T00:00:00Z+00:00, and
current-milliseconds, which is a monotonic time
clock. Combining these provides an implementation of
(current-time time-utc). Monontonic time, in this
implementation, is the same as TAI time; differences between TAI and
UTC are resolved through a leap second table. According to the
International Earth Rotation Service, there will be no leap second in
December, 2000. Thus, the leap second table is guaranteed to be
correct through June, 2000. 
Also, MzScheme (as of version 102, I believe) provides a method for returning the current time zone offset, via its SECONDS->DATE and CURRENT-DATE procedures.
MzScheme's DEFINE-STRUCT was used to define the time
and date objects. SRFI 9, Defining Record
Types, could be used instead.
Procedures meant to be used internally have names beginning with
TM:. Locale-related constants and procedures have
locale in their name; if a 'locale' SRFI is ever written,
it might be good to use that code instead.
From this, the rest of the implementation was built.
There is also a test suite.
Mike Sperber, Marc Feely, Dave Mason, and "Prfnoff" all made useful comments on previous versions of this draft. Thanks to Shriram Krishnamurthi for his editing help.
The DATE->STRING procedure uses a format string, based on
GNU C's date procedure, as well as scsh's
FORMAT-DATE procedure. 
Copyright (C) Neodesic Corporation (2000). All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(display (date->string (current-date 0)
"~4")): 2004-03-15T02:21:15Z