This post is meant to be the first in a series highlighting various interesting
features of Core
(although I should acknowledge that most of the continuing
series I’ve started so far have not, when it comes down to it, continued.) This
time I wanted to focus on how Core
handles time. Time is a
surprisingly complex topic, as anyone who has worked through the gory details of
calendrical calculations can tell you. One of the initial complexities is that
there are lots of different-but-related concepts that come into play, and in
order to design a good library, you have to figure out how to reflect those
concepts in your datatypes. Here are the primary types that
Core
uses for dealing with time:
Time.t
, an absolute time, i.e., a fully specified point in time, independent of time zone or any other information.Time.Span.t
, a length of time, as in “5 minutes” or “3 hours”.Time.Ofday.t
, a time of day, as in, “3:53:12 PM”.Date.t
, a date, e.g. “2008-12-13”.Weekday.t
, a day of the week, e.g., “Monday”TZ.Zone.t
, a timezone, e.g., “EST5EDT”. The combination of a date, a time of day, and a timezone is sufficient to compute aTime.t
Interestingly, Time.t
, Time.Ofday.t
and Time.Span.t
share the same
underlying implementation: they are all floating point numbers representing a
number of seconds. A Time.t
is the same kind of float returned by the
gettimeofday
call in the standard of library, basically a traditional UNIX
time. A Time.Ofday.t
is implemented with a float representing the number of
seconds since the beginning of the day, and a Time.Span.t
is represented by a
float representing the number of seconds in question.
By seperating into three types rather than one, we get types that are more
informative and less error prone. For example, the function Time.diff
and
Time.add
have the following signatures:
val diff: Time.t -> Time.t -> Time.Span.t
val add: Time.t -> Time.Span.t -> Time.t
This stops you from making basic mistakes, like taking two absolute times and adding them together and expecting to get another absolute time.
Core
’s handling of time has a lot going for it. There are many useful
functions, and it’s been reasonably well battle tested (although there are
surely bugs yet to be found.) There is also the very useful TZ
module, which
is a reimplementation of UNIX’s timezone handling, which uses the standard UNIX
timezone database. (“Why reimplement?” you may ask. It turns out that the libc
calls for doing timezone conversion require you to specify the timezone by
stuffing it into the TZ
environment variable before making the call. That
makes these calls painful and error-prone in the presence of threads.)
The biggest remaining problem we have is that time zone handling is not
integrated into the Time
module itself – Time
can only convert strings in
localtime and UTC. Integration of TZ
into Time
is something we hope to get
done in the next release or two.