Reputation: 528
I'm trying to query a purchases table in my rails database (Postgres) and I want to query on time ranges.
For example, I'd like to know how many purchases were made between 2 PM and 3 PM across all dates.
There is a created_at
column in this table but I don't see how to accomplish this without searching for a specific date as well.
I've tried:
Purchases.where("created_at BETWEEN ? and ?", Time.now - 1.hour, Time.now)
But this ultimately will just search for today's date with those times.
Upvotes: 5
Views: 4493
Reputation: 656331
Use a simple cast to time
:
Purchases.where("created_at::time >= ?
AND created_at::time < ?", Time.now - 1.hour, Time.now)
This way you can easily test against arbitrary times.
Consider:
Which border to include / exclude. Common practice is to include the lower border and exclude the upper. BETWEEN
includes both.
The exact data type (timestamp
or timestamp with time zone
) and how that interacts with your local time zone:
If you run these queries a lot and need them fast and your table isn't very small, you will want to create a functional index for performance:
CREATE INDEX tbl_created_at_time_idx ON tbl (cast(created_at AS time));
I used the standard SQL syntax cast()
instead of the Postgres syntactical shortcut ::
. This is required for indices.
This index works for a timestamp [without time zone]
since the cast is IMMUTABLE
as required for an index. But it does not work for a timestamp with time zone
, for the same reasons. You can fix this, but you need to define what you need exactly. Use the AT TIME ZONE
construct to define the time zone to extract the time for. For instance, to measure against UTC time:
CREATE INDEX tbl_created_at_time_idx2
ON tbl(cast(created_at AT TIME ZONE 'UTC' AS time));
Similar question dealing with dates ignoring the year:
Upvotes: 4
Reputation: 19879
You need to extract just the hour portion from created_at using PostgreSQL's date_part/extract function.
SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 20
For example, something like this:
Purchases.where(["EXTRACT(HOUR FROM created_at) BETWEEN ? AND ?", 13, 14])
Upvotes: 6