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


#if @HELP_DOY2DATE

    DOY2DATE

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

    Syntax:  DOY2DATE(doy, year)

             (date, time) = DOY2DATE(doy, year)
 
                doy - An integer or series, the input day of year.

               year - Optional. An integer or series. The year for
                      each DOY value. If a single value, the year
                      is used for each DOY value. Defaults to the
                      current year.

    Returns: A series of date values.

             (date, time) = DOY2DATE(doy, year) returns the date and time
             in two separate variables.

    Example:
             W1: doy2date(1, 2030)

             W1 == {1/1/2030}

             W1 represents the date of the first day of 2030.

    Example:
             W1: doy2date(1.5, 2030)

             W1 == {{1/1/2030}, {12:00:00}}

             W1 represents the date and time of the first day of 2030
             at noon.

    Example:
             (d, t) = doy2date(1.5, 2030)

             d == {1/1/2030}
             t == {12:00:00}

             Same as above, except the date and time values are returned in
             two separate variables.

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

             W3: date2doy(w2)
             W4: doy2date(w3, 2030)

             W3 == {1, 32, 60, 91}
             W4 == {1/01/2030, 2/02/2030, 3/01/2030, 4/01/2030}

             Demonstrates that DATE2DOY and DOY2DATE are inverse functions.

    Remarks:
             DOY2DATE converts a day of year value the equivalent date
             series. Each input day of year is an integer between 1 and 366
             where 1 represents day 1 or January 1.

             If DOY is fractional, DOY2DATE also returns a time value
             representing the fraction of the day elapsed.

             See DATE2DOY to convert a date series to the equivalent
             day of year series.
            
    See Also:
             DATE2DOY
             DATE2DT
             DT2UNIX
             DT2YMDHMS
             GETDT
             YMD2DATE
#endif


/* convert day of year to date */
doy2date(doy, year = {})
{
        local date, m, d, tod = {};

        if (argc < 1) error(sprintf("%s - input Day Of Year required", __FUNC__));

        if (isempty(year))
        {
                (year, m, d) = date2ymd(julstr(getdate()));
        }

        /* DOY.fraction */
        tod = doy - int(doy);
        doy = int(doy);
        
        tod *= 86400;

        /* cast to series */
        tod = {tod};

        if (any(tod > 1e-8))
        {
                if (all(abs(tod - int(tod)) < 1e-8))
                {
                        setvunits(tod, "Time");
                }
                else
                {
                        setvunits(tod, "Real Time");
                }
        
                setcomment(tod, "Time");
        }
        else
        {
                tod = {};
        }

        /* wraps date correctly */
        date = ymd2date(year, 1, doy);

        if (isarray(date))
        {
                setcomment(date, "Date");
        }

        if (outargc > 1)
        {
                /* fraction of day */
                if (isempty(tod))
                {
                        tod = doy * 0.0;

                        if (isarray(tod))
                        {
                                setvunits(tod, "Time");
                                setcomment(tod, "Time");
                        }
                }

                return(date, tod);
        }

        if (not(isempty(tod)))
        {
                date = ravel({date}, {tod});
        }

        return(date);
}