Timmy

Timmy is a general-purpose time and calendar library.

Contents

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.

Rationale and relation to 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.

Advanced calendar features

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, ...

Timezone safety

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.

Support for daylight saving timezones

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.

Static guarantees of operation correctness

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

Concepts

Time points versus time representation

Like many time libraries, Timmy enforces a strict separation between points in time and calendar representations. We reiterate the difference between the two here.

Points in time

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.

Calendar representations

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

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.

On the utility of both concepts

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.