在ruby中,如何为任意时区的任意未来时间创建UTC时间,并考虑DST(适用时)?

时间:2012-11-05 02:30:31

标签: ruby-on-rails timezone

在调度方法中,我需要获取(local_date,local_time和local_time_zone),并返回相应的utc time accounting ,以了解夏令时是否对 生效/ em> date。

我不想更改Time.zone,因为在线程安全的情况下,它会在多个请求中持续存在完全意外的结果 - 这是一件坏事。

以下(0800太平洋时间)不起作用,因为它们在UTC(16:00)返回相同的时间,即使第一天(10月1日)是夏令时,第二天(12月1日)不是在夏令时,所以UTC应该是不同的

Time.new(2012, 10, 1, 8, 0, 0, ActiveSupport::TimeZone['Pacific Time (US & Canada)'].utc_offset).utc
# 2012-10-01 16:00:00 UTC <<<< should be 15:00

Time.new(2012, 12, 1, 8, 0, 0, ActiveSupport::TimeZone['Pacific Time (US & Canada)'].utc_offset).utc
# 2012-12-01 16:00:00 UTC 

我曾希望.utc方法会考虑夏令时是否有效,但事实并非如此。

我不确定我是否应该使用Time对象,DateTime对象和TimeWith Zone等。

===

注意:有一种方法可以使用Chronic gem(下面)。但是我想使用内置的Ruby Date和Time方法来获得相同的(例如,正确的)结果:

Chronic.time_class =ActiveSupport::TimeZone["Pacific Time (US & Canada)"]
Chronic.parse("10/1/2012 0800").utc
# 2012-10-01 15:00:00 UTC 
Chronic.parse("12/1/2012 0800").utc
# 2012-12-01 16:00:00 UTC 

2 个答案:

答案 0 :(得分:0)

我最近经历了类似的事情,发现Time.zone.local可以很好地将夏令时考虑在内。我不确定美国的夏令时,但2013年10月6日澳大利亚的夏令时开始了。

以下代码似乎对我有用:

1.9.3-p194 :009 > Time.zone = 'Sydney'
 => "Sydney" 
1.9.3-p194 :010 > Time.zone.local(2013, 10, 1, 0, 0, 0).utc
 => 2013-09-30 14:00:00 UTC 
1.9.3-p194 :011 > Time.zone.local(2013, 10, 10, 0, 0, 0).utc
 => 2013-10-09 13:00:00 UTC 

您确定您的日期/时区是否正确?根据此页面,太平洋时间似乎在11月经历了夏令时: http://www.timeanddate.com/worldclock/timezone.html?n=137

答案 1 :(得分:0)

在另一个SO线程上找到它:诀窍是将时间(和区域)放入Time.parse可用的格式中:

Time.parse("2012-10-1 8:00:00 Pacific Time (US & Canada)").utc
# 2012-10-01 15:00:00 UTC 

Time.parse("2012-12-1 8:00:00 Pacific Time (US & Canada)").utc
# 2012-12-01 16:00:00 UTC

另一种方法(可能更好):

ActiveSupport::TimeZone["Pacific Time (US & Canada)"].parse("2012-12-1 8am").utc

在玩了一些游戏之后,我们似乎对改变Time.zone只是为了在某个区域中创建一个时间是谨慎的 - 设置Time.zone可以“坚持”多个请求(在同一个线程中)。因此,如果您有两个不同的窗口打开到rails应用程序,并且正在查看两个不同的帐户,则在一个窗口中为该帐户设置Time.zone实际上可以更改另一个帐户的另一个窗口中的Time.zone。