1

tzinfo对于任何了解API的人来说,这可能都是微不足道的:

给定一个Timezone来自 的对象tzinfo,我如何获得给定时间点的 UTC 偏移量(在时区的本地时间或 UTC 中给出)?

4

2 回答 2

5

你可以使用period_for_local方法。对于这些示例,我使用的是我居住的时区 ( America/Sao_Paulo),其中偏移量是-03:00在冬季(3 月到 10 月)和-02:00夏季(夏令时):

# Sao Paulo timezone
zone = TZInfo::Timezone.new('America/Sao_Paulo')

# date in January (Brazilia Summer Time - DST)
d = DateTime.new(2017, 1, 1, 10, 0)

period = zone.period_for_local(d)
puts period.offset.utc_total_offset / 3600.0

# date in July (Brazilia Standard Time - not in DST)
d = DateTime.new(2017, 7, 1, 10, 0)

period = zone.period_for_local(d)
puts period.offset.utc_total_offset / 3600.0

输出是:

-2.0
-3.0

utc_total_offset方法以秒为单位返回偏移量,因此我除以 3600 得到以小时为单位的值。

请注意,我也曾经3600.0将结果强制为浮点数。如果我只使用3600,结果将被四舍五入,并且时区Asia/Kolkata(偏移量为+05:30)将给出不正确的结果(5而不是5.5)。


请注意,您必须注意 DST 更改,因为您可以有间隙或重叠。

在圣保罗时区,夏令时从 2017 年 10 月 15 日开始:在午夜,时钟向前移动到凌晨 1 点(偏移量从-03:00变为-02:00),因此 00:00 和 01:00 之间的所有当地时间都无效。在这种情况下,如果您尝试获取偏移量,则会出现PeriodNotFound错误:

# DST starts at October 15th, clocks shift from midnight to 1 AM
d = DateTime.new(2017, 10, 15, 0, 30)
period = zone.period_for_local(d) # error: TZInfo::PeriodNotFound

当 DST 在 2018 年 2 月 18 日结束时,午夜时钟移回 17 日晚上 11 点(偏移量从-02:00变为-03:00),因此晚上 11 点到午夜之间的当地时间存在两次(在两个偏移量中)。

在这种情况下,您必须指定您想要的(通过设置 的第二个参数period_for_local),指示您是否想要 DST 的偏移量:

# DST ends at February 18th, clocks shift from midnight to 11 PM of 17th
d = DateTime.new(2018, 2, 17, 23, 30)
period = zone.period_for_local(d, true) # get DST offset
puts period.offset.utc_total_offset / 3600.0 # -2.0

period = zone.period_for_local(d, false) # get non-DST offset
puts period.offset.utc_total_offset / 3600.0 # -3.0

如果不指定第二个参数,会TZInfo::AmbiguousTime报错:

# error: TZInfo::AmbiguousTime (local time exists twice due do DST overlap)
period = zone.period_for_local(d)
于 2017-08-09T19:47:03.903 回答
1

似乎在 Ruby 1.9.3 中涉及到一些骇客(日期时间到时间),可能会丢失精度,但这是我根据@Hugo 的回答得出的结果:

module TZInfo

class Timezone

    def utc_to_local_zone(dateTime)
        return dateTime.to_time.getlocal(self.period_for_utc(dateTime).utc_total_offset)
    end

    def offset_to_s(dateTime, format = "%z")
        return utc_to_local_zone(dateTime).strftime(format)
    end 
end

end
于 2017-08-10T15:40:10.370 回答