如何在指定的时区中创建一个新的DateTime对象(最好是我的应用程序的默认时区,而不是UTC)?

46
我已经在/config/application.rb中设置了时区,我希望应用程序中生成的所有时间默认都是这个时区,但是当我创建一个新的DateTime对象(使用.new)时,它会在GMT中创建。如何让它处于我的应用程序的时区?
config.time_zone = 'Pacific Time (US & Canada)'

irb

的翻译是:

irb

DateTime.now
# => Wed, 11 Jul 2012 19:04:56 -0700 

mydate = DateTime.new(2012, 07, 11, 20, 10, 0)
# => Wed, 11 Jul 2012 20:10:00 +0000                    # GMT, but I want PDT

使用 in_time_zone 并不能起作用,因为它只会将 GMT 时间转换为 PDT 时间,这是错误的时间:

mydate.in_time_zone('Pacific Time (US & Canada)')
# => Wed, 11 Jul 2012 13:10:00 PDT -07:00               # wrong time (I want 20:10)
6个回答

41

您可以使用 ActiveSupport 的 TimeWithZone (Time.zone) 对象,以应用程序的时区创建和解析日期:

1.9.3p0 :001 > Time.zone.now
 => Wed, 11 Jul 2012 19:47:03 PDT -07:00 
1.9.3p0 :002 > Time.zone.parse('2012-07-11 21:00')
 => Wed, 11 Jul 2012 21:00:00 PDT -07:00 

3
非常有帮助!但是如果你想在一个不同于config/application.rb中设置的时区创建时间,该怎么办? - idrinkpabst
我会使用类似'2012-07-11 21:00'.to_datetime.in_time_zone('Eastern Time (US & Canada)')的代码。 - Peter Brown
4
实际上这并不起作用。假设你想创建一个在东部时间上午9点的时区。如果你执行'2012-07-11 09:00'.to_datetime.in_time_zone('Eastern Time (US & Canada)'),它会返回错误的时间,因为它是从协调世界时(UTC)转换的。如果你执行'2012-07-11 09:00 Eastern Time (US & Canada)'.to_datetime.in_time_zone('Eastern Time (US & Canada)'),这仍然不起作用,因为DateTime在处理夏令时时出问题。最好完全避免使用DateTime。有什么想法吗? - idrinkpabst

13

另一种无需字符串解析的方法:

irb> Time.zone.local(2012, 7, 11, 21)
=> Wed, 07 Nov 2012 21:00:00 PDT -07:00

参数与 DatTime.new 方法不同。Time.zone.local 不接受 0 或 -1 作为参数,会导致参数超出范围的错误。 - Tun

7

如果我想要指定时区偏移量,通常在实例化Time.new或DateTime.new时,只需要指定utc_offset。

[1] pry(main)> Time.new(2013,01,06, 11, 25, 00) #no specified utc_offset defaults to system time
 => 2013-01-06 11:25:00 -0500
[2] pry(main)> Time.new(2013,01,06, 11, 25, 00, "+00:00") #UTC
 => 2013-01-06 11:25:00 +0000
[3] pry(main)> Time.new(2013,01,06, 11, 25, 00, "-08:00") #PST
 => 2013-01-06 11:25:00 -0800 

5

如果您想在本地时区创建一个DateTime,该时区与config.time_zone设置的时区不同

la_date = ActiveSupport::TimeZone["America/Los_Angeles"].parse('2020-02-01')
DateTime.new(la_date.year, la_date.month, la_date.day, la_date.hour, la_date.min, la_date.sec, la_date.zone)

1
如果您不想解析,也可以使用 local。例如:ActiveSupport::TimeZone["America/Los_Angeles"].local(2020, 1, 1, 12, 0).to_datetime - Chad M

2
这也可以在DateTime类中实现,包括时区信息。
2.5.1 :001 > require 'rails'
 => true
2.5.1 :002 > mydate = DateTime.new(2012, 07, 11, 20, 10, 0)
 => Wed, 11 Jul 2012 20:10:00 +0000
2.5.1 :003 > mydate = DateTime.new(2012, 07, 11, 20, 10, 0, "PST")
 => Wed, 11 Jul 2012 20:10:00 -0800

或者

https://docs.ruby-lang.org/en/2.6.0/DateTime.html

2.6.0 :001 > DateTime.new(2012, 07, 11, 20, 10, 0, "-06")
 => Wed, 11 Jul 2012 20:10:00 -0600
2.6.0 :002 > DateTime.new(2012, 07, 11, 20, 10, 0, "-05")
 => Wed, 11 Jul 2012 20:10:00 -0500

0
在ApplicationController中,我会执行以下操作将时区设置为用户的时间。
我不确定这是否是您想要的。
class ApplicationController < ActionController::Base
  before_filter :set_timezone
  def set_timezone
    # current_user.time_zone #=> 'London'
    Time.zone = current_user.time_zone if current_user && current_user.time_zone
  end

end

1
这不是我在寻找的,但感谢您的发布。也许对其他人有帮助。 - user664833

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