带时区的Strptime

Posted

技术标签:

【中文标题】带时区的Strptime【英文标题】:Strptime with Timezone 【发布时间】:2011-12-16 02:02:41 【问题描述】:

我有一个字符串,我用DateTime.strptime 解析它。字符串中日期的时区是 CET,但 Ruby 创建了一个 UTC DateTime 对象,该对象当然有 2 小时的偏移量。

目前我正在解决DateTime.strptime().change(:offset => "+0020") 的问题,但我很确定这不是它的工作方式。

有人能告诉我正确的方法吗?

【问题讨论】:

如果您所在的国家/地区有 CEST/CET 时区,则固定偏移量将不起作用。对此也感兴趣,我看不到如何让 strptime 解析当前时区(但不是现在的值,正确的值取决于解析的字符串)。 【参考方案1】:

我是这样使用的:

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)> 

这是你的意思吗?

【讨论】:

我没有确定解析字符串中的时区的字符串。它的 10-26-2011 10:16:29 而不是“10-26-2011 10:16:29 CET” 你解决了我的问题,我可以"09-19-2012 11:08:44" + " CST"。我认为你的答案是正确的。 当你进入夏令时怎么办?这+“CST”不应该更知情吗?根据上面的评论,如果我们可以根据刚刚格式化的时间来选择它会很好......我正在学习讨厌时区。【参考方案2】:

我无法删除已接受的答案

正如@LeeJarvis 在下面的评论部分指出的那样,Chronic.parse 不接受:time_class 选项。所以这个答案是错误的,虽然它看起来有效,但它没有(除非 Chronic 允许很快通过 :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(在文档中,Chronic 在调用解析之前设置:time_class。我避免使用这种方法,因为它可能会导致整个应用程序的其他部分无法工作)

TimeZone 的文档位于 http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html

【讨论】:

这个答案不正确。 parse() 不采用 time_class 选项。它直接在Chronic 类上设置。不过,这最终会在未来版本的 Chronic 中改变 我的错...我会删除,直到此选项可用 =) 呃...我无法删除已接受的答案。我会在上面发表评论。【参考方案3】:

您可以使用to_time_in_current_zone 将日期转换为时区。例如:

Date.strptime('04/07/1988', '%m/%d/%Y').to_time_in_current_zone

【讨论】:

apidock.com/rails/Date/to_time_in_current_zone 方法被贬值了抱歉 :(【参考方案4】:

我正在“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

它不是特别优雅,但它确实有效。

【讨论】:

【参考方案5】:

我一直在与同样的问题作斗争,试图从表单中解析日期字符串并独立于服务器时间保存它。我遵循的过程就是这样。 我保证 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

这当然不是一个完美的解决方案,但它确实有效。 确保正确时区的步骤是:

    根据我们的格式解析日期字符串 根据该时区的时间提取当前的 utc 偏移量(如果您解析的日期恰好在 dst 中,而您的本地时间不是东部时间的 dst,我们必须这样做,这将确保 dst 是本地时间到解析的时间) 将时间转换为我们的目标语言环境,并允许时间在添加正确的偏移量的情况下发生变化

【讨论】:

【参考方案6】:

至少从 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

【讨论】:

这使用机器的时区,而不是 Rails 中设置的时区,顺便说一句。 @Sean 是的,没错。解决方法是对 Rails 5+ 使用 Time.zone.strptime 或 Time.zone.local_to_utc(DateTime.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:% M %p')) 用于旧版本的 Rails【参考方案7】:

这适用于 Rails 5:

Time.zone.strptime("2017-05-20 18:20:10", "%Y-%m-%d %H:%M:%S")

返回指定时区的时间。

【讨论】:

【参考方案8】:

对于前 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)

【讨论】:

以上是关于带时区的Strptime的主要内容,如果未能解决你的问题,请参考以下文章

使用strptime进行Python解析 - 月日时间:分钟:秒年时区 - 与格式不匹配

将时区缩写解析为 UTC [重复]

时区不正确

数据类型“带时区的时间戳”中的时区存储

java时间转换,带时区的

带 ActiveSupport 的默认时区(不带 Rails)