(我在Ruby MRI 1.9.2上使用Rails 3.2.3)
所有内容都集中存储在UTC中。这很好。每个用户都有一个"时区"属性。我的ApplicationController有一个before过滤器,用于将Time.zone调整为用户存储的时区。这也很好。
如上所述,如果我的用户用时间完成了日期时间选择,那么该时间应该在time.zone中,Rails会自动调整并将其保存为UTC。这也很好。
现在:我希望我的用户能够在另一个时区填写一个时间,然后将其存储为UTC。但是,Rails希望已完成的日期-时间选择已在(以前由ApplicationController设置)time.zone中填写。因此,Rails错误地调整为UTC。
如何实现将输入的时间保存为第三时区的目标
插图:
我的使用场景是佛罗里达州的一位用户为西海岸一家酒店的文档调整日期。他们希望进入西海岸。
我使用jQuery通过样式选择器对文本框进行样式设置,因此我有一种方法可以向文本框输出字符串:
<%= f.text_field(:created_at, :value => adjusted_to_hotel_time(@document.created_at), :class => 'text datetime_picker') %>
def adjusted_to_hotel_time(time)
time.in_time_zone(@current_hotel.timezone).to_s(:admin_jquery) # formatted for the jQuery datetime_picker text fields.
end
这运行得很好,但在保存@文档时,Rails会错误地调整为UTC。我不知道我不知道的是——我如何将在该字段中输入的数据"标记"为@current_hotel.timezone,以便Rails在保存父对象时正确偏移到UTC?
破解了!
基本上,提交给params的字符串表示酒店时区中的时间。我们必须使用内置的"use_zone"方法将全局Time.zone临时设置为该酒店的。
然后,我们通过使用Hotel的时区,而不是User,向方法传递一个块,在那里我们产生Rails期望的值。这意味着Rails转换为UTC会在数据库中产生正确的时间,因为在表单中输入的时间已转换为Users时区。这些偏移实际上相互抵消了。
@document.created_at = Time.use_zone(@current_hotel.timezone) {Time.zone.parse("#{params[:document][:created_at]}").in_time_zone(@current_hotel.timezone)}
我们基本上是在这里更改Time对象的时区,而不是在时区更改时转换该Time对象的实际时间(祝你解析那句话好运!)
这看起来对我来说很好,但我已经研究了太久了,我很想看到一种更好的方法/更多的Rails ey方法!
datetime
列类型只存储日期和时间,而不存储时区。您可能需要创建一个辅助列,以保留用于解释保存在其中的UTC时间的时区。
这两个值可以结合起来重新创建初始输入。