Ruby / Rails中的夏令时开始和结束日期

Daylight Saving Time start and end dates in Ruby/Rails

我正在开发一个Rails应用程序,在这个应用程序中,我需要找到给定特定偏移量或时区的夏令时开始和结束日期。

我基本上把从用户浏览器("+3""-5"收到的时区偏移量保存在我的数据库中,我想在它因夏令时而改变时对其进行修改。

我知道Time实例变量有dst?isdst方法,如果存储在这些方法中的日期在夏令时或非夏令时,这些方法返回真或假。

1
2
 > Time.new.isdst
 => true

但是使用这个来查找夏令时的开始日期和结束日期会占用太多资源,而且我还必须为我所拥有的每个时区偏移量执行此操作。

我想知道一个更好的方法。


好吧,根据你所说的和@dhouty的回答:

您希望能够输入一个偏移量并获取一组日期,以了解是否存在DST偏移量。我建议以一个由两个日期时间对象组成的范围结束,因为它很容易用于Rails中的许多用途…

1
2
3
4
5
6
7
8
9
10
11
12
require 'tzinfo'

def make_dst_range(offset)

  if dst_end = ActiveSupport::TimeZone[offset].tzinfo.current_period.local_end
     dst_start = ActiveSupport::TimeZone[offset].tzinfo.current_period.local_start
     dst_range = dst_start..dst_end
  else
     dst_range = nil
  end

end

现在,您有了一种方法,它不仅可以通过ActiveSupport附带的糖进行补偿。你可以这样做:

1
2
3
4
5
6
7
8
9
10
11
make_dst_range(-8)
#=> Sun, 08 Mar 2015 03:00:00 +0000..Sun, 01 Nov 2015 02:00:00 +0000

make_dst_range('America/Detroit')
#=> Sun, 08 Mar 2015 03:00:00 +0000..Sun, 01 Nov 2015 02:00:00 +0000

make_dst_range('America/Phoenix')
#=> nil     #returns nil because Phoenix does not observe DST

my_range = make_dst_range(-8)
#=> Sun, 08 Mar 2015 03:00:00 +0000..Sun, 01 Nov 2015 02:00:00 +0000

今天正好是8月29日,所以:

1
2
3
4
5
6
7
8
9
10
11
my_range.cover?(Date.today)
  #=> true
my_range.cover?(Date.today + 70)
  #=> false
my_range.first
  #=> Sun, 08 Mar 2015 03:00:00 +0000
  #note that this is a DateTime object. If you want to print it use:
my_range.first.to_s
  #=>"2015-03-08T03:00:00+00:00"
my_range.last.to_s
  #=>"2015-11-01T02:00:00+00:00"

ActiveSupport为您提供各种显示功能:

1
2
3
4
5
6
my_range.first.to_formatted_s(:short)
  #=>"08 Mar 03:00"
my_range.first.to_formatted_s(:long)
  #=>"March 08, 2015 03:00"
my_range.first.strftime('%B %d %Y')
   #=>"March 08 2015"

正如您所看到的,只使用偏移量是完全可行的,但是正如我所说,偏移量并不能告诉您所有的事情,所以您可能希望获取它们的实际时区并将其存储为一个字符串,因为该方法会很高兴地接受该字符串并仍然为您提供日期范围。即使您只是在您的区域和他们的区域之间获取时间偏移量,也可以很容易地将其更正为UTC偏移量:

1
2
3
my_offset = -8
their_offset = -3
utc_offset = my_offset + their_offset


你可能要找的是TZInfo::TimezonePeriod。具体来说,方法local_start/utc_startlocal_end/utc_end

给定时区偏移量,您可以使用

1
ActiveSupport::TimeZone[-8].tzinfo.current_period

或者,如果您有时区名称,也可以使用

1
ActiveSupport::TimeZone['America/Los_Angeles'].tzinfo.current_period