如何获取带有 DST 偏移量的 time_zone_options_for_select ?
ActionView::Helpers::FormOptionsHelper 提供 time_zone_options_for_select 来获取选项列表用于包含所有时区及其 UTC 偏移量的选择控件。我遇到的问题是如何让它在夏令时生效时显示正确的偏移量?
例如,美国山区时间通常为 -7 UTC,但在夏季实际上为 -6 UTC。有没有办法让该列表正确反映这一点?
The ActionView::Helpers::FormOptionsHelper provides the time_zone_options_for_select to get a list of options for a select control that includes all of the timezones with their UTC offset. The problem I'm having is how to get it to display the correct offset for when daylight savings time is in effect?
For instance U.S. Mountain time is usually -7 UTC but during the summer it's effectively -6 UTC. Is there a way to have that list correctly reflect that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
TL;DR
您收到的时区数据是“正确的”,因为
ActiveSupport::TimeZone
和TZInfo::Timezone
实例不会对当前日期做出假设,因此就这些对象的责任而言,对它们应用 DST 没有“意义”。您注意到这个问题,因为
time_zone_options_for_select
,ActiveSupport::TimeZone
,不幸返回调用#to_s
时的偏移字符串,如果该位置当前正在遵守夏令时,则该偏移字符串将不正确。无法修复选项中生成的字符串值,甚至无法删除其中的偏移量。如果这是不可接受的,您需要跳过使用
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”问题:
阿德莱德的非 DST 时区是 ACST(澳大利亚中部标准时间),即 GMT+9.5。目前(截至撰写本文时),阿德莱德采用 DST,这意味着他们采用 ACDT(澳大利亚中部夏令时),即 GMT+10.5。
这里的关键区别本质上就是我上面概述的 - ActiveSupport::TimeZone 实例只是不关心当前日期。该类本身是一个围绕
TZInfo::DataTimezone
实例的便捷包装器,它对当前日期有类似的看法 - 没有。如果您注意到,在上面的第二个代码片段中,我们在调用
#utc_offset
之前对时区对象调用了#now
。这将返回一个 ActiveSupport::TimeWithZone 实例,其中包含有关时区的信息以及当前日期 - 因此我们得到一个偏移量,该偏移量反映了当前日期应包含 DST 偏移量这一事实。因此,这里唯一的问题是,在
ActiveSupport::TimeZone
实例上的#to_s
返回值中包含 UTC 偏移字符串在这种情况下有点误导。包含它是因为它是该时区的“基本”UTC 偏移量。资源:
time_zone_options_for_select
实现TL;DR
The time zone data you are receiving is "correct" because
ActiveSupport::TimeZone
andTZInfo::Timezone
instances do not make assumptions about the current date, and therefore applying DST to them doesn't make "sense" in the context of the responsibility of those objects.You notice the problem because the default model for
time_zone_options_for_select
,ActiveSupport::TimeZone
, unfortunately returns the offset string when calling#to_s
, which, if the location is currently is observing DST, will be incorrect. There is no way to fix the string values generated in the options, or even remove the offset from them.If this isn't acceptable you'll need to skip on using
time_zone_options_for_select
, and useoptions_for_select
instead, and generate the options yourself.Some investigation
time_zone_options_for_select
uses::ActiveSupport::TimeZone
as the defaultmodel
parameter, so passing it in manually will not change your results. In order to construct options for a select box, that method will construct an array of tuples in the format of[time_zone.to_s, time_zone.name]
, for the purpose of passing it to the more genericoptions_for_select
method.time_zone
, in this case, is an instance of::ActiveSupport::TimeZone
.The important factor here is that this time zone instance object is, conceptually, completely unrelated/divorced from the idea of "the current date". The definition of a time zone (strictly speaking) has nothing to do with the current date. We can confirm this "not using DST" issue like so:
Adelaide's non-DST time zone is ACST (Australian Central Standard Time) which is GMT+9.5. Currently (as in the time of writing), Adelaide is in DST which means they are on ACDT (Australian Central Daylight Time), which is GMT+10.5.
The crucial difference here is essentially what I've outlined above - the
ActiveSupport::TimeZone
instance is just not concerned with the current date. The class itself is a convenience wrapper around aTZInfo::DataTimezone
instance, which has similar opinions on the current date - none.If you noticed, in the second code snippet above, we called
#now
on the time zone object before calling#utc_offset
. This returns anActiveSupport::TimeWithZone
instance, which includes information about the time zone, as well as the current date - and therefore we get an offset which reflects the fact that the current date should include the DST offset.So, the only problem here is that including the UTC offset string in the return value of
#to_s
onActiveSupport::TimeZone
instances is sort of misleading in this instance. It's included because it's the "base" UTC offset for that time zone.Resources:
time_zone_options_for_select
implementation我遇到了类似的问题,但最终使用了这个,
你找到更好的解决方案了吗?
I had similar problem but ended up using this
Did you find a better solution?