We're Moving!

The Vertica Forum is moving to a new OpenText Analytics Database (Vertica) Community.

Join us there to post discussion topics, learn about

product releases, share tips, access the blog, and much more.

Create My New Community Account Now


Calulating date after specific number of workdays — Vertica Forum

Calulating date after specific number of workdays

Hello,

I'm trying to calculate date after N working days (for now we ignore public holidays - it's only about excluding weekends). Unfortunately we're doing that in ETL part of Celonis Process Mining which uses Vertica SQL (10.1.x version) but without some specific analytic functions like LEAD/LAD which could solve my issue, I also cannot used any king of custom functions, so only simple SQL is viable here.

I've seen these links, however they cannot solve my problem:
A) https://forum.vertica.com/discussion/239801/counting-days-week-days-and-weekend-days-across-the-years (I want to calculate for every row in the table, not single value)
B)https://forum.vertica.com/discussion/239605/add-days-to-a-date-excluding-sat-and-sun

I've also tried generate list of days between min and max dates in the table, however I cannot find it useful without LEAD/LAG functions. Do you have some ideas?

CODE:
Create Table "TEST_TBL" AS (
SELECT the_date
FROM
(SELECT ts::date AS the_date
FROM
(
SELECT MIN(CPUDT)::TIMESTAMP AS tm FROM TABLE UNION --Get Min date from TABLE
SELECT MAX(CPUDT)::TIMESTAMP AS tm FROM TABLE --Get Max date from TABLE
) AS t TIMESERIES ts AS '1 DAY' OVER (ORDER BY tm)) foo --Fill the gapes by generating dates between MIN & MAX
WHERE DAYOFWEEK(the_date) NOT IN (1,7) --Do that only for working days

INPUT:

Some_Date

2022-11-28
2022-11-27

DESIRED OUTPUT
-------------- | ------------------------------ |

Some_Date Some_Date+3 workDays
2022-11-28 2022-12-01
2022-11-25 2022-12-30

Best Regards,
Mateusz Dudek

Answers

  • Bryan_HBryan_H Vertica Employee Administrator

    How about something like this (if you can't create function, you only need the SQL from the RETURN line):
    CREATE OR REPLACE FUNCTION AddBusinessDays(ts TIMESTAMP, days INT) RETURN TIMESTAMP
    AS BEGIN
    RETURN TIMESTAMPADD('day', (days % 5)::int + CASE ((1 + DAYOFWEEK_ISO(ts) + (days % 5)) % 7) WHEN 0 THEN 2 WHEN 1 THEN 1 ELSE 0 END, TIMESTAMPADD('week', (days / 5)::int, ts));
    END;
    Adapted from T-SQL example at https://stackoverflow.com/questions/5471524/add-business-days-to-date-in-sql-without-loops

  • MateuszDudekMateuszDudek Vertica Customer

    Hello Bryan_H,

    Thanks a lot for that snippet - I've seen that thread, but as I just seen that's a function, I ignored that - probably a mistake :)

    I've adjusted the code and added code for dummy data creation.
    It works however outcome is a bit strange - I wanted to add 3 working days so I should receive:
    2022-11-30
    2022-11-30
    2022-12-01

    CODE:
    DROP TABLE IF EXISTS "TEST_DATE_TBL_MD";

    Create table "TEST_DATE_TBL_MD" AS (
    SELECT '2022-11-28'::TIMESTAMP AS "SomeDate", 1 AS "DUMMY_KEY"
    UNION
    SELECT '2022-11-27'::TIMESTAMP AS "SomeDate", 1 AS "DUMMY_KEY"
    UNION
    SELECT '2022-11-26'::TIMESTAMP AS "SomeDate", 1 AS "DUMMY_KEY"
    );

    SELECT "SomeDate",
    TIMESTAMPADD('day', (3 % 5)::int + CASE ((1 + DAYOFWEEK_ISO("SomeDate") + (3 % 5)) % 7)
    WHEN 0 THEN 2
    WHEN 1 THEN 1
    ELSE 0 END, TIMESTAMPADD('week', (3 / 5)::int, "SomeDate")) AS "SomeDate+3WDs"
    FROM "TEST_DATE_TBL_MD";

    Output:

    Best Regards,
    Mateusz Dudek

  • marcothesanemarcothesane - Select Field - Administrator

    To cater for holidays, too - and, by adding some sort of a geography/region key, for local holidays, create a calendar table, with a counter set to 1 in case the row is a workday, 0 otherwise.
    For this example, I just create a calendar where Saturday and Sunday are non-working days, and limit to 3 months.

    DROP TABLE IF EXISTS cal;
    
    CREATE TABLE cal AS
    WITH
    cal AS (
      SELECT
        tm::DATE as dt
      , CASE DAYOFWEEK(dt)
          WHEN 1 THEN 0
          WHEN 7 THEN 0
          ELSE 1
        END AS wkdaycounter
      FROM (
                   SELECT TIMESTAMP '2022-10-01'
         UNION ALL SELECT TIMESTAMP '2022-12-31'
      ) limits(ts)
      TIMESERIES tm AS '1 DAY' OVER(ORDER BY ts) 
    );
    

    Then, you can range-join your input data over the from-date, so that the calendar date is greater than the from-date - and limit to, say the double number of workdays to add. On that range-join, apply a running sum on the week day counter coming from the calendar. Pack this last query again as a subquery (a Common Table Expression in my case), and finally filter by the result of the running sum equal to the number of workdays you want. I left all intermediate columns in the report so you can see what happened.,

    WITH
    indata(dt, wkdays) AS (
                 SELECT DATE '2022-11-26', 3
       UNION ALL SELECT DATE '2022-11-27', 3
       UNION ALL SELECT DATE '2022-11-28', 3
    )  
    ,
    wrkdayrunsum AS (
      SELECT
        indata.dt
      , indata.wkdays
      , cal.dt as after_n_wkdays
      , SUM(wkdaycounter) OVER(PARTITION BY indata.dt ORDER BY cal.dt) AS wdaycount
      FROM indata
      JOIN cal ON cal.dt > indata.dt AND cal.dt <= indata.dt + wkdays * 2
    ) 
    SELECT
      *
    FROM wrkdayrunsum
    WHERE wdaycount = wkdays
    ;
    -- out      dt     | wkdays | after_n_wkdays | wdaycount 
    -- out ------------+--------+----------------+-----------
    -- out  2022-11-27 |      3 | 2022-11-30     |         3
    -- out  2022-11-26 |      3 | 2022-11-30     |         3
    -- out  2022-11-28 |      3 | 2022-12-01     |         3
    
  • VValdarVValdar Vertica Employee Employee

    I think you can modify this for this:
    TIMESTAMPADD('week', (days / 5)::int, ts));
    TIMESTAMPADD('week', days // 5, ts));

    It's better but there's still a day that don't output like expected.

  • Kedis1999Kedis1999 Vertica Customer
    1. Calculating Date After Specific Number of Workdays
      The formula for calculating the date after a specific number of workdays is:
      Date (Workday + 1) / 2
      For example: If you want to calculate the date after 5 days, then you would use the following formula:
      (5 + 1) / 2 4/2 2
      So the date after two weeks is February 6th.
      1. Calculating Date Before Specific Number of Workdays
        The formula for calculating date before a specific number of work days is:
        Date Workday - (Workday + 1)/2
        For example: If we wanted to calculate the date before five days, we would use the following formula.
        (5 - (5+1)) / 2 4/ 2 2
        So the day before two weeks is January 25th.

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Emoji
Image
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file