关于ruby:在Rails datetime列中查询时间(带时区)

Querying time of day from in a Rails datetime column (with time zones)

我有一些通过postgresql datetime列存储在数据库中的新闻事件。但是,我想对事件发生的时间进行查询。就像是

1
Event.where("occurred_at < '11:00'")

如果这是postgresql时间列,你可以做什么。

为了增加额外的皱纹,我将Rails时区设置为整个应用程序的东部时间

1
config.time_zone = 'Eastern Time (US & Canada)'

因此,如果您尝试以某种方式提取数据库时间,那么该时间将是UTC,因此在半年期间,时间比较将关闭1小时(因为夏令时)。

我唯一能想到的是维护一个单独的'time'类型的数据库列。

编辑和澄清

这个问题的棘手部分是由于夏令时,UTC偏移在半年内发生变化。 Time.zone.parse("2013-01-01 10:00")给出2013年1月1日10:00 EST -05:00(即15:00 UTC),六个月后Time.zone.parse("2013- 07-01 10:00")给出2013年7月1日10:00 EDT -04:00(即UTC时间14:00)。因此,您不仅可以在不知道日期的情况下查询时间。


我已经完全删除并重写了这个答案,因为旧答案只适用于SQLite而不是OP所询问的Postgres。

我能找到的唯一简单方法(和Rails一样)是使用宝石。宝石是"tod",可以在这里找到:https://github.com/JackC/tod。

首先,您需要将gem 'tod'添加到Gemfile并运行bundle。然后,您将在类型时间的DB中创建一个列。

将其添加到Event.rb模型中

1
2
class Event < ActiveRecord::Base
  serialize :time, Tod::TimeOfDay

现在,您可以通过序列化格式获取时间戳并节省时间(即13:45:00)。 TimeOfDay类将为您提供调用和操作字段所需的方法。

在您的create操作中,您可能会有类似的内容(这假设DB中的列名为"tod_stamp",类型为time,而DateTime对象名为:occured_at):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def create
  @event = Event.new(event_params)
  tod_stamp = @event.occured_at.strftime('%H:%M:%S')
  @event.tod_stamp = TimeOfDay.parse(tod_stamp)

  respond_to do |format|
    if @event.save
      format.html { redirect_to @event, notice: 'Event was successfully created.' }
      format.json { render action: 'show', status: :created, location: @event }
    else
      format.html { render action: 'new' }
      format.json { render json: @event.errors, status: :unprocessable_entity }
    end
  end
end

现在当你向DB询问类似的东西时:

my_events = Event.where("tod_stamp <?","10:00:00")

您将根据活动记录的实际时间获得结果。如果您处于使用夏令时的时区,则无关紧要。您还可以在Tod主页上获取TimeOfDay解析,比较和操作的其他方法作为文档。

像往常一样,在尝试重新发明轮子之前,我应该寻找宝石。 :-) 希望这可以帮助。