Home > Software engineering >  Haskell get current time as ISO8601 string
Haskell get current time as ISO8601 string

Time:09-08

I've tried several things I could find online to print the current time as an ISO8601 string, but none of them have worked:

  1. This SO answer assumes you already know how to get the current time, but I can't figure that out.

    I keep on getting an error Could not find module ‘System.Locale’ because it seems like System.Locale is deprecated/not installed by default anymore?

    I tried installing old-local but that just gave me new errors, I think caused by incompatibilities between time and old-locale:

    • Couldn't match expected type ‘time-1.9.3:Data.Time.Format.Locale.TimeLocale’
                  with actual type ‘System.Locale.TimeLocale’
      NB: ‘time-1.9.3:Data.Time.Format.Locale.TimeLocale’
            is defined in ‘Data.Time.Format.Locale’ in package ‘time-1.9.3’
          ‘System.Locale.TimeLocale’
            is defined in ‘System.Locale’ in package ‘old-locale-1.0.0.7’
    • In the first argument of ‘formatTime’, namely ‘defaultTimeLocale’
      In the expression: formatTime defaultTimeLocale "%FT%T%QZ"
      In an equation for ‘iso8601’:
          iso8601 = formatTime defaultTimeLocale "%FT%T%QZ"
       |
    49 | iso8601 = formatTime defaultTimeLocale "%FT%T%QZ"
       |                      ^^^^^^^^^^^^^^^^^
    
    
  2. This wiki page gets the current time, but doesn't format it as ISO8601.

  3. this blog post seems really good, but only has one section on formatting which is actually the same as 1.:

Prelude Data.Time> formatTime defaultTimeLocale "%T, %F (%Z)" myTime

What I want, is to be able to call a function have it print out the current time as an ISO8601 string. I'm guessing this will have to actually be an IO action since it's not a strict function.

CodePudding user response:

I think I figured it out. Note that Haskell has funky string formatting time specifications

  • %F == year-month-day
  • %T == hour:minute:second
  • %Q == .up_to_12_decimals_for_fraction_of_a_second

import Data.Time.Format (defaultTimeLocale, formatTime)
import Data.Time.Clock

getCurrentTimeAsISO8601 :: IO String
getCurrentTimeAsISO8601 = do
  t <- getCurrentTime
  let val = formatTime defaultTimeLocale "%F %T%Q" t
  -- Take the first 23 characters so we don't get the microseconds
  return $ take 23 val

main = do
  time <- getCurrentTimeAsISO8601
  putStrLn time

You can use the online ghci here to copy-paste the code and it should all work.

CodePudding user response:

You can slighly improve this by performing a functor mapping:

import Data.Time.Format (defaultTimeLocale, formatTime)
import Data.Time.Clock(getCurrentTime)

getCurrentTimeAsISO8601 :: IO String
getCurrentTimeAsISO8601 = take 23 . formatTime defaultTimeLocale "%F %T%Q" <$> getCurrentTime

CodePudding user response:

The show instance for UTC is what you want. Therefore you can just use show.

getCurrentTimeASISO8601 :: IO String
getCurrentTimeASISO8601 = fmap (take 23 . show) getCurrentTime

Just a note: Up to my best knowledge ISO8601 isn't yyyy-MM-dd hh:mm:ss but yyyy-MM-ddThh:mm:ss. So if you are implementing this based on the standard, check it twice.

CodePudding user response:

I wonder if something from the time package’s Data.Time.Format.ISO8601 module might help? The iso8601Show function turns a UTCTime into a ISO8601 formatted string.

import Data.Time (getCurrentTime)
import Data.Time.Format.ISO8601 (iso8601Show)

main :: IO ()
main = do
  now <- getCurrentTime
  putStrLn (iso8601Show now)
  • Related