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”的问题:
::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 实例的便捷包装器,它在当前日期有类似的意见 - 没有。
如果您注意到,在上面的第二个代码 sn-p 中,我们在调用 #utc_offset 之前在时区对象上调用了 #now。这将返回一个 ActiveSupport::TimeWithZone 实例,其中包括有关时区以及当前日期的信息 - 因此我们得到一个偏移量,它反映了当前日期应该包括 DST 偏移量这一事实。
因此,这里唯一的问题是在 ActiveSupport::TimeZone 实例上的 #to_s 的返回值中包含 UTC 偏移字符串在这种情况下有点误导。包含它是因为它是该时区的“基本”UTC 偏移量。
资源: