Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate closest working day in Postgres

I need to schedule some items in a postgres query based on a requested delivery date for an order. So for example, the order has a requested delivery on a Monday (20120319 for example), and the order needs to be prepared on the prior working day (20120316).

Thoughts on the most direct method? I'm open to adding a dates table. I'm thinking there's got to be a better way than a long set of case statements using: SELECT EXTRACT(DOW FROM TIMESTAMP '2001-02-16 20:38:40');

like image 798
Dustin Avatar asked Mar 16 '12 20:03

Dustin


People also ask

How do I calculate day difference in PostgreSQL?

To count the difference between dates as days in PostgreSQL or Oracle, you simply need to subtract one date from the other, e.g. arrival - departure . But in most cases, what you really want is the number of days from the first date to the second date inclusively.

How do I extract a specific day from a date in PostgreSQL?

In PostgreSQL you can use the extract() function to get the day from a date. You can also use date_part() to do the same thing. When extracting the day from a date, you need to specify what sense of the word “day” you mean. For example, “day of week”, “day of month”, “day of year”, etc.

How do I extract the day of the week in PostgreSQL?

The first parameter is the date and the second is the desired output format. To extract the full day name, the format should be 'Day' : SELECT to_char( date '2022-01-01' , 'Day' ); The result is 'Saturday' .

What is Getdate in PostgreSQL?

GETDATE function returns the current date and time. There is no GETDATE function in PostgreSQL, but there is NOW() function for the same purpose. If there are multiple occurrences of the GETDATE function then you can automate them using extension.


3 Answers

This gets you previous business day.

SELECT 
    CASE (EXTRACT(ISODOW FROM current_date)::integer) % 7
        WHEN 1 THEN current_date-3
        WHEN 0 THEN current_date-2
        ELSE current_date-1
    END AS previous_business_day
like image 70
Yoseph Avatar answered Oct 18 '22 11:10

Yoseph


To have the previous work day:

select max(s.a) as work_day
from (
    select s.a::date
    from generate_series('2012-01-02'::date, '2050-12-31', '1 day') s(a)
    where extract(dow from s.a) between 1 and 5
    except
    select holiday_date
    from holiday_table
    ) s
where s.a < '2012-03-19'
;

If you want the next work day just invert the query.

like image 7
Clodoaldo Neto Avatar answered Oct 18 '22 09:10

Clodoaldo Neto


SELECT y.d AS prep_day
FROM  (
    SELECT generate_series(dday - 8, dday - 1, interval '1d')::date AS d
    FROM (SELECT '2012-03-19'::date AS dday) x
    ) y
LEFT   JOIN holiday h USING (d)
WHERE  h.d IS NULL
AND    extract(isodow from y.d) < 6
ORDER  BY y.d DESC
LIMIT  1;
  • It should be faster to generate only as many days as necessary. I generate one week prior to the delivery. That should cover all possibilities.

  • isodow as extract parameter is more convenient than dow to test for workdays.

  • min() / max(), ORDER BY / LIMIT 1, that's a matter of taste with the few rows in my query.

  • To get several candidate days in descending order, not just the top pick, change the LIMIT 1.

  • I put the dday (delivery day) in a subquery so you only have to input it once. You can enter any date or timestamp literal. It is cast to date either way.

like image 4
Erwin Brandstetter Avatar answered Oct 18 '22 11:10

Erwin Brandstetter