以文本形式查询日期时间并包含不同的时区
Query datetime as text and include different timezones
短版:
我在数据库中有 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
所以我的 table 显示 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_param17:50
会找到user_id_33并且对于search_param11: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()
(但少index-friendly):
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,它使用 <timestamp> AT TIME ZONE <time zone>
运算符将其值解释为 UTC 中的值:
created_at AT TIME ZONE 'UTC'
然后,告诉 PostgreSQL 使用 <timestamp with time zone> AT TIME ZONE <time zone>
运算符(与上面的同名运算符完全不同)将此值偏移为 Asia/Jerusalem
中的本地时间:
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.
短版: 我在数据库中有 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
所以我的 table 显示 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_param17:50
会找到user_id_33并且对于search_param11: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()
(但少index-friendly):
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,它使用 <timestamp> AT TIME ZONE <time zone>
运算符将其值解释为 UTC 中的值:
created_at AT TIME ZONE 'UTC'
然后,告诉 PostgreSQL 使用 <timestamp with time zone> AT TIME ZONE <time zone>
运算符(与上面的同名运算符完全不同)将此值偏移为 Asia/Jerusalem
中的本地时间:
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.