-- Find gaps in date rangesSELECTe1.end_date,e2.start_date,DATERANGE(e1.end_date,e2.start_date)asgap_rangeFROMEntitye1,Entitye2WHEREe1.end_date<e2.start_dateANDNOTEXISTS(SELECT1FROMEntitye3WHEREOVERLAPS(DATERANGE(e1.end_date,e2.start_date),DATERANGE(e3.start_date,e3.end_date))=TRUE)-- GENERATE_TIME_SERIES: optional 4th argument outputs all timestamps in a target timezoneSELECTGENERATE_TIME_SERIES(e.start_tz,e.end_tz,'1 hour','Europe/Sofia')ashourFROMEntityeWHEREe.id=1-- DATE_BIN: snap a timestamp to the nearest interval boundary relative to an originSELECTDATE_BIN('7 days',e.created_at,'2023-01-02')asweek_startFROMEntitye-- Range bounds: third argument controls inclusivity — default is '[)' (inclusive lower, exclusive upper)SELECTDATERANGE(e.start_date,e.end_date,'[]')asinclusive_rangeFROMEntitye-- Range operators must be compared with = TRUE / = FALSE in Doctrine DQLSELECTeFROMEntityeWHEREOVERLAPS(e.active_period,DATERANGE('2023-01-01','2023-12-31'))=TRUESELECTeFROMEntityeWHERECONTAINS(TSTZRANGE(DATE_SUBTRACT(CURRENT_TIMESTAMP(),'30 days'),CURRENT_TIMESTAMP()),e.start_tz)=TRUE-- Group by calendar month using DATE_TRUNC + DATE_ADDSELECTTSTZRANGE(DATE_TRUNC('month',e.created_at),DATE_ADD(DATE_TRUNC('month',e.created_at),'1 month'))asmonth_range,COUNT(e.id)asentity_countFROMEntityeGROUPBYmonth_rangeORDERBYmonth_range
Empty ranges: a range containing no values, which PostgreSQL prints as empty (e.g. DATERANGE('2023-01-01', '2023-01-01')). In PHP, use DateRange::empty() and isEmpty() — see Empty Ranges. A range with two NULL bounds is not empty: it is (,), unbounded on both sides
Infinite ranges: Use a parameter set to null for unbounded sides (DQL does not accept a bare NULL argument)
Example: DATERANGE('2023-01-01', :noEnd) with :noEnd set to null represents “from 2023-01-01 onwards”
💡 Tips for Usage:
Range operators should be used with = TRUE or = FALSE in DQL
Date functions work with PostgreSQL’s rich date/time types
Range types provide efficient storage and querying for value ranges
Overlaps testing is optimized with proper indexes on range columns
Date extraction supports many field types: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DOW (day of week), DOY (day of year)
Range bounds default to [) (inclusive lower, exclusive upper) if not specified