Rails和PostgreSQL中的TimeZone和DST

问题描述 投票:1回答:2

背景

带有默认created_at列的商品模型

Rails config.time_zone = 'Warsaw'

我有一篇有关created_at =当地时间2012-08-19 00:15(UTC中的2012-08-18 22:15的文章。

目标

[接收所有在2012-08-19(当地时间)创建的文章。

我的(无法正常工作)解决方案

Article.where(
  "date_trunc('day', created_at AT TIME ZONE '#{Time.zone.formatted_offset}')
   = '#{Date.civil(2012, 8, 19)}'"
)

哪个生成SQL:

SELECT "articles".* FROM "articles"
WHERE (date_trunc('day', created_at AT TIME ZONE '+01:00') = '2012-08-19')

并返回一个空集。但是,如果我在psql中运行相同的查询,它将返回一条文章...使我感到困惑。

问题

我在做什么错以及如何解决?

ruby-on-rails postgresql datetime dst rails-postgresql
2个回答
5
投票

目标:接收2012年8月19日(当地时间)创建的所有文章。

'+01:00'(就像您使用它)是一个fixed时间偏移,并且不能考虑DST(夏令时)。为此使用时区name(不是缩写)。这些在PostgreSQL中可用:

SELECT * FROM pg_timezone_names;

对于华沙,这应该是'Europe/Warsaw'。系统从其存储的信息中了解DST的范围,并应用相应的时间偏移。


此外,您的查询可以简化。

由于'Europe/Warsaw'created_at,所以保存的值反映了创建行时服务器的本地时间(内部保存为UTC时间戳)。

基本上只有两种可能,具体取决于客户所在的时区。

  1. 您的阅读客户端使用timestamp [without time zone]相同设置作为书写客户端:只是强制转换为最新。

    timezone
  2. 您的阅读客户端以timezone不同设置运行,而不是书写客户端:添加SELECT * FROM articles WHERE created_at::date = '2012-08-19'; '。例如,如果是timezone,则看起来像:

    timezone

AT TIME ZONE '<tz name of *writing* client here>的双重申请,就像您在已发布的答案中一样,应该不是

注意时区name,而不是缩写。参见:

  • Europe/Warsaw

如果您的应用程序跨越多个时区..

..将... WHERE (created_at AT TIME ZONE 'Europe/Warsaw')::date = '2012-08-19'; 的列默认设置为AT TIME ZONE-或其他时区,重点是:在各处使用相同的值。

..或最好,切换到Time zone names with identical properties yield different result when applied to timestampcreated_at)。


0
投票

now() AT TIME ZONE 'UTC'帮助了。我必须运行以下查询:

timestamptz

此问题将需要对created_at列的确切定义(确切的数据类型是什么?]

Rails总是将created_at列创建为没有时区的时间戳。因此,我必须使第一个timestamp with time zone表示该时间戳记为UTC的dbms,第二个要显示CEST区域的日期的时间。

© www.soinside.com 2019 - 2024. All rights reserved.