Rails 3.1:在一个时间范围内查询Postgres的记录

Cla*_*lay 1 postgresql timezone datetime ruby-on-rails ruby-on-rails-3

在我的应用程序中,我有一个Person模型.每个Person都有一个属性time_zone,指定其默认时区.我也有一个Event模特.每个Event都有一个start_timeend_time时间戳,以UTC时间保存在Postgres数据库中.

我需要创建一个查询,查找特定人员在一天的午夜和下一个午夜之间的事件.该@todays_events控制器变量保存查询的结果.

我采用这种方法的部分原因是我可能让其他时区的人查看一个人的事件列表.我希望他们看到这一天,因为这个人会看到这一天,而不是基于他们作为观察者所在的时区.

无论出于何种原因,我仍然在我的结果集中得到前一天的一些事件.@todays_events.我的猜测是我将UTC时间戳与非UTC参数进行比较,或者沿着那些行进行比较.通常,只有在前一天晚上开始或结束的事件才会显示在今天的查询结果列表中.

现在,我正在建立:

@today    = Time.now.in_time_zone(@person.time_zone).midnight.to_date
@tomorrow = (@today + 1.day ).to_datetime
@today    = @today.to_datetime
Run Code Online (Sandbox Code Playgroud)

我的查询如下:

@todays_activities = @person.marks.where("(start_time >= ? AND start_time < ?) OR (end_time >= ? AND end_time < ?);", @today, @tomorrow, @today, @tomorrow ).order("start_time DESC")
Run Code Online (Sandbox Code Playgroud)

我应该如何改变这种做法,我保证只接收从今天的结果(按照@person.time_zone@todays_activities查询?

mu *_*ort 10

当你打电话时,你正在失去对时区的追踪,to_date所以不要这样做:

@today    = Time.now.in_time_zone(@person.time_zone).midnight.utc
@tomorrow = @today + 1.day
Run Code Online (Sandbox Code Playgroud)

当你some_date.to_datetime,你得到一个UTC的DateTime实例,所以结果是这样的:

Time.now.in_time_zone(@person.time_zone).midnight.to_date.to_datetime
Run Code Online (Sandbox Code Playgroud)

将有一个00:00:00的时间和UTC的时区; 00:00:00是正确的时间,@person.time_zone但不适合UTC(当然,除非@person是在+0时区内).

您可以使用以下方法简化查询overlaps:

where(
    '(start_time, end_time) overlaps (timestamp :today, timestamp :tomorrow)',
    :today => @today, :tomorrow => @tomorrow
)
Run Code Online (Sandbox Code Playgroud)

请注意,overlaps半开放间隔工作:

每个时间段被认为代表半开时间间隔start <= time < end,除非开始和结束相等,在这种情况下它代表单个时刻.