sql - 以文本形式查询日期时间并包含不同的时区

标签 sql ruby-on-rails postgresql ruby-on-rails-3

简短版: 我在数据库中有 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_attimestamp (或 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 zonewithin the -2 and -3 UTC偏移量,分别。那么,因为你的 config.active_record.default_timezone设置为 :utc , 它在 UTC 时区内发送给您的客户端 (ruby),这意味着它添加了 23小时,分别。

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/

相关文章:

sql - 使用 order by 选择前 4 个,但仅在实际需要时?

聚合上的MySQL语法查询

sql - Arel#extract方法在rails中如何使用?

ruby-on-rails - 当我在heroku上部署rails应用程序时,步骤 "verifying deploy.."不会停止。最后部署失败

postgresql - 无法使用 pgAdmin 将 PostgreSQL 连接到远程数据库

sql - 在 Postgresql 中选择正聚合值并忽略负值

ruby-on-rails - 通过 searchkick 进行多语言搜索

sql - 如何检查给定模式中是否存在表

python - 即使没有任何更改,Alembic 也会继续创建空的迁移文件

MySQL从子查询行到列