Let's say I have an integer representing Epoch time, for example epoch = 1499055085
, and I want to convert it to UTCTime
in Haskell.
How can I do this?
In other languages this is a very trivial task, why is it so difficult in haskell?
Who says it is difficult?
You can simply use fromIntegral :: (Integral a, Num b) => a -> b
to convert the epoch (an integer) to POSIXTime
.
Next we can use posixSecondsToUTCTime :: POSIXTime -> UTCTime
to obtain the UTCTime
, and finally we use the utctDay :: UTCTime -> Day
to get the day part of the UTCTime
.
In case you want a (year,month,day) tuple, we can use the toGregorian :: Day -> (Integer,Int,Int)
method.
So we can use the following method:
import Data.Time.Calendar(toGregorian)
import Data.Time.Clock(utctDay,UTCTime)
import Data.Time.Clock.POSIX(posixSecondsToUTCTime)
epochToUTC :: Integral a => a -> UTCTime
epochToUTC = posixSecondsToUTCTime . fromIntegral
epochToGregorian :: Integral a => a -> (Integer,Int,Int)
epochToGregorian = toGregorian . utctDay . epochToUTC
And then for instance:
Main> epochToGregorian 1234567
(1970,1,15)
Main> epochToGregorian 123456789
(1973,11,29)
Main> epochToGregorian 1234567890
(2009,2,13)
Not a bad question at all, in spite of the down votes. So what would be the equivalent of fairly standard "strptime" and "strftime" here?
You find this rather complicated, and I agree, as I spent a fair amount of time figuring this out (n00b here), so here are some of my findings. It is not simple, because:
epoch -> utc
in the standard library, it is not an omission, it is because it cannot exist.It's simpler in say python as datetime
ship with "pretty good defaults" inferred from your environment. The concept of a "good enough default parameter value for most circumstances" is not something that works well with Haskell.
If the epoch value comes from some arbitrary integer, then Willem Van Onsem's epochToUTC
works. It if is a timestamp from a file (EpochTime
), we need another function as this is not quite an integer (it looks like an integer, it behaves like an integer, but it is neither Int
nor Integer
—that is some very deep water).
As for the import
statements, you may simplify this to a mere import Data.Time
, which will grab all we need from this module, with the exception of posixSecondsToUTCTime
, because... I suppose it is deemed as sort of specialized.
import System.Posix.Types(EpochTime)
import Data.Time
import Data.Time.Clock.POSIX(posixSecondsToUTCTime)
epochToUTC :: EpochTime -> UTCTime
epochToUTC = posixSecondsToUTCTime . realToFrac
Example in ghci: (timestamp of current working directory)
import System.Posix.Files
fStat <- getFileStatus "."
let someTime = epochToUTC . modificationTime $ fStat
And we are good to manipulate this time value. Note that the EpochTime
is specific to the System.Posix
module. If it is a timestamp retrieved from say a database or a web page, it could be yet another story (type safety is not free).
Just as this "strptime" operation was not terribly familiar, a similar story goes with a "strftime"-like operation. This would be done with formatTime
. Example:
formatTime defaultTimeLocale "%Y-%m-%d" someTime
--equivalent
formatTime defaultTimeLocale ( iso8601DateFormat Nothing ) someTime
--whichever dateFmt defined in that TimeLocale
formatTime defaultTimeLocale ( dateFmt defaultTimeLocale ) someTime
--"%a, %_d %b %Y %H:%M:%S %Z"
formatTime defaultTimeLocale rfc822DateFormat someTime
If always on defaultTimeLocale
, then you can elegantly abbreviate to:
formatTime' = formatTime defaultTimeLocale
Readings:
A Haskell Time Library Tutorial (We need more like this!)
Time - HaskellWiki
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With