3

ActionView::Helpers::FormOptionsHelper 提供time_zone_options_for_select以获取选择控件的选项列表,其中包括所有时区及其 UTC 偏移量。我遇到的问题是如何让它在夏令时生效时显示正确的偏移量?

例如,美国山区时间通常是 -7 UTC,但在夏季,它实际上是 -6 UTC。有没有办法让该列表正确反映这一点?

4

2 回答 2

3

TL;博士

您收到的时区数据是“正确的”,因为ActiveSupport::TimeZone实例TZInfo::Timezone不会对当前日期做出假设,因此对它们应用 DST 在这些对象的职责范围内没有“意义”。

注意到了这个问题,因为 , 的默认模型time_zone_options_for_select不幸ActiveSupport::TimeZone地在调用 时返回了偏移字符串#to_s,如果该位置当前正在观察 DST,则该字符串将是不正确的。无法修复选项中生成的字符串值,甚至无法从中删除偏移量。

如果这是不可接受的,您将需要跳过 using time_zone_options_for_selectoptions_for_select而是使用,并自己生成选项。

一些调查

time_zone_options_for_select用作::ActiveSupport::TimeZone默认model参数,因此手动传递它不会改变您的结果。为了构造选择框的选项,该方法将构造一个格式为 的元组数组[time_zone.to_s, time_zone.name],以便将其传递给更通用的options_for_select方法。time_zone,在这种情况下,是 的一个实例::ActiveSupport::TimeZone

这里的重要因素是,这个时区实例对象在概念上与“当前日期”的概念完全无关/背离。时区的定义(严格来说)与当前日期无关。我们可以像这样确认这个“不使用 DST”问题:

::ActiveSupport::TimeZone.all.find { |tz| tz.name == "Adelaide" }.utc_offset
=> 34200 # 9 hours and 30 minutes, in seconds

阿德莱德的非 DST 时区是 ACST(澳大利亚中部标准时间),即 GMT+9.5。目前(在撰写本文时),阿德莱德处于 DST,这意味着他们处于 ACDT(澳大利亚中央夏令时间),即 GMT+10.5。

::ActiveSupport::TimeZone.all.find { |tz| tz.name == "Adelaide" }.now.utc_offset
=> 37800 # 10 hours and 30 minutes, in seconds

这里的关键区别本质上是我上面概述的 -ActiveSupport::TimeZone实例只是关心当前日期。类本身是一个TZInfo::DataTimezone实例的便利包装器,它在当前日期有类似的意见 - 没有。

如果您注意到,在上面的第二个代码片段中,我们#now在调用#utc_offset. 这将返回一个ActiveSupport::TimeWithZone实例,其中包括有关时区以及当前日期的信息 - 因此我们得到一个偏移量,它反映了当前日期应包括 DST 偏移量这一事实。

#to_s因此,这里唯一的问题是,在on实例的返回值中包含 UTC 偏移字符串在ActiveSupport::TimeZone这种情况下有点误导。包含它是因为它是该时区的“基本”UTC 偏移量。

资源:

于 2021-01-07T01:02:18.633 回答
2

我有类似的问题,但最终使用了这个

time_zone_select('time_zone', TZInfo::Timezone.us_zones, 
                                     :default => "America/Los_Angeles", 
                                     :model => TZInfo::Timezone

你找到更好的解决方案了吗?

于 2012-05-25T19:46:41.137 回答