View Raw SPL
/****************************************************************************
*                                                                           *
*   DATEOFFSET.SPL Copyright 2024 (C) DSP Development Corporation           *
*                                                                           *
*   Author:        Randy Race                                               *
*                                                                           *
*   Synopsis:      Add or subtract years, months, days                      *
*                                                                           *
*   Revisions:     10 Nov 2024     RRR     Creation                         *
*                                                                           *
****************************************************************************/


#if @HELP_DATEOFFSET

    DATEOFFSET

    Purpose: Adds or subtracts years, months, days to a Julian date.

    Syntax:  DATEOFFSET(date, years, months, days)

             date - A Julian date series.

                years - A scalar or series, the year values. Defaults to 0.

               months - A scalar or series, the month values. Defaults to 0.

                 days - A scalar or series, the day values. Defaults to 0.

    Returns: A date series.

    Example:
             W1: ymd2date(2030, 1, 1)
             W2: dateoffset(w1, 1, 1, 1)

             W1 contains the date series:

                1-1-2030

             W2 adds 1 year, 1 month and 1 day to the date in W1. The
             resulting date is:

                2-2-2031

    Example:
             W1: ymd2date(2030, 1, 1)
             W2: dateoffset(w1, 1, 1, 1)
             W3: dateoffset(w2, -1, -1, -1)

             Same as above except W3 removes the offset in W2 to return
             the same date as in W1:

                1-1-2030

    Example:
             W1: grand(3, 100000);setdate(w0, "1-1-2030")
             W2: col(getdt(w1), 1)
             W3: dateoffset(w2, months:1..3, days:-3)

             W1 generates a 3 point random series with a spacing between
             samples of 100000 seconds. The start date is set to 1-1-2030.

             W2 obtains the date values for each sample of W1. W2 contains
             the date values:

               1-01-2030
               1-02-2030
               1-03-2030

             W3 adds 1 month to the first value, 2 months to the second value
             and 3 months to the last date value and then then subtracts
             3 days from each resulting date value. The date offset values are
             specified using the PARAMETER:VALUE syntax. The resulting date
             values are:

               1-29-2030
               2-27-2030
               3-21-2030

    Example:
             W1: grand(3, 100000);setdate(w0, "1-1-2030")
             W2: col(getdt(w1), 1)
             W3: dateoffset(w2, months:-3, days:1..3)
             W4: dateperiod(w2, w3)
             W5: dateoffset(w3, w4)
             W6: w2 == w5

             Same as above except W4 computes the period in years, months,
             and days between the date values in W2 and the date values in
             W3. The difference is 2 month and 30 days for the first value,
             2 months and 29 days for the second value and 2 months 28 days
             for the last value.

             W5 adds the offset values in W4 to the date values in W3.
             The resulting date values are the same as the original
             values in W2. In this case, subtracting 3 months and adding 1,
             2 and 3 days to the date values in W2 is the same as subtracting
             2 months and subtracting 30, 29, and 28 days to the date values
             in W2,

             W6 compares the date values of W2 and W5, verifying the values
             are identical.

    Remarks:
             DATEOFFSET adds or subtracts years, months, days and hours
             from a date series.

             The offset values can be specified using the PARAMETER:VALUE
             syntax. For example:

               dateoffset(dt, months:3, days:5)

             adds 3 months and 5 days to the date series DT.

             The offset values are always added in years, months, days order.

    See Also:
             DTDURATION
             DTOFFSET
             DTPERIOD
             GETDT
             TIMEOFFSET
#endif



/* add offset to julian date */
dateoffset(date = getdate(), years = 0, months = 0, days = 0)
{
        /* parse args */
        (date, years, months, days) = dateoffset_parse_args(argc, date, years, months, days);

        /* internal function */
        date = juloffset({date}, {years}, {months}, {days});

        return(date);
}


/* parse args */
dateoffset_parse_args(nargs, date, years, months, days)
{
        local y, m, d;

        y = years;
        m = months;
        d = days;

        if (nargs < 2)
        {
                error(sprintf("%s - date and offset values required", __CALLER__));
        }
        else if (isdate(date))
        {
                if (nargs == 2)
                {
                        /* Date, {y, m, d} */
                        if (numcols(years) > 1 && numcols(years) <= 3)
                        {
                                try
                                {
                                        y = col(years, 1);
                                        m = col(years, 2);
                                        d = col(years, 3);
                                }
                                catch
                                {
                                }
                        }
                        else
                        {
                                y = years;
                        }
                }
        }
        else if (isdatetime(date))
        {
                if (isdatetime(y))
                {
                        (y, m, d) = dt2ymdhms(y);
                }
                else
                {
                        if (numcols(years) > 1 && numcols(years) >= 3)
                        {
                                try
                                {
                                        y = col(years, 1);
                                        m = col(years, 2);
                                        d = col(years, 3);
                                }
                                catch
                                {
                                }
                        }
                        else
                        {
                                y = years;
                        }
                }

                date = date[.., 1..2..end];

        }

        return(date, y, m, d);
}