Selecting workday-only daterange
s (without weekends):
You can check what day of the week it is on the first day in the range using extract()
and knowing its length from upper()-lower()
, determine if it'll cross a weekend: online demo
select *
from test_table
where '2023-02-11'::date <@ date_slot
and extract(isodow from lower(date_slot)
+ (not lower_inc(date_slot))::int)
+( (upper(date_slot) - (not upper_inc(date_slot))::int)
-(lower(date_slot) + (not lower_inc(date_slot))::int) ) < 6 ;
Cases where your ranges have varying upper and lower bound inclusivity are handled by lower_inc()
and upper_inc()
- their boolean result, when cast to int, just adds or subtracts a day to account for whether it's included by the range or not.
The range is on or includes a weekend if it starts on a weekend day or continues for too long from any other day of the week:
- 4 days, if it starts on a Monday (
isodow=1
)
- 3 days, if it starts on a Tuesday (
isodow=2
)
- 2 days, if it starts on a Wednesday (
isodow=3
)
- 1 days, if it starts on a Thursday (
isodow=4
)
- 0 days, if it starts on a Friday (
isodow=5
)
This means the isodow
of range start date and the range length cannot sum up to more than 5 for the range not to overlap a weekend.
You can also enumerate the dates contained by these ranges using generate_series()
and see if they include a Saturday (day 6
) or a Sunday (0
as dow
, 7
as isodow
):
select *
from test_table
where '2023-02-11'::date <@ date_slot
and not exists (
select true
from generate_series(
lower(date_slot) + (not lower_inc(date_slot))::int,
upper(date_slot) - (not upper_inc(date_slot))::int,
'1 day'::interval) as alias(d)
where extract(isodow from d) in (6,7) );
Selecting records based on workday-only date
s:
First comment got it right
select *
from table_with_dateranges dr,
table_with_dates d
where d.date <@ dr.date_slot
and extract(isodow from d.date) not in (6,7);