Library
Module
Module type
Parameter
Class
Class type
Timmy is a general-purpose time and calendar library.
The entry point of the main library is the module: Timmy
.
An virtual library that exposes system-dependent clock and current timezone is provided as Clock
.
Ptime
Timmy
is built on top of the widely used Ptime
library which does most of the underlying heavy lifting. It is not intended as a replacement for it but as an (arguably) higher level, safer and more complete calendar-wise layer, while certainly not being as lean and as battle-tested. Interoperability exists for all relevant objects so both can easily be mixed if needed.
We describe here the main rationale for such an additional layer.
Ptime
made its intention clear to not be a calendar library, and offers limited calendaring support. Timmy
offers advanced calendaring features such as computations over dates, weekdays, ISO 8601 weeks, ...
While Ptime
has timezone support, many operation don't explicitely require a timezone and will default to UTC - eg. Ptime.to_date_time
takes the timezone as an optional argument. If an application handles timezone, it is pretty much never correct to omit the timezone in any such conversion call and a single omission can introduce hard to track bugs.
Timmy
takes a zero compromise approach on this, all calls converting between dates and points in time have a mandatory timezone parameter.
Ptime
supports only fixed timezone, ie. GMT+X. However many real-life timezone are not a fixed offset because of daylight saving time. Because of this, no Ptime
timezone can convert correctly dates both in August and Decemebr in Paris because the first is GMT+2 and the latter GMT+1.
Timmy.Timezone.t
supports such varying timezones and offers out-of-the-box implementation for both javascript and Unix.
Because Ptime
uses tuples to represent dates and daytimes, operations on these objects can fail because there are no guarantees a tuple is a valid date or datetime. Timmy
introduces private record types that are guaranteed to be valid dates and daytimes, while still allowing destructuring, thus avoiding potential runtime assertions.
let at_daytime_ptime (t : Ptime.t) (daytime : Ptime.time) =
let (date, _) = Ptime.to_date_time t in
(* Runtime assertion required *)
Ptime.of_date_time (date, time) |> Option.value_exn
let at_daytime_timmy (t : Timmy.Time.t) (daytime : Timmy.Daytime.t) =
let date = Timmy.Date.of_time t in
Timmy.Date.to_time date time
Like many time libraries, Timmy
enforces a strict separation between points in time and calendar representations. We reiterate the difference between the two here.
A point in time, represented by Timmy.Time.t
, is a universal moment that occured simultaneously for every human being, no matter where you are on earth or in the universe -- as such Timmy
boldly disregards relativity. "The moon landing" is often taken as an example of point in time, because since it didn't happen on earth it emphasizes its decorelation from any date: to all of humanity, the instant the lunar module touched ground is a single, unmistakably unique point in time.
On the other hand, calendar representations such as a date and time of the day combo represented by Timmy.Date.t
and Timmy.Daytime.t
are highly dependent on the context and location on earth -- ie. the timezone. For instance, the moon landing is a unique point in time, but depending on the location on earth one viewed the live broadcast either on a Monday (1969-07-20) either on a Sunday (1969-07-19).
Conversions between points in time and calendar representations can only happen in the context of a timezone. Timmy
stricly enforces this by always requiring a Timmy.Timezone.t
when performing such conversion.
Some libraries take the approach of calendar dates always being paired with a timezone, thus making them equivalent to time points and not requiring the distinction. This simplification limits the applicable use cases since a date and daytime combo *is* a standalone sensible value without being tied to a timezone.
If you want to send a user a reminder for a sports match, you should save it at a specific point in time, since no matter where the user is on earth, the live broadcast will happen at that precise time, even if it's the the middle of the night to her.
If however the user want a reminder to take some medication before lunch at 11:55 every day, you should save it as a calendar representation: if the user flies to the other side of the world for a week, you do not want to wake her up at midnight instead. To find the actual time at which you need to send the reminder, you will need the user current timezone, which is enforced by Timmy
's API.