【问题标题】:Rails: Get timezone offset nameRails:获取时区偏移名称
【发布时间】:2020-12-28 11:10:54
【问题描述】:

在 Ruby 或 Rails 中,给定一个时区标识符,如 America/Los_Angeles,我知道如何获得特定的时区偏移缩写,如 PDT:

Time.current.in_time_zone('America/Los_Angeles').zone
=> "PDT"

Time.now.in_time_zone("America/Los_Angeles").strftime('%Z')
=> "PDT"

Time.now.in_time_zone("America/Los_Angeles").strftime('%z')
=> "-0700"

甚至是时区本身的友好名称:

ActiveSupport::TimeZone::MAPPING.key('America/Los_Angeles')
=> "Pacific Time (US & Canada)"

但是我怎样才能得到像Pacific Daylight Time 这样的字符串,而不仅仅是PDT 来表示特定日期的完整时区偏移名称?

输入:America/Los_Angeles 和特定日期或日期时间

所需输出:Pacific Daylight Time

【问题讨论】:

  • AFAIK 目前没有办法获得完整的区域形式。您可能需要添加自己的逻辑来做到这一点。 timeanddate.com/time/zones - 可用缩写区域的全名列表

标签: ruby-on-rails ruby timezone


【解决方案1】:

简短的故事:~出于某种原因,~(因为@bata mentioned in his answer 缩写不是唯一的,所以这可能是没有官方缩写-人类友好名称映射的原因)该标准似乎不支持它。您可能需要自己实现此映射。但是,如果您想了解为什么它可能不那么容易,请继续阅读。

所以...这是一个有趣的兔子洞...

使用了哪些宝石以及它们从哪里获得信息

ActiveSupport uses tzinfo gem for that 反过来使用 tz-info gem。 tz-info 说它uses one of two data sources

  • 类 Unix 系统中的 zoneinfo 目录
  • TZInfo::数据

Rails 的 Gemfile 模板 confirms that TZInfo data is used on window

起初我认为可能会有一个公关机会为流行的宝石做出贡献。 Quick search suggests 没有将 PDT 映射到任何“人类友好形式”。

查看unixzoneinfo数据库

$ cat /usr/share/zoneinfo/America/Los_Angeles
TZif2H*ˉ#pa&t\؀Ðݩ޾߉iip~KIR^-)4GJQ',3qo_O?/v( fe HG *)
                                                     x                                                   
                                                       q(a'Q                                             
A       0C      ΐ

௠
 #j$5 %J& '*'))6 "S      54+ !"V
eGYe턠g';gfiiHjke lmvG noV) pq6: XX YZ [޵\ ]^d _y`Mޠab-cgwdE G-Gӵ I                                      
                                ros tOt v8vxx͠yz{f|~}H~^s*&                                               
                                                         LMTPDTPSTPWTPPTTZif2^H*ˉ#pa&t\؀Ðݩ޾߉iip~KIR^-)4GJQ',3qo_O?/v( fe HG *)
                    x
                      q(a'Q
A       0C      ΐ

௠
 #j$5 %J& '*'))6 "S      54+ !"V
eGYe턠g';gfiiHjke lmvG noV) pq6: XX YZ [޵\ ]^d _y`Mޠab-cgwdE G-Gӵ I                                      
                                ros tOt v8vxx͠yz{f|~}H~^s*&                                               
                                                         LMTPDTPSTPWTPPT                                 
PST8PDT,M3.2.0,M11.1.0

看起来像一个二进制文件...

$ strings /usr/share/zoneinfo/America/Los_Angeles
TZif2
 v+ !
 2s$
3Gt 4S
5'V 62
mvG n
oV) p
TZif2
 v+
3Gt
5'V
mvG
oV)
PST8PDT,M3.2.0,M11.1.0

嗯。不管这些是什么意思,这个 TZ 似乎没有“人类友好”的名字。

更多挖掘unix tzinfo 格式,显然有ziczdump 工具

$ zdump /usr/share/zoneinfo/America/Los_Angeles
/usr/share/zoneinfo/America/Los_Angeles  Thu Sep 10 03:07:49 2020 PDT 

不是很有用...

