2010-12-17 62 views
19

在保持时区不变的情况下读取,写入和序列化日期和时间变得令人讨厌。我正在使用Ruby(和Rails 3.0),并试图改变DateTime的时区。 (到UTC),但不是时间本身。如何更改Ruby中DateTime的时区?

我想这一点:

t = DateTime.now 
t.hour 
-> 4 
t.offset = 0 
t.hour 
-> 4 
t.utc? 
-> true 

我来最接近的是这一点,但它并不直观。

t = DateTime.now 
t.hour 
-> 4 
t += t.offset 
t = t.utc 
t.hour 
-> 4 
t.utc? 
-> true 

有什么更好的办法吗?

+2

如果您实际上使用'now'作为时间戳,那么将其作为同一时间的UTC标记版本存储在数据库中是错误的,是正确的?当系统的所有部分都使用UTC时,我个人会遇到最少的麻烦,只有在我可能调整的视图中显示在服务器或浏览器的时区中时才会遇到。 – Phrogz 2010-12-17 20:43:20

+0

这很困难,因为我正在阅读时区未知或不相关的CSV文件中的日期,因此我将它们作为UTC存储在数据库中。但是,当使用本地区域的日期查询(即大于'2010/01/01 8:00 pm')时,它首先将该时间转换为UTC(我的问题的来源),然后再在查询中使用它。我试图让整个应用程序不受时区限制,以便用户可以在7:00 - 8:00范围内加载包含时间的CSV文件,然后查询7:00 - 8:00并返回同一组记录。相反,Ruby假定分析的时间在本地区域中。 – 2010-12-17 21:17:03

回答

35

使用Rails 3,您正在寻找DateTime.change()

dt = DateTime.now 
=> Mon, 20 Dec 2010 18:59:43 +0100 
dt = dt.change(:offset => "+0000") 
=> Mon, 20 Dec 2010 18:59:43 +0000 
+2

对于它的价值,.change似乎也可以在2.3中获得。 – joshaidan 2012-07-17 15:25:52

+7

更有帮助的是实际链接到答案。我认为这是一个:http://stackoverflow.com/questions/5941613/are-the-date-time-and-datetime-classes-necessary/14007547#14007547 – micapam 2013-04-16 07:54:00

+0

或简单DateTime.now.utc – courtsimas 2013-04-30 16:42:50

7

我会使用Time对象。因此,获得当前本地时间然后由UTC偏移增加它并转换为UTC,像这样:

t = Time.now # or Time.parse(myDateTime.asctime) 
t # => Thu Dec 16 21:07:48 -0800 2010 
(t + t.utc_offset).utC# => Thu Dec 16 21:07:48 UTC 2010 

虽然,每Phrogz评论,如果你只是想存储时间戳的位置无关的方式则只需使用当前UTC时间:

Time.now.utc 
+0

这是一个很大的表现。这似乎比我上面已经解决的解决方案更慢,更复杂。 – 2010-12-17 20:19:51

+0

如果你不特别关心DateTime对象(只是当前的即时),那么跳过解析并使用'Time.now'。我已经稍微编辑了我的答案。 – maerics 2010-12-17 21:06:41

+0

这与我上面的解决方案完全相同,但是有一个额外的字符串解析步骤。 – 2010-12-17 21:18:39

8
d = DateTime.now 
puts [ d, d.zone ] 
#=> 2010-12-17T13:28:29-07:00 
#=> -07:00 

d2 = d.new_offset(3.0/24) 
puts d2, d2.zone 
#=> 2010-12-17T23:28:29+03:00 
#=> +03:00 

编辑:这个答案不考虑通过评论提供给另一个答案的愿望是有报道“小时”是时间后同样的信息区域变化。

+0

'new_offset'听起来很有用,文档使它看起来像我以后的样子,但它只是从一个偏移量转换为另一个偏移量。正如问题所述,我希望改变偏移量,同时保持时间不变。 – 2010-12-17 21:06:12

+1

对我来说,这个'DateTime.now.new_offset(-8.0/24)'是这个页面上唯一可以用于我的目的的工具 - 用来放置银行交易。从太平洋时间,DST可以忽略不计。可能因为我的简单脚本不包括提到的框架,也没有任何活动。 – Marcos 2012-01-27 12:26:17

9

使用一些例如偏移由于夏令时,“+1000”全年不会工作。签出ActiveSupport :: TimeZone。 More info here

+2

提供使用“ActiveSupport :: TimeZone”而不仅仅是链接到文档的示例是首选。 – 2017-08-13 15:08:51

3

由于@Sam指出,改变偏移量是不够的,会导致错误。为了给DST时钟的进步性,转换应以下列方式进行:

d = datetime_to_alter_time_zone 
time_zone = 'Alaska' 

DateTime.new 
    .in_time_zone(time_zone) 
    .change(year: d.year, month: d.month, day: d.day, hour: d.hour, min: d.min, sec: d.sec) 
1

如果有人(比如我)在字符串格式一样时区的“太平洋时间(美国&加拿大)”

比,这是我找到的最好办法:

datetime.change(ActiveSupport::TimeZone[time_zone_string].formatted_offset(false) 
-1

您可以指定要通过添加以下行的配置文件在您的应用程序使用时区(配置/ application.rb中) : config.time_zone =“孟买”

你可以从这里找到相同的官方文档:http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html

另一种选择是,你“猴子补丁”的“日期时间”类。