【问题标题】:Storing dates in UTC after updating the user entered time zone to reflect proper UTC time在更新用户输入的时区以反映正确的 UTC 时间后以 UTC 存储日期
【发布时间】:2014-04-24 23:02:59
【问题描述】:

我有一个事件模型,它具有开始和结束日期/时间以及相关的时区。

我需要根据输入的时区将提交的日期时间存储在正确版本的 UTC 中。

例如,如果用户提交 2014-04-24 7PM EST

数据库应该是:

2014-04-24T23:00:00.000Z

不是这个:

2014-04-24T19:00:00.000-07:00

好的,我知道 Rails 以 UTC 存储所有内容,但我需要根据时区存储更新后的 UTC 时间 - 因为我的表单是 3 个字段,x2 日期/时间和 x1 时区

这是我认为可以正常工作的模型验证:

  def calc_utc_based_off_timezone
    time_zone = self.time_zone

    puts "start date before assignment: "
    puts self.start_date

    self.start_date = self.start_date.in_time_zone(time_zone)
    self.end_date = self.end_date.in_time_zone(time_zone)

    puts "start date after assignment: "
    puts self.start_date
  end

在我的表单中输入:

2014-04-24 - 19:00

2014-04-26 - 19:00

估计

输出:

分配前的开始日期:

2014-04-24 19:00:00 UTC

分配后的开始日期:

2014-04-24 19:00:00 UTC

我的期望:

分配前的开始日期:

2014-04-24 19:00:00 UTC

分配后的开始日期:

2014-04-24 23:00:00 UTC

任何帮助将不胜感激,谢谢。

【问题讨论】:

  • 您正在尝试转换为区域并返回 UTC?您永远不会从循环转换中获得不同的价值。 in_time_zone 不会增加时间或任何东西。似乎在这里您需要使用本地时区从您的时间中提取除时区之外的所有内容,然后转换为 UTC。
  • @aledalgrande 嗯,我想我想错了。很难相信没有人做过这个/或者没有日期函数来处理这个。如果我也做了你所指的提取,你的意思是手动添加或减去时间?
  • 要么这样,要么您必须以它已经具有与 UTC 不同的时区的方式生成时间。您当前正在执行此操作:UTC -> 其他 -> UTC。这不会改变最后的时间。你需要做的事情:其他的 -> UTC。
  • @canigetabreak 无需手动计算时区偏移量。只需设置 Time.zone = "EST" 或其他任何内容,rails 就会将输入时间解释为在该时区中。 “更新的 UTC”是什么意思? Rails 应用偏移量并将时间存储在 utc 中,当检索任何 datetime 对象时,rails 会抓取 Time.zone,然后应用它来显示您所在时区的时间,而数据库中的 utc 时间没有改变。

标签: ruby-on-rails ruby datetime ruby-on-rails-4


【解决方案1】:

ActiveSupport::TimeWithZone 类中支持带有时区的时间对象。 只要您在将参数提供给新对象函数Event.new(params[:event]) 之前设置时区,rails 就会应用设置的偏移量,并解释为就好像它在该时区中一样。

# example params like the request
params = {
          time_zone:"EST",
          event:{
            start_date:"2014-04-24 - 19:00",
            end_date:"2014-04-26 - 19:00"}
          }   

Time.zone = params[:time_zone] # pulled from a time_zone_select field
@event = Event.new(params[:event])

如果您有单独的时间和日期字段,只需将它们组合到数据库中保存日期时间的任何字段中。

params[:event][:start_date] = "#{params[:event][:start_date]} #{params[:event][:start_time]}"
params[:event][:end_date] = "#{params[:event][:end_date]} #{params[:event][:end_time]}"

@event = Event.new(params[:event])

时区偏移将自动应用,如果您检查对象,您应该得到以下信息。

> puts @event.start_date
2014-04-25 00:00:00 UTC
> puts @event.end_date
2014-04-27 00:00:00 UTC

这是处理 Rails 和时区的绝佳指南 - The Exhaustive Guide to Rails Time Zones

【讨论】:

  • 故事的寓意是在控制器端验证而不是模型端进行验证??我读对了吗?
  • 不一定是“验证”,但您需要做的就是确保在创建新对象之前将 Time.zone 设置在某处。您可以在应用程序控制器中的 before_filter 或就在实际代码之前。
  • 谢谢,我不知道为什么我会遇到这样的困难,但你的解释很有帮助。
  • 我在学习它时花了几个星期的时间,这里有一个很好的指南,可以让它更清晰。 The Exhaustive Guide to Rails Time Zones
【解决方案2】:

你是对的,Rails ActiveSupport 中有一些东西,

Time.parse("2014-04-24 - 19:00").in_time_zone

Thu, 24 Apr 2014 23:00:00 UTC +00:00

Time.parse("2014-04-24 - 19:00").getutc

2014-04-24 23:00:00 UTC

您还可以通过传递其他参数来指定响应的详细信息和格式(如 iso8601),如下所示:

> Time.parse("2014-04-24 - 19:00").getutc.iso8601(2)
"2014-04-24T23:00:00.00Z"
> Time.parse("2014-04-24 - 19:00").getutc.iso8601(3)
"2014-04-24T23:00:00.000Z"

ActiveSupport::TimeWithZone 的文档:http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html#method-i-getutc

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-11
    • 2014-11-01
    • 1970-01-01
    • 2018-05-08
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    相关资源
    最近更新 更多