This SRFI is currently in *final* status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to `srfi-174@nospamsrfi.schemers.org`

. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

- Received: 2019/9/14
- Draft #1 published: 2019/9/16
- Draft #2 published: 2019/11/10
- Draft #3 published: 2019/11/11
- Finalized: 2019/12/21

This SRFI defines the trivial type *timespec*, which is used
to represent the `struct timespec`

defined by the
POSIX `<time.h>`

header.

The reason for putting this very simple and straightforward type into a SRFI (and library) of its own is that timespecs are part of the interface for more than one SRFI. If they are defined in just one SRFI and imported by the rest, that produces an otherwise useless and unnecessary dependency on the SRFI containing the definition. This arises particularly in R6RS and R7RS because record types are generative (distinct definitions lead to distinct record types) and because most implementations report a warning or even an error if the same identifier is imported from more than one library, unless they have both imported it in turn from the same original library.

Timespec is an immutable type that holds two exact integer values:

The

*seconds*component — If non-negative, the number of whole seconds since a particular epoch. If negative, the number of whole seconds to go back in time from the epoch. Normally excludes leap seconds (i.e. a leap second that occurs between the epoch and*seconds*does not increment or decrement*seconds*). The minimum range of values is 2^{-39}(inclusive) to 2^{39}(exclusive), allowing a range of at least 15,000 years before and after the epoch.The

*nanoseconds*component — The partial second added to*seconds*. Always non-negative and less than 10^{9}. If*seconds*is non-negative, this is the number of additional nanoseconds to go toward the future after*seconds*. If*seconds*is negative, this is the number of additional nanoseconds to go further back in time before*seconds*.

It is recommended, but not absolutely required, that timespecs be a disjoint and immutable type. For efficiency's sake they may be represented otherwise in particular implementations. If they are not disjoint, the exact representation (such as a SRFI 19 time object or a pair) must be documented by the implementation.

If timespecs are represented as SRFI 19 time objects,
the `timespec`

constructor must set the
SRFI 19 time type to `TIME_UTC`

.
It is an error to mutate a time object (or pair, or other type)
that is serving as a timespec,
and if this is done, code relying on the immutability of timespecs will break.

Note that IEEE 64-bit floats are *not* a sufficient representation
for timespecs,

It is recommended, but not required, that timespecs
be a disjoint type, but for efficiency's sake they may be represented
otherwise in particular implementations.
It is an error to mutate the values held in a timespec object.
Note that IEEE 64-bit floats are *not* a sufficient representation,
because their nanosecond-precision range is confined to a period of 208 days
centered on the epoch.

In no case can this SRFI guarantee anything about the accuracy of timespecs, or the precision of any timespec sources. Since it is difficult to usefully determine and communicate timestamp precision and accuracy in most applications, the timespec type does not contain any standard field to hold such information.

An implementation of this SRFI must document:

- Which concrete representation is used for the timespec abstract data type (a disjoint type, a pair, etc.)
- The minimum and maximum values of the
*seconds*component.

`(timespec `

*seconds nanoseconds*`)`

Returns a timespec with the given *seconds*
and *nanoseconds* components.

`(timespec? `

*obj*`)`

Returns `#f`

if *obj* is definitely not a timespec,
and `#t`

if it is most probably one.

If timespecs are a disjoint type, this procedure simply tests whether
*obj* belongs to that type. If not, then each component
is checked to see if it is an exact integer, and in the case
of the *nanoseconds* component, whether it is a non-negative integer
less than 10^{9}.
In addition, if the implementation knows that its fixnum width is at least 40 bits,
it can also check that the value of the seconds component is a fixnum.

`(timespec-seconds `

*timespec*`)`

Returns the *seconds* component of *timespec*.
The result must be the same (in the sense of `eqv?`

)
as the value passed to `timespec`

.

`(timespec-nanoseconds `

*timespec*`)`

Returns the *nanoseconds* component of *timespec*.
The result must be the same (in the sense of `eqv?`

)
as the value passed to `timespec`

.

`(inexact->timespec `

*inexact*`)`

Converts *inexact* into an approximate number of seconds and
nanoseconds since the (unspecified) epoch and returns the results as
a timespec object.

`(timespec->inexact `

*timespec*`)`

Returns an inexact number representing the seconds from the epoch to
the value of *timespec*.

Note that these operations are not inverses, because inexact numbers typically do not have nanosecond precision.

`(timespec=? `

*timespec1 timespec2*`)`

Returns `#t`

if *timespec1* and *timespec2*
represent the same instant of time, and `#f`

otherwise.

`(timespec<? `

*timespec1 timespec2*`)`

Returns `#t`

if *timespec1* represents an earlier
instant of time than *timespec2*, and `#f`

otherwise.

Note that it is an (undetectable) error to compare two timespecs that are relative to different epochs.

`(timespec-hash `

*timespec*`)`

Returns an exact non-negative integer representing a hash code
for *timespec*.

An implementation of SRFI 174 is in the repository of this SRFI. The files are:

`srfi/174.sld`

- uses a disjoint type`chibi-tests.scm`

- Tests using`(chibi tests)`

Note: A pair-based implementation is also available; simply
comment out the `define-record-type` declaration
in `srfi/174.sld`

and remove the comment markers
from the declarations that follow.

Discussions between me, Lassi Kortela, and Harold Ancell, mostly on the SRFI 170 mailing list, made the need for this SRFI clear.

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 (including the next paragraph) 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.

Editor: Arthur A. Gleckler