Problems / Fifteen-Minute Buckets / Editorial
time_bucket(INTERVAL '15 minutes', event_time)
14:07 -> 14:00
14:59:59 -> 14:45
14:15:00
GROUP BY bucket_start
COUNT(*)
bucket_start
The arithmetic alternative, date_trunc('hour', ts) + INTERVAL 15 MINUTE * (EXTRACT(minute FROM ts) // 15), does the same thing and shows what the built-in encapsulates: truncate to the hour, then add back the floored quarter-hours.
date_trunc('hour', ts) + INTERVAL 15 MINUTE * (EXTRACT(minute FROM ts) // 15)
Bucketing timestamps is *flooring*, not rounding — 14:22:59 belongs to 14:15, never 14:30. Getting the boundary semantics right (14:15:00 stays in 14:15) matters because downstream joins on bucket_start silently misalign if two systems round differently. In PySpark-on-DuckDB, F.expr lets you reach the same native time_bucket function when no built-in F equivalent exists.
14:22:59
14:15
14:30
F.expr
time_bucket
F
Solve Fifteen-Minute Buckets yourself →