Features

Different time units represented as different type parameters for single Time data type.
Amount of required boilerplate is minimal.

Time stored as Rational number.

It means that if you convert 900 milliseconds to seconds, you will have 0.9 second instead of 0 seconds.
So property toUnit @to @from . toUnit @from @to ≡ id is satisfied.

Different unit types are stored as rational multiplier in type.

o-clock package introduces its own kind Rat for type-level rational numbers.
Units are stored as rational multipliers in type. Because of that some computation is performed on type-level.
So if you want to convert Week to Day, o-clock library ensures that time units will just be multipled by 7.

Functions from base that work with time are converted to more time-safe versions:

These functions are: threadDelay, timeout, getCPUTime.

Externally extensible interface.

It means that if you want to roll out your own time units and use it in your project,
this can be done in easy and convenient way (see tutorial below).

Note: features support for GHC-8.2.2 is quite limited.

Example: How to make your own time unit

This README section contains tutorial on how you can introduce your own time units.
Let's solve the following problem:

You're CEO of big company. Your employers report you number of hours they worked this month.
You want format hours in more human-readable way, i.e. in number of work weeks and work days.
So we want 140 hours be formatted as 3ww2wd (3 full work weeks and 2 full work days).

Setting up

Since this tutorial is literate haskell file, let's first write some pragmas and imports.