在考虑时区的同时查询日期时间范围

时间:2011-05-13 18:05:07

标签: ruby-on-rails performance postgresql datetime timezone

我在查询时遇到了很多麻烦。我真的不知道怎么解释这个,但我会尝试。

基本上,我们有几个带有'posting_at'字段的对象,用于在日期时间字段中保存日期和时间以及时区。我需要查询并获取这些对象的日期范围。

以前,我将其转换为Date并将其与另一个Date对象进行比较。查询是这样的:

Date(posted_at) >= :start_date AND Date(posted_at) <= :end_date

但是,当Postgre将其转换为Date时,它会丢失时区信息,从而导致查询无法获得结果。

所以,我改为:

if start_date then
    start_time = Time.zone.parse("#{start_date.year}-#{start_date.month}-#{start_date.day}")
    conditions << "posted_at >= :start"
    hash[:start] = start_time
end

if end_date then
    end_time = Time.zone.parse("#{end_date.year}-#{end_date.month}-#{end_date.day}").end_of_day
    conditions << "posted_at <= :end"
    hash[:end] = end_time
end

虽然这可以获得准确的结果,但它的性能也很糟糕,并且在我的应用程序中造成一些超时。

我找不到任何其他方法来执行此查询并仍然保持准确的结果。有人会有一些建议或想法吗?

提前谢谢。

2 个答案:

答案 0 :(得分:1)

您永远不想在您的数据库中存储时区信息。

这是一篇讨论一些陷阱的读物:

http://derickrethans.nl/storing-date-time-in-database.html

你会得到更好的结果,如tadman建议的那样:添加一个包含时间戳at time zone 'utc'的新字段,然后将其编入索引。然后,您就可以使用posted_at between ? and ?抓取内容。

答案 1 :(得分:0)

您可能有更多的运气将您的开始和结束时间转换为UTC,这将使得时区在进行查询时几乎无关紧要。这很容易做到:

start_date.to_time.to_datetime.beginning_of_day.utc
end_date.to_time.to_datetime.end_of_day.utc

您还可以将查询调整为:

posted_at BETWEEN :start AND :end

确保您搜索的字段也有索引,否则您的表现会非常糟糕。