View Raw SPL
/****************************************************************************
*                                                                           *
*   DATE2DOY.SPL  Copyright 2026 (C) DSP Development Corporation            *
*                              All Rights Reserved                          *
*                                                                           *
*   Author:       Randy Race                                                *
*                                                                           *
*   Synopsis:     Converts date to day of year number                       *
*                                                                           *
*   Revisions:    20 Jan 2026     RRR     Creation                          *
*                                                                           *
****************************************************************************/


#if @HELP_DATE2DOY

    DATE2DOY

    Purpose: Converts date values to day of year (DoY) values.

    Syntax:  DATE2DOY(date, time)

             (doy, yfrac) = DATE2DOY(date, time)

               date - Optional. A string or series of Julian dates, the
                      input dates. Defaults to the current date.

               time - Optional. A string or series of TOD times, the
                      input times. Defaults to empty series.

    Returns: A series of Day of Year values.

             (doy, yfrac) = DATE2DOY(date, time) returns the Day of Year
             values in DOY and the fraction of the year elapsed for each
             date time input in YFRAC.

    Example:
             W1: date2doy("1/1/2030")

             W1 == {1}

             W1 contains the value 1, indicating "1/1/2030" is the first
             day of 2030.

    Example:
             W1: date2doy("1/1/2030", "12:00:00")

             W1 == {1.5}

             W1 contains the value 1.5, indicating "1/1/2030
             12:00:00" is the first day plus one half day :of 2030.

    Example:
             W1: (doy, yfrac) = date2doy("1/1/2030", "12:00:00");ravel(doy, yfrac)

             W1 == {{1.5, 0.001370}}

             The first column of W1 contains the value 1.5, indicating
             "1/1/2030 12:00:00" is the first day and one half of 2030. 
             The second column contains the value 0.001370, indicating
             that on "1/1/2030 12:00:00", 0.137% of the year has elapsed.

    Example:
             W2: ymd2date({{2030, 1, 1},
                           {2030, 2, 1},
                           {2030, 3, 1},
                           {2030, 4, 1}})

             W3: date2doy(w2)

             W3 == {1, 32, 60, 91}

             W3 indicates that for 2030, 1/1/2030 is day 1, 2/1/2030 is
             day 32, 3/1/2030 is day 60 and 4/1/2030 is day 91.

    Example:
             W1: gnorm(1000, 10000);setdate("2030-Jun-01");settime("12:00:00")
             W2: getdt(w1)
             W3: date2doy(w2)
             W4: doy2date(w3)

             W1 contains a random series that extends from 6/01/2030 to
             9/25/2030.

             W2 returns the date time values of each sample of W1.

             W3 converts the date time values in W2 to fractional DoY
             values.

             W4 converts the fractional DoY values of W3 back to date time
             values. The result in W4 is equal to W2 within machine
             precision.

    Remarks:
             DATE2DOY converts a date or datetime series to the
             corresponding day ofyear (DOY) series.

             Each DOY value is an integer from 1 to 366, where 1
             corresponds to January 1.

             If TIME is specified, the function returns fractional DOY
             values ranging from 1.0 to 366.0. The integer portion
             represents the day of the year and the fractional portion
             indicates the proportion of that day that has elapsed (0.0 at
             midnight, 0.5 at noon, etc.).
            
    See Also:
             DATE2DT
             DOY2DATE
             DT2UNIX
             DT2YMDHMS
             GETDT
             YMD2DATE
#endif


/* convert date and time to day of year */
date2doy(date = getdate(), time = {})
{
        local y, m, d, hh, mm, ss, doy, dfrac, diny, yfrac;

        (date, time) = utc_parse_args(date, time, "");

        (y, m, d, hh, mm, ss) = dt2ymdhms(date, time);

        /* offset by first day in year */
        doy = 1 + date - ymd2date(y, 1, 1);

        if (not(isempty(time)))
        {
                /* fraction of day */
                dfrac = hh * 60 * 60 + mm * 60 + ss;
                dfrac /= 86400;
        }
        else
        {
                dfrac = doy * 0;
        }

        doy += dfrac;

        if (isarray(doy))
        {
                setcomment(doy, "Day of Year");

                setvunits(doy, "DoY");
                sethunits(doy, getconfig("hunits"));
        }

        if (outargc > 1)
        {
                /* days in particular year */
                diny = dtduration(ymd2date(y + 1, 1, 1), ymd2date(y, 1, 1)) / 86400;

                /* fraction of elapsed year */
                yfrac = (doy - 1) / diny;

                if (isarray(yfrac))
                {
                        setcomment(yfrac, "Fraction of Elapsed Year");
                        setvunits(yfrac, "Year");
                        sethunits(yfrac, getconfig("hunits"));
                }
        
                return(doy, yfrac);
        }
        else
        {
                return(doy);
        }
}