ActionView::Helpers::FormOptionsHelper 提供time_zone_options_for_select以获取选择控件的选项列表,其中包括所有时区及其 UTC 偏移量。我遇到的问题是如何让它在夏令时生效时显示正确的偏移量?
例如,美国山区时间通常是 -7 UTC,但在夏季,它实际上是 -6 UTC。有没有办法让该列表正确反映这一点?
ActionView::Helpers::FormOptionsHelper 提供time_zone_options_for_select以获取选择控件的选项列表,其中包括所有时区及其 UTC 偏移量。我遇到的问题是如何让它在夏令时生效时显示正确的偏移量?
例如,美国山区时间通常是 -7 UTC,但在夏季,它实际上是 -6 UTC。有没有办法让该列表正确反映这一点?
您收到的时区数据是“正确的”,因为ActiveSupport::TimeZone
实例TZInfo::Timezone
不会对当前日期做出假设,因此对它们应用 DST 在这些对象的职责范围内没有“意义”。
您注意到了这个问题,因为 , 的默认模型time_zone_options_for_select
不幸ActiveSupport::TimeZone
地在调用 时返回了偏移字符串#to_s
,如果该位置当前正在观察 DST,则该字符串将是不正确的。无法修复选项中生成的字符串值,甚至无法从中删除偏移量。
如果这是不可接受的,您将需要跳过 using time_zone_options_for_select
,options_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 偏移量。
资源:
我有类似的问题,但最终使用了这个
time_zone_select('time_zone', TZInfo::Timezone.us_zones,
:default => "America/Los_Angeles",
:model => TZInfo::Timezone
你找到更好的解决方案了吗?