I need a function in PostgreSQL that accepts a date range and returns the dates inside the date range that are Mondays. Anybody have an idea how this could be done?
            Asked
            
        
        
            Active
            
        
            Viewed 1,637 times
        
    2 Answers
3
            
            
        create function f(dr daterange)
returns setof date as $$
    select d::date
    from generate_series(
        lower(dr), upper(dr), interval '1 day'
    ) s (d)
    where
        extract(dow from d) = 1 and
        d::date <@ dr;
    ;
$$ language sql;
select f(daterange('2014-01-01', '2014-01-20'));
     f      
------------
 2014-01-06
 2014-01-13
 
    
    
        Clodoaldo Neto
        
- 118,695
- 26
- 233
- 260
- 
                    Nice and simple. A minor gripe: When working with a `daterange` inclusive / exclusive borders should be observed. – Erwin Brandstetter Apr 14 '14 at 00:05
2
            The most efficient way should be to find the first Monday and generate a series in steps of 7 days:
CREATE OR REPLACE FUNCTION f_mondays(dr daterange)
  RETURNS TABLE (day date) AS
$func$
SELECT generate_series(a + (8 - EXTRACT(ISODOW FROM a)::int) % 7
                     , z
                     , interval '7 days')::date
FROM  (
   SELECT CASE WHEN lower_inc(dr) THEN lower(dr) ELSE lower(dr) + 1 END AS a
        , CASE WHEN upper_inc(dr) THEN upper(dr) ELSE upper(dr) - 1 END AS z
   ) sub
$func$ LANGUAGE sql;
- The subquery extracts start ( - a) and end (- z) of the range, adjusted for inclusive and exclusive bounds with range functions.
- The expression - (8 - EXTRACT(ISODOW FROM a)::int) % 7returns the number of days until the next monday.- 0if it's Monday already. The manual about- EXTRACT().
- generate_series()can iterate any given interval - 7 days in this case. The result is a- timestamp, so we cast to- date.
- Only generates Mondays in the range, no - WHEREclause needed.
Call:
SELECT day FROM f_mondays('[2014-04-14,2014-05-02)'::daterange);
Returns:
day
----------
2014-04-14
2014-04-21
2014-04-28
 
    
    
        Erwin Brandstetter
        
- 605,456
- 145
- 1,078
- 1,228
