首页 > 解决方案 > 在 Haskell 中显示当地时间

问题描述

我的状态对象将日期存储为UTCTime. 但我需要将它们作为适当的当地时间显示给用户。

我试过使用getCurrentTimeZonethen utcToLocalTime,但它不适用于夏季的日期。问题似乎是现在getCurrentTimeZone返回我的时区,而不是适当的日期。

let time = UTCTime (fromGregorian 2018 08 08) 0
tz <- getCurrentTimeZone -- GMT - my time zone now
utcToLocalTime tz time
-- 2018-08-08 00:00:00 - wrong

如果我将日期传递给getTimeZone

let time = UTCTime (fromGregorian 2018 08 08) 0
tz <- getTimeZone time -- BST - the timezone for the date
utcToLocalTime tz time
-- 2018-08-08 01:00:00 - right

问题是,设置/显示时间的代码很深IO(应该如此),所以当我想显示时间时无法运行此代码。

我看过Olsen 包,但是当我通过它GMT(使用timeZoneName)时,它的作用与上面的第一个示例相同 - 无法弄清楚如何告诉它获取数据。

标签: haskelltimezone

解决方案


使用包执行此操作的预期方法timezone-olson是使用 a TimeZoneSeries,它是随时间变化的完整系列时区转换,而不仅仅是 a TimeZone,它反映了某个时间点的时区。

您通常需要从IO. 您可以从标准位置加载默认的本地时区系列/etc/localtime,或者您可以从例如/usr/share/zoneinfo/America/Chicago或其他位置加载特定系列。不幸的是,似乎没有一种健壮的、独立于平台的方式来指定和加载时区文件。

TimeZoneSeries读取后,需要将其传递给您的纯计算,您可以在其中使用utcToLocalTime'该时间点的时区获取正确的本地时间。希望你已经有一个Reader方便的:

import Control.Monad.Reader
import Data.Time (UTCTime(..), fromGregorian, LocalTime)
import Data.Time.LocalTime.TimeZone.Olson (getTimeZoneSeriesFromOlsonFile)
import Data.Time.LocalTime.TimeZone.Series (TimeZoneSeries, utcToLocalTime')

data R = R { tzs :: TimeZoneSeries }

main :: IO ()
main = do
  mytzs <- getTimeZoneSeriesFromOlsonFile "/etc/localtime"
  print $ runReader getTimes R { tzs = mytzs }

getTimes :: Reader R LocalTime
getTimes = flip utcToLocalTime' (UTCTime (fromGregorian 2018 08 08) 0) <$> asks tzs

看起来tz包是一样的,尽管它使用 typeTZ代替TimeZoneSeries. 您仍然需要loadTZFromFile输入IO并将其传递utcToLocalTimeTZ给位于纯代码中的调用。有一个方便的函数可以从(或环境变量指定的备用位置)loadLocalTZ读取;它看起来与平台无关,但和路径在源代码中是硬编码的(除非它使用环境变量代替,如果已设置)。/etc/localtimeTZ/etc/localtime/usr/share/zoneinfoTZDIR/usr/share/zoneinfo

无论如何,代码看起来像:

import Control.Monad.Reader
import Data.Time (UTCTime(..), fromGregorian, LocalTime)

import Data.Time.Zones (utcToLocalTimeTZ, loadLocalTZ, TZ)

data R = R { tz :: TZ }

main :: IO ()
main = do
  mytz <- loadLocalTZ
  print $ runReader getTimes R { tz = mytz }

getTimes :: Reader R LocalTime
getTimes = flip utcToLocalTimeTZ (UTCTime (fromGregorian 2018 08 08) 0) <$> asks tz

推荐阅读