如何在 haskell 中将纪元转换为公历日期时间

How to convert epoch to gregorian datetime in haskell

假设我有一个代表大纪元时间的整数,例如epoch = 1499055085,我想在Haskell中将其转换为UTCTime。 我该怎么做?

在其他语言中这是一个非常微不足道的任务,为什么在 haskell 中如此困难?

谁说难?

您可以简单地使用 fromIntegral :: (Integral a, Num b) => a -> b 将纪元(整数)转换为 POSIXTime

接下来我们可以使用 posixSecondsToUTCTime :: POSIXTime -> UTCTime to obtain the UTCTime, and finally we use the utctDay :: UTCTime -> Day 来获取 UTCTime 的日期部分。

如果你想要一个 (year,month,day) 元组,我们可以使用 toGregorian :: Day -> (Integer,Int,Int) 方法。

所以我们可以使用下面的方法:

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

然后例如:

Main> epochToGregorian 1234567
(1970,1,15)
Main> epochToGregorian 123456789
(1973,11,29)
Main> epochToGregorian 1234567890
(2009,2,13)

尽管有反对票,但这个问题一点也不差。那么这里相当标准的 "strptime" 和 "strftime" 相当于什么?

你觉得这相当复杂,我同意,因为我花了相当多的时间来解决这个问题(这里是 n00b),所以这里是我的一些发现。不简单,因为:

  1. 处理时间很复杂。
  2. Data.Time库侧重于类型安全(与Haskell一致),这也意味着没有为您完成自动类型转换。因此,您必须了解一两件事。
  3. epoch 的读法取决于它到底代表什么以及它是如何存储的。因此,如果标准库中没有实现通用函数epoch -> utc,那不是遗漏,而是因为它不存在。

说 python 更简单,因为 datetime 随 "pretty good defaults" 一起从您的环境中推断出来。 "good enough default parameter value for most circumstances" 的概念不适用于 Haskell.

如果纪元值来自某个任意整数,则 Willem Van Onsem 的 epochToUTC 有效。如果它是来自文件的时间戳 (EpochTime),我们需要另一个函数,因为它不是一个整数(它看起来像一个整数,它的行为也像一个整数,但它既不是 Int 也不是Integer——那是一些很深的水)。

至于 import 语句,您可以将其简化为纯粹的 import Data.Time,它将从该模块中获取我们需要的所有内容,但 posixSecondsToUTCTime 除外,因为。 ..我想它被认为是一种专业化。

import System.Posix.Types(EpochTime)
import Data.Time
import Data.Time.Clock.POSIX(posixSecondsToUTCTime)

epochToUTC :: EpochTime -> UTCTime
epochToUTC = posixSecondsToUTCTime . realToFrac

ghci 中的示例:(当前工作目录的时间戳)

import System.Posix.Files

fStat <- getFileStatus "."
let someTime = epochToUTC . modificationTime $ fStat

并且我们可以很好地操纵这个时间值。请注意,EpochTime 特定于 System.Posix 模块。如果它是从数据库或网页中检索到的时间戳,则可能是另一个故事(类型安全不是免费的)。

正如这个 "strptime" 操作不太熟悉一样,类似的故事也发生在类似 "strftime" 的操作中。这将通过 formatTime 完成。示例:

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

如果总是在defaultTimeLocale,那么你可以优雅地缩写为:

formatTime' = formatTime defaultTimeLocale

读数:

A Haskell Time Library Tutorial(我们需要更多这样的!)

Time - HaskellWiki