我有一个字符串,我用DateTime.strptime
. 字符串中日期的时区是 CET,但 Ruby 创建了一个 UTC DateTime 对象,该对象当然有 2 小时的偏移量。
目前我正在解决这个问题,DateTime.strptime().change(:offset => "+0020")
但我很确定这不是它的工作方式。
有人可以启发我正确的方法吗?
我有一个字符串,我用DateTime.strptime
. 字符串中日期的时区是 CET,但 Ruby 创建了一个 UTC DateTime 对象,该对象当然有 2 小时的偏移量。
目前我正在解决这个问题,DateTime.strptime().change(:offset => "+0020")
但我很确定这不是它的工作方式。
有人可以启发我正确的方法吗?
我通过以下方式使用它:
ruby-1.9.2-head :001 > require 'date'
=> true
ruby-1.9.2-head :002 > fmt = "%m-%d-%Y %H:%M:%S %Z"
=> "%m-%d-%Y %H:%M:%S %Z"
ruby-1.9.2-head :003 > DateTime.strptime "10-26-2011 10:16:29 CET", fmt
=> #<DateTime: 2011-10-26T10:16:29+01:00 (212186380589/86400,1/24,2299161)>
ruby-1.9.2-head :004 > DateTime.strptime "10-26-2011 10:16:29 UTC", fmt
=> #<DateTime: 2011-10-26T10:16:29+00:00 (212186384189/86400,0/1,2299161)>
ruby-1.9.2-head :005 > DateTime.strptime "10-26-2011 10:16:29 PST", fmt
=> #<DateTime: 2011-10-26T10:16:29-08:00 (212186412989/86400,-1/3,2299161)>
是你的意思吗?
这适用于 Rails 5:
Time.zone.strptime("2017-05-20 18:20:10", "%Y-%m-%d %H:%M:%S")
返回指定时区的时间。
至少从 Rails 4.2(可能更早,尚未测试)开始,只要您使用Time#strptime
而不是DateTime.strptime
,就会自动应用当前时区:
> DateTime.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> Wed, 28 Dec 2016 17:00:00 +0000
> Time.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> 2016-12-28 17:00:00 -0800
我正在“strptiming”这个字符串:
19/05/2014 8:13:26 a.m.
本地时间戳,在我的例子中是奥克兰 NZ,在字符串中没有时区戳,可以看出。
据我所知Time.strptime
,使用服务器时区作为基础。
在我的情况和一般的良好实践中,我的服务器在 UTC 时区运行,因此每次解析字符串最终都会创建一个时间对象,即 +0000 (UTC) 的时间:
2014-05-19 08:13:26 +0000
然后转换为in_time_zone(Time.zone)
:
Mon, 19 May 2014 20:13:26 NZST +12:00
可以看出比我想要的实际时间晚了 12 小时(UTC 偏移量)。
我试着+' Auckland', '...%Z'
按照上面的方法使用这个技巧,没有任何改变。然后我+ '+1200', '...%Z'
按照上面的方法使用了正确工作的技巧。
但是我担心夏季时间,然后解析会提前一个小时,所以这就是我完成的:
Time.strptime(call_data[:datetime].gsub(/\./, "").gsub(/am/, "AM").gsub(/pm/, "PM") + (Time.zone.now.time_zone.utc_offset/3600).to_s.ljust(4,'0').rjust(6,' +'), '%d/%m/%Y %I:%M:%S %p %Z').in_time_zone(Time.zone)
结果:
Mon, 19 May 2014 08:13:26 NZST +12:00
它不是特别优雅,但它确实有效。
您可以使用 将日期转换为时区to_time_in_current_zone
。例如:
Date.strptime('04/07/1988', '%m/%d/%Y').to_time_in_current_zone
我一直在与同样的问题作斗争,试图从表单中解析日期字符串并独立于服务器时间保存它。我遵循的过程就是这样。我保证 RoR 和 Ruby 时区设置为 UTC。如果服务器也处于 UTC 时间,它会更容易。
我正在使用 ActiveSupport:TimeZone 格式存储用户区域设置,就像US/Eastern
我有一个解释日期函数一样,它可以解释一个本机不包含时区或偏移量的日期字符串
# date_str looks something like this `12/31/2014 6:22 PM`
# tz is a string containing an ActiveSupport::TimeZone name like `US/Eastern`
def interpret_date(date_str, tz)
Time.use_zone tz do
parsed_dt = DateTime.strptime(date_str, '%m/%d/%Y %H:%M %p')
offset = parsed_dt.in_time_zone(tz).utc_offset
parsed_dt.advance(seconds: -(offset)).in_time_zone(tz)
end
end
这当然感觉不是一个完美的解决方案,但它确实有效。确保正确时区的步骤是:
对于前 Rails 5,以下将起作用:
t0 = Time.strptime("2018-05-01", "%Y-%m-%d") # Or whatever
t1 = Time.zone.now.change(year: t0.year, month: t0.month, day: t0.day, hour: t0.hour, min: t0.min, sec: t0.sec, usec: t0.usec)
我无法删除已接受的答案
正如@LeeJarvis 在下面的评论部分中指出的那样,Chronic.parse
不接受:time_class
选项。所以这个答案是错误的,虽然它看起来有效,但它没有(除非慢性允许:time_class
很快通过一个选项。)
慢性宝石真的很强大。
我这样使用它:
Chronic.parse("next 5:00 pm",
:time_class => ActiveSupport::TimeZone.new(User.first.time_zone)).utc
在我上面的示例中,User.first.time_zone
是“太平洋时间(美国和加拿大)”。
Chronic 支持多种格式,请访问 https://github.com/mojombo/chronic
确保传递:time_class
选项并转换为 UTC(在文档中,:time_class
调用 parse 之前的 Chronic 设置。我避免使用这种方法,因为它可能会导致应用程序中的其他部分无法工作)
TimeZone 的文档位于 http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html