View Raw SPL
/****************************************************************************
*                                                                           *
*   DTPERIOD.SPL  Copyright 2024 (C) DSP Development Corporation            *
*                                                                           *
*   Author:       Randy Race                                                *
*                                                                           *
*   Synopsis:     Calculates date time difference in YMSHMS                 *
*                                                                           *
*   Revisions:    10 Nov 2024     RRR     Creation                          *
*                                                                           *
****************************************************************************/


#if @HELP_DTPERIOD

    DTPERIOD

    Purpose: Calculates the difference of date time series in years, months,
             days, hours, minutes and seconds.

    Syntax:  DTPERIOD(date1, time1, date2, time2)

             (yr, mo, dy, hr, mn, s) = DTPERIOD(date1, time1, date2, time2)

                    date1 - A series of Julian integer dates, the end date.

                    time1 - A series of time of day values, the end time.

                    date2 - Optional. A series of Julian integer dates,
                            the start date. Defaults to an empty series.

                    time2 - Optional. A series of time of day values,
                            the start time. Defaults to an empty series.


    Alternate Syntax:  DTPERIOD(datetime1, datetime2)

             (yr, mo, dy, hr, mn, s) = DTPERIOD(datetime1, datetime2)

                datetime1 - An array, the end date and time values in
                            adjacent columns.

                datetime2 - Optional. An array, the start date and time
                            values in adjacent columns. Defaults to an
                            empty array.

    Returns: The elapsed period as an N x 6 series of years, months, days,
             hours, minutes, seconds.

             (yr, mo, dy, hr, mn, s) = DTPERIOD(datetime1, datetime2)

             returns the values in separate variables.
             
             If only one date and time series or one composite date time
             series is specified, the periods are computed on the two
             point difference of each date time value.

    Example:
             W1: ymdhms2dt(2027, 1, 2, 12, 0, 0)
             W2: ymdhms2dt(2027, 3, 1, 12, 0, 0)
             W3: dtperiod(w2, w1)
             W4: dtoffset(w1, w3)

             W1 contains the date time:

              1-02-2027 12:00:00

             W2 contains the date time:

              3-01-2027 12:00:00

             W3 computes the difference between the two date times in years,
             months, days, hours, minutes, seconds. The period is 0 years,
             1 month, 27 days, 0 hours, 0, minute and 0 seconds.

             W4 recovers the end date time by adding the offset in W3 to
             the start date time in W1.

    Example:
             W1: ymdhms2dt(2028, 1, 2, 12, 0, 0)
             W2: ymdhms2dt(2028, 3, 1, 12, 0, 0)
             W3: dtperiod(w2, w1)
             W4: dtoffset(w1, w3)

             Same as the first example except the end and start year
             is 2028, a leap year. The period is 0 years, 1 month, 28 days,
             0 hours, 0, minute and 0 seconds. The days value has increased
             from 27 days to 28 days because of the leap year.

    Example:
             W1: ymdhms2dt(2027, 1, 2, 12, 0, 0)
             W2: ymdhms2dt(2027, 3, 1, 12, 0, 0)
             W3: dtperiod(w1, w2)
             W4: dtoffset(w2, w3)

             Same as the first example above except the start and end date
             times are swapped. The result is a negative period, 0 years,
             -1 month, -30 days, 0 hours, 0 minutes and 0 seconds.

             W4 recovers the earlier end date in W1 time by adding the
             negative offset in W3 to the later start date time in W2.

    Example:
             W1: gnorm(10, 60*60*2 + 13)
             W2: getdt(w1)
             W3: dtperiod(w2)

             W1 contains 10 random samples with a time spacing of 7213
             seconds or 2 hours and 13 seconds between samples.

             W2 computes the date time values for each sample in W1.

             Because only one date time series was given, W3 computes
             the two point difference between subsequent samples of W2.
             The result is 0 years, 0, months, 0 days, 2 hours, 0 minutes
             and 13 seconds for each sample, equal to the original sample
             spacing of the series in W1.

    Example:
             W1: ymdhms2dt(2001, 6, 3, 12, 10, 0.3)
             W2: ymdhms2dt()
             W3: dtperiod(w2, w1)
             W4: dtoffset(w1, years:40)
             W5: dtperiod(w4, w2)

             W1 represents the birthday of someone born on June 3, 2001
             at 12:10:00.300.

             W2 contains the current date time.

             W3 contains the current age of the person in years, months, days, 
             hours, minutes and seconds.

             W4 adds 40 years to the birthday in W1. The person will turn
             40 on June 3, 2041 at 12:10:00.300.

             W5 displays the number of years, months, days, hours, minutes
             and seconds remaining before their 40th birthday.

    Remarks:
             DTPERIOD computes the difference between two date time series
             with the result in periods of years, months, days, hours,
             minutes and seconds.

             If only one date and time series or one composite date
             time series is provided, the two point period difference
             between subsequent date time series value is computed.

             A date time period is measured in years, months, days, hours,
             minutes and seconds.

             A date time duration is measured in seconds.

             See DTDURATION to compute the time difference in seconds.

    See Also:
             DATEPERIOD
             DTDIFF
             DTDURATION
             DT2UNIX
             TIMEPERIOD
             YMDHMS2DT
