Counting Days since last Christmas

Filed under: haskell

Hello reader. It’s been a minute since there’s been an update about writing code in Haskell, so here’s one. Throughout the past year, I’ve been working on a small app during spare time for fun and to better understand Haskell’s handling of date types for web development.

For one of my blogging projects I’ve been whimsically counting the days since the last Christmas, rather than counting down the days to Christmas. You might be wondering why. There’s a famous Christmas carol that counts the days of Christmas, a sequentially growing number with each passing day. Instead of focusing on material gifts, I wanted to focus on gratitude and personal for each passing day. I also wanted to take a page from George Michael’s songbook, where during the next Christmas I could compare last Christmas with the current Christmas :smile:


Table of Contents

  1. getCurrentTime :: IO UTCTime
  2. utctDay :: UTCTime -> Day
  3. fromGregorian :: Integer -> Int -> Int -> Day
  4. diffDays :: Day -> Day -> Integer
  5. daysSinceXmas as a do block

For the code shown here, I only used the [time](http://hackage.haskell.org/package/time-1.6.0.1) library that is bundled with the GHC compiler. At the time of the writing, I’m on version time-1.6.0.1 which is missing some of the functions in the newer versions. You can likely use ghc-pkg list to see the current installed versions on your machine.

getCurrentTime :: IO UTCTime

The first thing I wanted to figure out was how to get the current date.

With Haskell you can import the Date.Time package then use the getCurrentTime method. Guess what, this returns an IO type. This presents a challenge for the ongoing work as I shall attempt to explain.

Caption

Getting Current Time in ghci

Here’s what the UTCTime looks like:

Caption

Getting Current Time in ghci

utctDay :: UTCTime -> Day

Data.Time comes with this function diffDays, and in the spirit of minimalism I try to use this function without writing extra.

What are we constrained to with the types? Let us take a look:

diffDays :: Day -> Day -> Integer

What we know now is that you are presented with a IO UTCTime for current time that needs to be a Day type. That’s like connecting an HDMI cable to USB-C. You need an adapter.

Luckily, there is a function that can act as the adapter. utctDay :: UTCTime -> Day combined with fmap you can convert the current time to a Day type.

Caption

Getting Current Time in ghci

fromGregorian :: Integer -> Int -> Int -> Day

Not quite finished yet. How do you get the last Christmas’ date?

For now let’s use this very readable function fromGregorian, it looks like so:

let last_xmas = (fromGregorian 2017 12 25)

diffDays :: Day -> Day -> Integer

To this point we have the current day, and last Christmas as a day.

let today = fmap utctDay getCurrentTime
let last_xmas = (fromGregorian 2017 12 25)

Below you can see that you can’t force the IO Day into a Day type. Haskell won’t let you force an IO into a non IO type. You can use unsafePerformIO, however it is HIGHLY unadvised because of possible side effects. Don’t do it that way if possible.

Caption

Example of IO Error

When it comes to IO conversions, I find it easier to put the code in a do block and liberally use the <- symbol. Not sure why this works, but it does.

daysSinceXmas as a do block

Finally we see how combining all these steps together into the ghci console looks like.

Caption

Example of a do block in ghci

You can write this do block into a *.hs file, like the below image and continue building from there! I used this function in a web app I’m building with Reflex.


Follow my instagram, where I will post more updates!

View this post on Instagram

A post shared by Dr. Kat Chuang (@katychuang.nyc) on