【问题标题】:Rails 5: Not converting DateTime object timezone correctlyRails 5:未正确转换 DateTime 对象时区
【发布时间】:2017-10-01 16:21:34
【问题描述】:

这个问题已经困扰我一段时间了。

我取一个日期时间字符串:

[14] pry(#<EventsController>)> params[:event][:ended_at]
=> "05/31/2017 2:00 PM"

我将它转换为 DateTime 对象:

pry(#<EventsController>)> to_datetime = DateTime.strptime(params[:event][:ended_at], "%m/%d/%Y %H:%M %p")
=> Wed, 31 May 2017 14:00:00 +0000

如果我在 to_datetime 对象上运行 in_time_zone 方法,它会输出错误的太平洋时区时间:

[16] pry(#<EventsController>)> to_datetime.in_time_zone("Pacific Time (US & Canada)")
=> Wed, 31 May 2017 07:00:00 PDT -07:00

它应该读作“2:00PM”,与输入的方式相同。

如果我去 google 并检查“14:00:00 +0000”是否是 PDT 时间的正确条目,它会验证为正确:

http://imgur.com/a/ZJ80F

关于它为什么不能正确转换的任何线索?

【问题讨论】:

    标签: ruby-on-rails time ruby-on-rails-5


    【解决方案1】:

    错误是ended_at 被系统配置假定为“+0000”,您需要包含ended_at 所在的原始时区。

    irb(main):001:0> date = "05/31/2017 2:00 PM"
    => "05/31/2017 2:00 PM"
    irb(main):002:0> to_datetime = DateTime.strptime(date, "%m/%d/%Y %H:%M %p")
    => Wed, 31 May 2017 14:00:00 +0000
    

    请注意,这个已经设置为UTC,因为系统假定为时区

    irb(main):001:0> date = "05/31/2017 2:00 PM -0700"
    => "05/31/2017 2:00 PM -0700"
    irb(main):002:0> to_datetime = DateTime.strptime(date, "%m/%d/%Y %H:%M %p %z")
    => Wed, 31 May 2017 14:00:00 -0700
    irb(main):003:0> new_to_datetime = to_datetime.utc
    => Wed, 31 May 2017 21:00:00 +0000
    irb(main):004:0> new_to_datetime.in_time_zone("Pacific Time (US & Canada)")
    => Wed, 31 May 2017 14:00:00 PDT -07:00
    

    更新

    @antonio 的评论提到他请假 1 小时

    irb(main):046:0> time = DateTime.strptime(date + " Pacific Time (US & Canada)", "%m/%d/%Y %H:%M %p %Z").class
    => DateTime
    irb(main):047:0> time = DateTime.strptime(date + " Pacific Time (US & Canada)", "%m/%d/%Y %H:%M %p %Z")
    => Wed, 31 May 2017 14:00:00 -0800
    irb(main):048:0> time.utc.class
    => Time
    

    如您所见,这些是不同的类,这表明存在问题,您可以使用 Time 而不是 DateTime

    irb(main):049:0> time = Time.strptime(date + " Pacific Time (US & Canada)", "%m/%d/%Y %H:%M %p %Z")
    => 2017-05-31 14:00:00 -0700
    irb(main):050:0> time.class
    => Time
    

    【讨论】:

    • 几乎在那里。但是,我似乎抵消了一个小时的差异。我正在使用的字符串不包含“-0700”,因此我必须使用current_user 的时区(当前为“太平洋时间(美国和加拿大)”)对其进行格式化,如下所示:datetime_string = params[:event][:started_at] + " " + current_user.time_zone@987654331 @ 如果我在控制台中看到它是如何保存的,我会看到 Wed, 31 May 2017 20:00:00 UTC +00:00 这是下午 1 点,而不是像字符串一样的下午 2 点。我的做法有什么问题?
    • 我对此的唯一解释是,当您使用初始转换 strptime 时,没有检测到夏令时变化。我建议你使用time = Time.strptime(date + " Pacific Time (US &amp; Canada)", "%m/%d/%Y %H:%M %p %Z")
    • 我看到了你的编辑,我没有得到你在编辑中演示的任何 UTC 偏移量。我看到你的有 -0700 而我的显示 +0000 [2] pry(#&lt;EventsController&gt;)&gt; datetime_string =&gt; "05/31/2017 2:00 PM Pacific Time (US &amp; Canada)" [3] pry(#&lt;EventsController&gt;)&gt; time = Time.strptime(datetime_string, "%m/%d/%Y %H:%M %p %Z") =&gt; 2017-05-31 14:00:00 +0000
    • 不确定:|如果可行,我使用的是 ruby​​ 2.4.0
    【解决方案2】:

    如果我们查看您的第一次尝试:

    pry(#<EventsController>)> to_datetime = DateTime.strptime(params[:event][:ended_at], "%m/%d/%Y %H:%M %p")
    => Wed, 31 May 2017 14:00:00 +0000
    

    我们看到"05/31/2017 2:00 PM" 被正确解析在UTC,因此+0000 偏移量。

    然后,如果您将该 UTC 时间转换为 PDT,则应用 -7 小时调整:

    => Wed, 31 May 2017 07:00:00 PDT -07:00
    # -------------------------------^^^^^^
    

    并且14:00:00 变为07:00:00,因为14 - 7 == 7

    如果您希望 to_datetime 出现在 PDT 中,那么最简单的方法就是告诉 DateTime.strptime 时间戳字符串是 PDT:

    no_tz       = '05/31/2017 2:00 PM'
    to_datetime = DateTime.strptime("#{no_tz} PDT", '%m/%d/%Y %H:%M %p %z')
    # ------------------------------^^^^^^^^^^^^^^^---------------------^^
    

    然后你会得到你正在寻找的14:00:00 PDT

    > to_datetime.iso8601
    => "2017-05-31T14:00:00-07:00" 
    # -------------^^------^^^^^^
    

    【讨论】:

    • 我希望将 DateTime 保存为 UTC,以便所有用户所要做的就是选择他们的时区并显示调整为他们时区的 UTC 时间。我必须对代码进行哪些更改,以便用户可以看到用户选择Time.zone 的正确时间?
    • to_datetime.in_time_zone('UTC') 将为您提供 UTC 时间戳。
    猜你喜欢
    • 1970-01-01
    • 2015-10-26
    • 1970-01-01
    • 1970-01-01
    • 2018-04-07
    • 2013-08-25
    • 2011-06-25
    • 1970-01-01
    • 2020-11-21
    相关资源
    最近更新 更多