#endif


/* ymdhms periods between date/time values */
dtperiod(d1, t1, d2, t2)
{
        local years, months, days, hours, minutes, seconds, ymdhms;
        local usediff, dateonly, timeonly;

        /*
         *  basically a wrapper around the internal dtdifference() function,
         *  code complexity is from argument parsing and column iteration
         */

        (d1, t1, d2, t2, usediff, dateonly, timeonly) = dt_durper_parse_args(argc, d1, t1, d2, t2);

        if (usediff)
        {
                d2 = t2 = {};
        }

        if (usediff)
        {
                if (outargc > 1)
                {
                        if (timeonly)
                        {
                                (hours, minutes, seconds) = timeperiod(d1);

                                return(hours, minutes, seconds);
                        }
                        else if (dateonly)
                        {
                                (years, months, days) = dateperiod(d1);

                                return(years, months, days);
                        }
                        else
                        {
                                d2 = t2 = {};

                                (years, months, days, hours, minutes, seconds) = dtperiod_iterate(d1, t1, d2, t2);

                                return(years, months, days, hours, minutes, seconds)
                        }
                }
                else
                {
                        if (timeonly)
                        {
                                ymdhms = timeperiod(d1);
                        }
                        else if (dateonly)
                        {
                                ymdhms = dateperiod(d1);
                        }
                        else
                        {
                                d2 = t2 = {};

                                ymdhms = dtperiod_iterate(d1, t1, d2, t2);
                        }

                        settable(ymdhms);

                        return(ymdhms);
                }
        }
        else
        {
                if (outargc > 1)
                {
                        if (timeonly)
                        {
                                (hours, minutes, seconds) = timeperiod(t1, t2);

                                return(hours, minutes, seconds);
                        }
                        else if (dateonly)
                        {
                                (years, months, days) = dateperiod(d1, d2);

                                return(years, months, days);
                        }
                        else
                        {
                                (years, months, days, hours, minutes, seconds) = dtperiod_iterate(d1, t1, d2, t2);

                                return(years, months, days, hours, minutes, seconds)
                        }
                }
                else
                {
                        if (timeonly)
                        {
                                ymdhms = timeperiod(t1, t2);
                        }
                        else if (dateonly)
                        {
                                ymdhms = dateperiod(d1, d2);
                        }
                        else
                        {
                                ymdhms = dtperiod_iterate(d1, t1, d2, t2);
                        }

                        settable(ymdhms);

                        return(ymdhms);
                }
        }
}


/* column iteration for multiple date/time series */
ITERATE dtperiod_iterate(d1, t1, d2, t2)
{
        local years, months, days, hours, minutes, seconds, ymdhms;

        /* internal function */
        (years, months, days, hours, minutes, seconds) = dtdifference({d1}, {t1}, {d2}, {t2});

        if (outargc > 1)
        {
                return(years, months, days, hours, minutes, seconds);
        }
        else
        {
                ymdhms = ravel(years, months, days, hours, minutes, seconds);

                return(ymdhms);
        }
}