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
Table of Contents
- getCurrentTime :: IO UTCTime
- utctDay :: UTCTime -> Day
- fromGregorian :: Integer -> Int -> Int -> Day
- diffDays :: Day -> Day -> Integer
- 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.
Getting Current Time in ghci
Here’s what the UTCTime looks like:
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:
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.
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:
diffDays :: Day -> Day -> Integer
To this point we have the current day, and last Christmas as a day.
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.
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.
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!