Dealing with Dates and Times (5/365)

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

  1. There is no type to represent seconds since Unix epoch (I’ll call this Unix time).
  2. There is no simple way to read and write Day, UTC datetime, Local time in the ISO8601 format.
  3. 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
This entry was posted in Haskell and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s