首页 > 解决方案 > 将 UTC 时间戳转换为 ELM 中的用户时区

问题描述

我正在编写一个用 ELM 编写的日历,它需要显示它通过 REST 接口从后端获取的条目。我从后端获得的所有时间都是 UTC,我需要在用户的时区向用户显示它们。

我通过以下任务在开始时从用户那里获取时区来实现这一点:

getTimezone : Cmd Msg
getTimezone =
    Task.perform SetTimezone here

并将结果存储在模型中。

每当我需要向用户显示时间戳时,我都会使用以下两个函数:

formatTime : Zone -> Posix -> String
formatTime zone timestamp =
    let
        hour =
            toHour zone timestamp

        minute =
            toMinute zone timestamp
    in
    (padLeft 2 '0' <| fromInt hour) ++ ":" ++ (padLeft 2 '0' <| fromInt minute)

formatTimeOfIsoTimestamp : Zone -> String -> String
formatTimeOfIsoTimestamp zone isoTimestamp =
    toTime isoTimestamp |> Result.map (formatTime zone) |> Result.withDefault isoTimestamp

上周末我们在欧洲从 DST 切换到标准时间后,我注意到了一个问题:

上周(仍然有 DST)本周内的所有时间都关闭了一小时,因为我的代码仍然在时间戳上增加了两个小时(CEST 的偏移量),而只增加了一个小时(CET 的偏移量)是正确的。本周则相反:本周和接下来几周的时间戳是正确的,而过去几周的时间戳现在都是不正确的。

我在https://package.elm-lang.org/packages/elm/time/latest/Time#here中看到了这些注释,这可能是我遇到的问题:here不返回时区Europe/Berlin信息,而是返回固定的偏移量,在我的情况下Etc/GMT+1,或者Etc/GMT+2取决于 DST 目前是否处于活动状态。

我现在的问题是:如果我需要格式化全年分布的时间戳,我该如何正确处理 ELM 中的时区?有没有其他软件包可以帮助我解决这个问题?如果需要,我还可以向服务器询问用户的正确时区(例如Europe/Berlin),但出于性能原因,我不想为我需要转换的每个时间戳发出服务器请求。所以我认为我需要在 ELM 中实现 IANA 时区数据库。

标签: datetimetimezoneelm

解决方案


除了使用Time.here提供的固定偏移量,另一种方法是在启动时通过标志Intl.DateTimeFormat().resolvedOptions().timeZone传递( MDN ) 的结果。

使用justinmimbs/timezone-data,在 Elm 端解析它可能看起来像:

TimeZone.zones
    |> Dict.get resolvedTimeZone
    |> Maybe.withDefault TimeZone.zone_australia__sydney

推荐阅读