在Rails datetime列中查询时间(带时区)

时间:2013-12-22 19:47:42

标签: ruby-on-rails ruby postgresql timezone activesupport

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

这样的东西
Event.where("occurred_at < '11:00'")

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

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

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)。所以你不能在不知道日期的情况下查询时间。

1 个答案:

答案 0 :(得分:3)

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

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

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

将此添加到Event.rb模型

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

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

在您的create操作中,您可以拥有类似的内容(这假设数据库中的列名为“tod_stamp”,类型为时间,而DateTime对象名为:occured_at ):

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&lt;?”,“10:00:00”)

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

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