我知道那里有几十个类似的问题,更不用说关于Interwebs的一般文章了,但是我仍然很难理解Rails如何在内部与Time Zones一起工作。
我目前在我的应用程序文件中配置了config.time_zone = 'Eastern Time (US & Canada)'
,因为这是我和其他项目管理员所在的位置。拥有该网站的公司位于加利福尼亚州,因此他们将在太平洋时间。该应用程序拥有全球受众,虽然我们还没有这样做,但我们最终将实现用户首选时区。
所以我目前的问题:
我知道Rails分别在存储和检索时会神奇地将日期时间列值转换为UTC,但是查看给定日期时间属性的本地版本的正确方法是什么?
何时会使用Time.now
与Time.zone.now
对Time.now.in_time_zone
对DateTime.now
与DateTime.now.in_time_zone
对比{/ 1>}
将给定的datetime属性与上面列出的方法或相对于当前配置的时区的某些其他特定时间进行比较的正确方法是什么?使用UTC?
我们会有一些时间敏感的东西,比如需要根据应用程序的时区在特定时间发布的文章,所以如何让应用程序在我们指定的时区进行比较,而不是当前配置一个(假设用户时区已实现?)
(新问题)如果我在以后将config.time_zone
更改为UTC
会怎样?我是否必须在数据库中重置所有时间,否则会影响旧时间?
答案 0 :(得分:8)
首先,重要的是要了解rails的时区内容主要是关于演示。在幕后,一切都发生在UTC。
Q1。在控制台上,Rails将在您的默认时区中显示时间,因此Something.last.created_at
会在Time.zone指定的区域中显示该时间戳
Q2。所有这些都返回一个代表'now'的对象。 DateTime与时间的选择与时区无关。例如,如果您需要能够表示unix时期之外的时间,请使用DateTime。 Time.now
和Time.zone.now
之间的区别在于您是否返回Time的实例(将在服务器的本地时区中作为控制器)。这可以控制例如to_s
返回的内容,但不会表示当前的时间:
SomeModel.create(:time_attribute => Time.now)
SomeModel.create(:time_attribute => Time.zone.now)
会将同一行插入数据库。如果您只是向用户显示时间(例如,如果您的站点显示标题中的当前时间),那么您应该使用Time.zone.now
以便它以正确的时区显示。如果你只是将它存储在数据库中那么它并不重要 - 无论如何,activerecord会将它转换为TimeWithZone。
Q3。 TimeWithZone
上的比较方法是通过比较日期的utc版本来实现的,因此您可以安全地比较不同区域中的时间 - 您无需将它们转换为某个公共时区。您还可以将TimeWithZone实例与普通时间对象进行比较。
Q4。你通常不需要做任何事情。实现此目的的常用方法是在模型上使用published_at
属性。显示列表文章的页面将添加
where('published_at <= ?', Time.now)
查询的条件。在创建文章时,Rails从表单中获取日期时间并将其转换为utc,因此存储在数据库中的是published_at
时间的utc版本。比较是时区独立的,因此无论时区是什么,查询都能正常工作。
这可能会变得很复杂,只有纯粹的时间(例如'4pm'),因为时区转换只有在你知道日期时才能正确完成(即你知道精确的时刻),这取决于DST (或国家改变其时区的政治事件)与UTC变化的偏差。在这种情况下,您通常只想存储一天中的时间,并且只有在知道日期时才将其转换为完整时间。
Q5。 Rails始终将UTC存储在数据库中。这样做的直接后果是更改config.time_zone
不需要您更改存储在数据库中的数据。您甚至可以基于每个用户设置Time.zone
,以便用户在其时区中查看时间 - config.time_zone
只控制Time.zone的默认值