In the past, I’ve had to deal with reading, writing, and performing arithmetic on dates and times in Haskell and the experience is not a pleasant one. Actually, I’ve had to do this in PHP and Erlang and the experience is no better.
So, along the way I created some utilities to make life a little easier. I’ll take a few posts to cover them but let me start with the most common annoyances I’ve had. They are as follows
- There is no type to represent seconds since Unix epoch (I’ll call this Unix time).
- There is no simple way to read and write Day, UTC datetime, Local time in the ISO8601 format.
- Most of all, there is no easy way to convert between UTC time and Local time or Unix time.
Now, there are a few libraries to help you. Most notably, datetime
provides many of these utilities but the types are not very helpful. Believe me when I say a huge chunk of your datetime problems are solved if only you could do those three things easily and in an error-free way.
I have a single file here, that allows you to do the following. Reading
ghci> :l TimeUtils.hs
ghci> readISO8601 "2016-05-03" :: Maybe Day
Just 2016-05-03
ghci> readISO8601 "2016-05-03" :: Maybe UTCTime
Nothing
ghci> readISO8601 "2016-05-03T12:05:23" :: Maybe UTCTime
Nothing
ghci> readISO8601 "2016-05-03T12:05:23" :: Maybe LocalTime
Just 2016-05-03 12:05:23
ghci> readISO8601 "2016-05-03T12:05:23Z" :: Maybe UTCTime
Just 2016-05-03 12:05:23 UTC
ghci> readISO8601 "2016-05-03T12:05:23Z" :: Maybe UnixTime
Just 1462277123
Writing
ghci> showISO8601 <$> (readISO8601 "2016-05-03" :: Maybe Day)
Just "2016-05-03"
ghci> showISO8601 <$> (readISO8601 "2016-05-03T12:05:23Z" :: Maybe UnixTime)
Just "2016-05-03T12:05:23Z"
And converting
ghci> utcToUnixTime <$> readISO8601 "2016-05-03T12:05:23Z"
Just 1462277123
ghci> localTimeToUnixTime <$> readISO8601 "2016-05-03T12:05:23"
Just 1462277123
ghci> (unixTimeToUTC . succ) <$> readISO8601 "2016-05-03T12:05:23Z"
Just 2016-05-03 12:05:24 UTC
For fun
ghci> let Just t = readISO8601 "2016-05-03T12:05:23Z" :: Maybe UnixTime
ghci> mapM_ (putStrLn . showISO8601) . take 10 . enumFrom $ t
2016-05-03T12:05:23Z
2016-05-03T12:05:24Z
2016-05-03T12:05:25Z
2016-05-03T12:05:26Z
2016-05-03T12:05:27Z
2016-05-03T12:05:28Z
2016-05-03T12:05:29Z
2016-05-03T12:05:30Z
2016-05-03T12:05:31Z
2016-05-03T12:05:32Z