【问题标题】:How to do time comparisons with mysql when timezones are involved?涉及时区时如何与mysql进行时间比较?
【发布时间】:2016-06-03 21:45:25
【问题描述】:

我有一个名为“Sessions”的表,其中包含一个 starts_at 字段(日期时间)。我想应用一个名为“starts_after”的过滤器,它返回在一天中的某个时间之后开始的所有会话(忽略日期,只查看会话时间)。所有时间都以 UTC 格式存储在数据库中。容易吧?但随之而来的是时区。每个会话都属于一个事件,该事件有一个与之关联的时区。现在我有:

  time = Time.new('1','1','1','14','00,'00','-07:00)
  Schedulables.where("DATE_FORMAT(CONVERT_TZ(schedulables.starts_at,'-07:00'), '%H,%i') >
                      DATE_FORMAT('#{time}', '%H,%i')")

但是,只有开始时间为 17:00 或更长的会话才能返回给我。还值得注意的是,服务器时间为 EST,17:00 和 14:00 之间的差异等于我的服务器时区 (-4:00) 和我在这里处理的时区 (-7: 00)。

【问题讨论】:

  • 基本上,无论哪个值都不会改变,您转换为其他值的 TZ。例如如果您正在执行select * from foo where dbfield=$value 之类的操作,您可以将$value 转换为dbfield 的TZ - 在查询启动时进行一次转换,完成。诉将每个 dbfield 转换为 $value 的 tz。

标签: mysql ruby-on-rails activerecord


【解决方案1】:

CONVERT_TZ() 需要三个参数。我只看到两个,所以不清楚这个查询是如何工作的。

您的服务器时区应该无关紧要。但我猜你的环境,知道时间值的时区和服务器的时区,可能会以典型的“有用”(阅读:通常无用)ORM 风格将其隐式转换为服务器时间。

你想要的查询,在 SQL 中,比你正在构建的更简单,看起来像这样:

WHERE TIME(CONVERT_TZ(schedulables.starts_at,'UTC','-07:00')) >= TIME('14:00:00')

...假设您希望事情在“本地”时间 14:00:00 或之后开始。 14:00:00 只是 TIME() 函数转换为时间文字的字符串。

最好将两个值都转换为时间,而不是与 DATE_FORMAT() 的输出进行词法比较,即使后者可能仍然是正确的。

也可能是,如果您的环境正在“修复”时间值,那么您可以通过在服务器时间中声明它来“取消修复”它,例如Time.new('1','1','1','14','00,'00','-04:00),允许两个不正确的操作相互抵消...或使用CONVERT_TZ() 转换为服务器时间而不是本地时间(因为您的时间值可能也被转换为服务器时间,静默)但这两者是可怕的计划,因为日期时间的双重转换不是无损的。

请注意,如果没有其他因素限制要评估的行数,您的方法将无法扩展。通常,在WHERE 子句中使用列值作为函数的参数可能效果不佳,因为无法使用该列上的索引来解析这样的表达式,并且可能需要进行全表扫描。

【讨论】:

  • 糟糕,这只是一个糟糕的复制/粘贴工作,我在 convert_tz 中将“00:00”作为第二个参数。我会试试你的建议,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-28
  • 2019-05-23
  • 2021-12-06
  • 2012-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多