简体   繁体   中英

Get records created after a particular time of day

Say I have an Event model with a date_time field representing the date time the event is held, and I want to see all Events that are held, say, 'after 10pm', or 'before 7am' across multiple dates. How could I do this?


My first thought was something like this:

scope :after_time ->(time){ where("events.date_time::time between ?::time and '23:59'::time", time) }

But this doesn't work because dates are stored in UTC and converted to the app's timezone by ActiveRecord.

So let's say I'm searching for Events after 5pm, from my local Adelaide time. The eventual query is this:

WHERE (events.date_time::time between '2016-10-09 06:30:00.000000'::time and '23:59'::time)

That is, because my timezone is +10:30 (Adelaide time), it's now trying to calculate between 6:30am and midnight, where it really needs to be finding ones created between 6:30am and 1:30pm utc.

Now, for this example in particular I could probably hack something together to work out what the 'midnight' time needs to be given the time zone difference. But the between <given time> and <midnight in Adelaide> calculation isn't going to work if that period spans midnight utc. So that solution is bust.


UPDATE:

I think I've managed to get the result I want by trial and error, but I'm not sure I understand exactly what's going on.

scope :after_time, ->(time) { time = time.strftime('%H:%M:%S') where_clause = <<-SQL (events.date_time at time zone 'UTC' at time zone 'ACDT')::time between ? and '23:59:59' SQL joins(:performances).where(where_clause, time) }

It's basically turning everything into the one time zone so the query for each row ends up looking something like WHERE '20:30:00' between '17:00:00' and '23:59:59' , so I'm not having to worry about times spanning over midnight.

Even still, I feel like there's probably a proper way to do this, so I'm open to suggestions.

this may help you and then you need not to convert every date of DB, instead you can convert the parameterized timestamp into UTC time:

scope :after, ->(start_time) { where('created_at::time > :time', time: start_time.utc.strftime('%H:%M:%S')) }

Now, for eg I do have 3 events for following timestamps(all in UTC):

  1. 2013-04-11 11:43:43
  2. 2013-04-11 15:10:40
  3. 2013-04-12 07:39:26

and then you can call:

start_time = Time.zone.parse('2016-01-01 20:00:00')
# => Fri, 01 Jan 2016 20:00:00 ACDT +10:30
Event.after(start_time) # this will return 2 events(1, 2)

query will be:

SELECT "events".* FROM "events" WHERE (created_at::time > '09:30:00')

Note: This will raise an error ActiveRecord::StatementInvalid: PG::AmbiguousColumn: ERROR: column reference "created_at" is ambiguous if you will use this query with any another model that will have created_at column

Check if this works for you,

s = DateTime.now.change(hour: 6, min: 30).utc
e = Date.today.end_of_day.utc
Event.where("date_time::time between ?::time and ?::time", s, e)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM