简短版: 我在数据库中有 2 个用户,每个用户都在不同的时区创建:
User.find(1).created_at
=> Thu, 04 Aug 2016 11:15:29 IDT +03:00
User.find(33).created_at
=> Sun, 01 Jan 2017 17:50:20 IST +02:00
所以我的表显示 11:15 和 17:50。例如,我想搜索 17:50
,然后搜索 11:15
作为文本:
search_param = '17:50'
没问题,我只是将日期转换为文本,然后进行搜索,但是找不到用户,因为它已保存为 UTC:
User.where("to_char(created_at,'DD-Mon-YYYY HH24:MI:SS') ilike ?", "%#{search_param}%").first
=> nil
为了找到它,我只需将偏移量应用于我的查询(添加时区 UTC+2),并且确实找到了用户:
User.where("to_char(created_at AT TIME ZONE 'UTC+2','DD-Mon-YYYY HH24:MI:SS') ilike ?", "%#{search_param}%").first
=> User #33 @2017-01-01 17:50:20 +0200
但有些用户保存为 UTC+3,有些保存为 UTC+2.. 我不能同时应用两个偏移量...所以如果我将 search_param
更改为 11:15
我找不到 user_id_1 因为我还需要将 UTC+2
更改为 UTC+3
- 当我使用 UTC+2 时,我只会找到创建为 +2 的用户(如
User.find(33)
)。 - 当我使用 UTC+3 时,我只会找到创建为 +3 的用户(如
User.find(1)
)。
我的问题:如何执行 where 查询 - 对两个用户的 created_at
时间进行文本搜索,因为他们都保存在不同的时区偏移量中?
或者在这个例子中,查询对于 search_param 17:50
会找到 user_id_33 而对于 search_param 11:15
会找到 user_id_1?
更多详情:
我注意到在数据库中它们被保存为 UTC(我认为):
User.select("created_at as created_at_db").find(33).created_at_db
=> "2017-01-01 15:50:20.903289"
User.select("created_at as created_at_db").find(1).created_at_db
=> "2016-08-04 08:15:29.171776"
时间设置:
#application.rb
config.time_zone = 'Jerusalem'
config.active_record.default_timezone = :utc
created_at 列信息:
User.columns.select{|table_col| table_col.name == 'created_at'}
=> [#<ActiveRecord::ConnectionAdapters::PostgreSQLColumn:0x81f9c48
@coder=nil,
@default=nil,
@limit=nil,
@name="created_at",
@null=false,
@precision=nil,
@primary=false,
@scale=nil,
@sql_type="timestamp without time zone",
@type=:datetime>]
最佳答案
您应该能够查询您的用户实体:
date_trunc('minute', created_at AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Jerusalem')::time = '17:50'
或者,使用 to_char()
(但对索引不太友好):
to_char(created_at AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Jerusalem', 'HH24:MI') = '17:50'
重点是 created_at
是timestamp
(或 timestamp without time zone
,这只是一个别名)。首先,您可以告诉 PostgreSQL,它以 UTC 格式解释其值,使用 <timestamp> AT TIME ZONE <time zone>
运算符(operator):
created_at AT TIME ZONE 'UTC'
然后,告诉 PostgreSQL 偏移这个值,就好像它是 Asia/Jerusalem
中的本地时间一样与 <timestamp with time zone> AT TIME ZONE <time zone>
运算符(与上面的同名运算符完全不同):
created_at AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Jerusalem'
现在,您只需截断此值以仅提取小时和分钟部分。
也许值得一提的是使用这些:
created_at AT TIME ZONE 'UTC+2'
created_at AT TIME ZONE 'UTC+3'
不小心为你工作。这些创建 timestamp with time zone
值 within the -2
and -3
UTC偏移量,分别。那么,因为你的 config.active_record.default_timezone
设置为 :utc
, 它在 UTC 时区内发送给您的客户端 (ruby),这意味着它添加了 2
和 3
小时,分别。
Another issue to keep in mind is that in POSIX time zone names, positive offsets are used for locations west of Greenwich. Everywhere else, PostgreSQL follows the ISO-8601 convention that positive timezone offsets are east of Greenwich.
关于sql - 以文本形式查询日期时间并包含不同的时区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42110246/