Epoch in Haskell

A common requirement in programs is getting the number of seconds, milliseconds, or nanoseconds since the Unix epoch. Here’s how to do it in Haskell.

import Data.Time.Clock.POSIX (getPOSIXTime, POSIXTime)
import Data.Time.Clock (UTCTime, getCurrentTime)
import Data.Time.Format (formatTime, defaultTimeLocale)

main :: IO ()
main = do
    now <- getCurrentTime
    putStrLn $ formatTime defaultTimeLocale "%Y-%m-%d %H:%M:%S%Q %z" now
    
    posixTime <- getPOSIXTime
    let seconds = floor posixTime :: Integer
    let milliseconds = floor (posixTime * 1000) :: Integer
    let nanoseconds = floor (posixTime * 1000000000) :: Integer
    
    print seconds
    print milliseconds
    print nanoseconds
    
    let utcFromSeconds = posixSecondsToUTCTime $ fromIntegral seconds
    let utcFromNanoseconds = posixSecondsToUTCTime $ fromIntegral nanoseconds / 1000000000
    
    putStrLn $ formatTime defaultTimeLocale "%Y-%m-%d %H:%M:%S %z" utcFromSeconds
    putStrLn $ formatTime defaultTimeLocale "%Y-%m-%d %H:%M:%S%Q %z" utcFromNanoseconds

posixSecondsToUTCTime :: POSIXTime -> UTCTime
posixSecondsToUTCTime = id

In Haskell, we use the Data.Time library to work with time-related functions. The getPOSIXTime function returns the current time as the number of seconds since the Unix epoch.

We use getCurrentTime to get the current time, and formatTime to format it as a string.

To get the elapsed time since the Unix epoch in seconds, milliseconds, or nanoseconds, we multiply the POSIX time by the appropriate factor and convert it to an integer.

You can also convert integer seconds or nanoseconds since the epoch into the corresponding UTCTime. In this example, we use posixSecondsToUTCTime to perform this conversion.

Here’s an example of what the output might look like:

$ runhaskell epoch.hs
2023-05-15 10:30:45.123456 +0000
1684146645
1684146645123
1684146645123456000
2023-05-15 10:30:45 +0000
2023-05-15 10:30:45.123456 +0000

Next, we’ll look at another time-related task: time parsing and formatting.