Skip to content

Instantly share code, notes, and snippets.

@sbailliez
Created July 3, 2024 19:16
Show Gist options
  • Save sbailliez/c85778f570ed9b07aeb8307c7d5b8edb to your computer and use it in GitHub Desktop.
Save sbailliez/c85778f570ed9b07aeb8307c7d5b8edb to your computer and use it in GitHub Desktop.
Equivalent to WORKDAY function in Excel/Google Sheet (does not support holidays, only handles weekends as saturday/sunday)
CREATE OR REPLACE FUNCTION f_add_business_day(start_date date, num_days integer)
RETURNS date AS
$BODY$
SELECT COALESCE(
(
SELECT workdays.date
FROM (
SELECT calendar.date::date,
row_number() OVER (ORDER BY CASE WHEN num_days = abs(num_days) THEN calendar.date END, calendar.date DESC) as elapsed_days
FROM generate_series(
/* start the calendar from day +1 or -1 depending on the sign of num_days */
start_date + (CASE WHEN num_days = abs(num_days) THEN 1 ELSE -1 END),
/* until far enough in the future (or past). It is 2*num + 5 days away to cover enough range */
start_date + (((abs(num_days) * 2) + 5) * (CASE WHEN num_days = abs(num_days) THEN 1 ELSE -1 END)),
/* increment/decrement by 1 day */
'1 day'::interval * (CASE WHEN num_days = abs(num_days) THEN 1 ELSE -1 END)
) calendar(date)
/** remove the weekends if there were any holidays we could hardcode them here */
WHERE EXTRACT('dow' FROM calendar.date) NOT IN (0, 6)
) workdays
/* find the right day N days away */
WHERE elapsed_days = abs(num_days)
),
/* handle the case when the input is 0, it would not match any row, so return same date */
start_date)
$BODY$
LANGUAGE sql IMMUTABLE
COST 100;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment