通过Ruby / tzinfo获取给定日期时区的UTC偏移量?

时间:2017-08-09 17:16:01

标签: ruby datetime timezone timezone-offset tzinfo

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

给定来自Timezone的{​​{1}}对象,如何在给定时间点获得UTC偏移量(以时区或UTC的当地时间给出)?

2 个答案:

答案 0 :(得分:4)

您可以使用period_for_local method。对于这些示例,我使用的是我居住的时区(America/Sao_Paulo),其中冬季(3月至10月)的偏移量为-03:00,夏季为-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而不是{{1 }})。

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

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

PeriodNotFound

当DST结束时,2018年2月18日,午夜时钟转回第17个晚上11点(并且从# 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 偏移到-02:00),因此存在晚上11点到午夜之间的当地时间两次(两次补偿)。

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

period_for_local

如果您未指定第二个参数,则会出现# 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

答案 1 :(得分:1)

在Ruby 1.9.3中似乎存在一些hackery(DateTime to Time),可能会损失精度,但这是我根据@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