$ zic /usr/share/zoneinfo/America/Los_Angeles
"/usr/share/zoneinfo/America/Los_Angeles", line 1: line too long 

呃。

但是阅读manpages 以了解其中一个工具,我发现timezoneinfo 是官方的RFC 8536。我不擅长阅读这些,但格式中有标题(仅限版本)和

  • data block(检查一下,显然它存储了 TZ 的所有历史更改)
  • footer 似乎包含 PDT 字符串等,并且没有提到提供“友好”名称的可能性。

如果您难以阅读 RFC,看起来 tzinfo-data gem 试图为不包括 tzinfo 数据库的系统(即 Windows)重现相同的数据:

https://github.com/tzinfo/tzinfo-data/blob/4ab39f022f5537b97eed133c1169f9ace3a82e2b/lib/tzinfo/data/definitions/PST8PDT.rb

          timezone 'America/Los_Angeles' do |tz|
            tz.offset :o0, -28378, 0, :LMT
            tz.offset :o1, -28800, 0, :PST
            tz.offset :o2, -28800, 3600, :PDT
            tz.offset :o3, -28800, 3600, :PWT
            tz.offset :o4, -28800, 3600, :PPT
            
            tz.transition 1883, 11, :o1, -2717640000, 7227400, 3
            tz.transition 1918, 3, :o2, -1633269600, 29060207, 12
            tz.transition 1918, 10, :o1, -1615129200, 19375151, 8
            tz.transition 1919, 3, :o2, -1601820000, 29064575, 12
            tz.transition 1919, 10, :o1, -1583679600, 19378063, 8
            tz.transition 1942, 2, :o3, -880207200, 29164799, 12
            # ... [cut!]

这里是offset 方法定义:https://github.com/tzinfo/tzinfo/blob/f361d7d0b859ba5b91d30ffd6b66c3c59f90e969/lib/tzinfo/format2/timezone_definer.rb#L37:L59(至少我认为是这样,除非你在 ruby​​ 中运行代码,否则你永远不会知道)

如您所见,夏令时没有:LMT:PST 缩写。

这里是transition方法https://github.com/tzinfo/tzinfo/blob/8c549373736a7873e18bb787b818d8786591e5e5/lib/tzinfo/format1/timezone_definer.rb#L30:L61

您可以自行探索更多内容。但看起来每一个从 DST 和返回的过渡都应该出现在 tzinfo 中。洛杉矶似乎计划到 2060 年。如果您尝试计算 2060 年之后的时间,如果您会得到与 DST 相关的 TZ 错误,那真的很有趣?

最后一件事:缩写

不知道unixtzinfo db 是否属于这种情况,但在 gem 中它们是在本地定义的!

如果所有定义 (https://github.com/tzinfo/tzinfo-data/search?q=%3APDT&unscoped_q=%3APDT),:PDT 的含义似乎相同

但请注意

  • lib/tzinfo/data/definitions/Asia/Manila.rb 定义了正偏移量tz.offset :o3, 28800, 3600, :PDT,但是
  • lib/tzinfo/data/definitions/America/Dawson.rb 使用相同的缩写定义负偏移量tz.offset :o7, -28800, 3600, :PDT

这是什么意思 - 不知道。但这可能是我们在任何地方都没有“全球友好时区名称”的原因。

数据库中可能有错误。 official DB README 说:

这个历史本地时间信息数据库有几个目标:

  • 提供有关民间时代历史的数据纲要 即使不是 100% 准确也很有用。

  • 了解已存在的各种本地时间规则 过去,因此可能会在未来出现。

  • 测试本地时间规则描述系统的通用性。

时区数据文件中的信息绝不是权威; 欢迎修复和增强。请参阅文件 CONTRIBUTING 了解详情。

【讨论】:

    【解决方案2】:

    我认为缩写没有标准。此外,它们并不像您在此处看到的那样是唯一的:https://www.timeanddate.com/time/zones/

    【讨论】:

    • 这个问题根本不是关于缩写的问题。
    猜你喜欢
    • 2016-05-07
    • 2011-02-28
    • 1970-01-01
    • 2020-04-20
    • 2014-02-15
    • 2021-04-11
    • 2020-01-02
    • 1970-01-01
    • 2016-08-06
    相关资源
    最近更新 更多