Ruby on Rails 中时区转换错误

4

我在这里真的遇到了困难。 基本上,我想要导入一个Excel文件。因此,我最终使用了Rails中的CSV导入。

CSV.open('[path-to-file]', 'r').each do |row|

实际上,导入操作正常运作,但Excel/CSV文件中有一个日期列,数据库中有一个日期时间列。在CSV.open方法中我做了以下操作:

date = DateTime.strptime(row[0], "%Y-%m-%d").strftime("%Y-%m-%d")
start_datetime = DateTime.parse(date + " 6:30:00").utc
Event.create(:event_start => start_datetime)

这将在数据库中创建正确的事件及其正确的日期时间。例如,看起来像这样:
2008-11-18 09:30:00

我的问题:
如果我选择注释掉application.rb中的这一行代码
config.time_zone = 'Berlin'

Rails使用UTC来显示我的事件,一切看起来都像数据库的内容。
如果我选择取消注释config.time_zone部分(我确实需要这样做),Rails应该添加1小时(柏林:UTC/GMT +1小时)。实际上,它至少会添加1小时,但有时会添加2小时。对我来说,没有任何联系,Rails何时选择添加1个或2个小时。
如果我在普通的Web界面(在浏览器中)上创建一个事件,一切都正常工作(减去1小时以保存UTC到DB并添加1小时以在正确的时区显示)。
如果您能提供一些提示,帮助我定位这个问题,那将非常有帮助。
我的系统:Rails 3.2.3 在 Ruby 1.9.3p194 上,MySQL 在 Suse Enterprise 上。
示例:
CSV:
2012-01-08
2012-02-09
2012-03-10
2012-04-11
2012-05-12
2012-06-13
2012-07-14
2012-08-15
2012-09-16
2012-10-17
2012-11-18
2012-12-19

数据库(MySQL):

| id | event_start
+----+---------------------    
|  1 | 2012-01-08 06:30:00
|  2 | 2012-02-09 06:30:00
|  3 | 2012-03-10 06:30:00
|  4 | 2012-04-11 06:30:00
|  5 | 2012-05-12 06:30:00
|  6 | 2012-06-13 06:30:00
|  7 | 2012-07-14 06:30:00
|  8 | 2012-08-15 06:30:00
|  9 | 2012-09-16 06:30:00
| 10 | 2012-10-17 06:30:00
| 11 | 2012-11-18 06:30:00
| 12 | 2012-12-19 06:30:00

浏览器视图 - 在这里,我只使用了一个 .order("event_start ASC")。

events.each do |ev|
ev.event_start

2012-12-19 07:30:00 +0100
2012-11-18 07:30:00 +0100
2012-10-17 08:30:00 +0200
2012-09-16 08:30:00 +0200
2012-08-15 08:30:00 +0200
2012-07-14 08:30:00 +0200
2012-06-13 08:30:00 +0200
2012-05-12 08:30:00 +0200
2012-14-11 08:30:00 +0200
2012-03-10 07:30:00 +0100
2012-02-09 07:30:00 +0100
2012-01-08 07:30:00 +0100

请注意您浏览器中的以下两个日期:2012-07-142012-14-11。第一个日期在最后一栏显示了14(表明这是日期列)。然而,后一个日期在第二栏显示了14(表明那是日期列)。这显然是矛盾的。 - Alfred Fazio
我也注意到了。我猜这是个错别字,应该是04-11(从记录的顺序来判断)。 - awendt
1个回答

4

我相信你看到的差异是因为夏令时(DST)。

请注意,夏季期间所有日期都是+0200,而其他时间都是+0100。这就是你没有注意到的联系。

这是因为柏林是一个带有DST的时区。你导入的日期都是UTC,它们被写入数据库为UTC,但Rails(正确地)根据它们是否在夏季来解释它们。

这就是为什么你没有得到一个恒定的1小时差异。

如果你想让时间在夏季和冬季都为当地时间9:30,请尝试使用

Time.zone.parse("#{date} 09:30:00")

在您的引入代码中。

有关详细信息,请参见ActiveSupport::TimeWithZone


1
太好了。谢谢你的回答。这是我最后想到的事情。救了我的一天 :) - michi
太棒了。真是太好了!非常感谢你。 - michi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接