    #pragma once

    class SCDateTime;

    #define SCDATETIME_SUPPORT_CHRONO 1

    #ifdef SCDATETIME_SUPPORT_CHRONO
    #include <chrono>
    #endif
    #include <cstdint>  // std::int64_t
    #include <math.h>  // ceil, floor, fabs
    #include <string.h>  // stricmp
    #include <time.h>  // time_t

    // Set 1 to enable warning of usage the SCDateTime `deprecated` functions
    #define SHOW_WARNING_IF_DEPRECATED 0

    #if SHOW_WARNING_IF_DEPRECATED
    # define DEPRECATED(MESSAGE) __declspec(deprecated(MESSAGE))

    // Disable warning within SCDateTime.h file because we want to use these deprecated functions internally
    # pragma warning(push)
    # pragma warning(disable: 4996)
    #else
    # define DEPRECATED(MESSAGE)
    #endif

    // A date in the number of days since EPOCH.
    typedef int t_SCDate;

    // A time of day in the number of seconds since midnight.
    typedef int t_SCTime;

    enum MonthEnum
    { JANUARY = 1
    , FEBRUARY = 2
    , MARCH = 3
    , APRIL = 4
    , MAY = 5
    , JUNE = 6
    , JULY = 7
    , AUGUST = 8
    , SEPTEMBER = 9
    , OCTOBER = 10
    , NOVEMBER = 11
    , DECEMBER = 12
    };

    static const char* FULL_NAME_FOR_MONTH[13] = {"", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
    static const char* SHORT_NAME_FOR_MONTH[13] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    static const int DAYS_IN_MONTH[13] = {0, 31, 28, 31,  30,  31,  30,  31,  31,  30,  31,  30,  31};
    static const int DAYS_IN_YEAR_AT_MONTH_END[13]   = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
    static const char FUTURES_CODE_FOR_MONTH[13] = {'\0', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'Q', 'U', 'V', 'X', 'Z'};

    enum DayOfWeekEnum
    { DAY_OF_WEEK_NOT_SET = -1
    , SUNDAY = 0
    , MONDAY = 1
    , TUESDAY = 2
    , WEDNESDAY = 3
    , THURSDAY = 4
    , FRIDAY = 5
    , SATURDAY = 6
    };

    enum DayOfWeekMondayBasedEnum
    { DAY_OF_WEEK_MONDAY_BASED_NOT_SET = -1
    , MONDAY_MONDAY_BASED = 0
    , TUESDAY_MONDAY_BASED = 1
    , WEDNESDAY_MONDAY_BASED = 2
    , THURSDAY_MONDAY_BASED = 3
    , FRIDAY_MONDAY_BASED = 4
    , SATURDAY_MONDAY_BASED = 5
    , SUNDAY_MONDAY_BASED = 6
    };

    const double DATETIME_UNSET_DOUBLE = 0;
    const int64_t DATETIME_UNSET = 0;

    static const char* FULL_NAME_FOR_DAY_OF_WEEK[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
    static const char* SHORT_NAME_FOR_DAY_OF_WEEK[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
    static const char* TWO_CHAR_NAME_FOR_DAY_OF_WEEK[7] = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"};

    static const int32_t DAYS_IN_YEAR = 365;  // Approximate

    static const int MONTHS_PER_YEAR = 12;
    static const int DAYS_PER_WEEK = 7;  // number of days in a week
    static const int HOURS_PER_DAY = 24;  // number of hours in a day
    static const int MINUTES_PER_HOUR = 60;  // number of minutes in an hour
    static const int SECONDS_PER_MINUTE = 60;  // number of seconds in a minute
    static const int MILLISECONDS_PER_SECOND = 1000;  // number of milliseconds in a second
    static const std::int64_t MICROSECONDS_PER_MILLISECOND = 1000;  // number of microseconds in a millisecond
    static const int NANOSECONDS_PER_MICROSECOND = 1000;  // number of nanoseconds in a microsecond

    static const int MINUTES_PER_DAY = MINUTES_PER_HOUR*HOURS_PER_DAY;  // number of minutes in a day = 1 440
    static const int SECONDS_PER_DAY = SECONDS_PER_MINUTE*MINUTES_PER_DAY;  // number of seconds in a day = 86 400
    static const int SECONDS_PER_HOUR = SECONDS_PER_MINUTE*MINUTES_PER_HOUR;  // number of seconds in an hour = 3 600
    static const int MILLISECONDS_PER_DAY = MILLISECONDS_PER_SECOND*SECONDS_PER_DAY;  // number of milliseconds in a day = 86 400 000
    static const int MILLISECONDS_PER_HOUR = MILLISECONDS_PER_SECOND*SECONDS_PER_HOUR;  // number of milliseconds in an hour = 3 600 000
    static const int MILLISECONDS_PER_MINUTE = MILLISECONDS_PER_SECOND*SECONDS_PER_MINUTE;  // number of milliseconds in a minute = 60 000
    static const std::int64_t MICROSECONDS_PER_DAY = MICROSECONDS_PER_MILLISECOND*MILLISECONDS_PER_DAY;  // number of microseconds in a day = 86 400 000 000
    static const std::int64_t MICROSECONDS_PER_HOUR = MICROSECONDS_PER_MILLISECOND*MILLISECONDS_PER_HOUR;  // number of microseconds in an hour = 3 600 000 000
    static const std::int64_t MICROSECONDS_PER_MINUTE = MICROSECONDS_PER_MILLISECOND*MILLISECONDS_PER_MINUTE;  // number of microseconds in a minute = 60 000 000
    static const std::int64_t MICROSECONDS_PER_SECOND = MICROSECONDS_PER_MILLISECOND*MILLISECONDS_PER_SECOND;  // number of microseconds in a second = 1 000 000
    static const std::int64_t NANOSECONDS_PER_DAY = NANOSECONDS_PER_MICROSECOND*MICROSECONDS_PER_DAY;  // number of nanoseconds in a day = 86 400 000 000 000
    static const std::int64_t NANOSECONDS_PER_SECOND = NANOSECONDS_PER_MICROSECOND*MICROSECONDS_PER_SECOND;  // number of nanoseconds in a second = 1 000 000 000
    static const std::int64_t NANOSECONDS_PER_MILLISECOND = NANOSECONDS_PER_MICROSECOND*MICROSECONDS_PER_MILLISECOND;  // number of nanoseconds in a millisecond = 1 000 000

    static const int EPOCH_YEAR = 1899;
    static const int EPOCH_MONTH = 12;
    static const int EPOCH_DAY = 30;

    static const int SCDATETIME_UNIX_EPOCH_DATE = 25569;  // 1970-01-01
    static const double SCDATETIME_UNIX_EPOCH = 25569.0;  // 1970-01-01 00:00:00

    #ifdef SCDATETIME_SUPPORT_CHRONO
    // This is the SCDateTime epoch (1899-12-30 00:00:00) as a system_clock
    // time_point.
    //
    // The from_time_t method takes a number of seconds since the Unix epoch,
    // which is 1970-01-01 00:00:00.  The difference between the two epochs is
    // 25569 days, and there are 86400 seconds per day.  The product of these two
    // values would overflow a 32-bit int, so the ll literal suffix is used to
    // prevent that from happening.  Since SCDateTime epoch is before Unix epoch,
    // the offset from the Unix epoch is negative.
    static const auto SCDATETIME_EPOCH_SYSTEM_CLOCK
        = std::chrono::system_clock::from_time_t(-25569ll * 86400ll);
    #endif

    /*==========================================================================*/
    inline int DaysSince1Jan0AtYearBeginning(const int Year)
    {
        return Year * 365 + Year / 4 - Year / 100 + Year / 400;
    }

    static const int DAYS_BEFORE_UNIX_EPOCH = DaysSince1Jan0AtYearBeginning(1970) + 1;  // 1970-01-01
    static const int DAYS_BEFORE_SC_EPOCH = DaysSince1Jan0AtYearBeginning(1900) - 1;    // 1899-12-30

    int64_t SCDateTimeDoubleToSCDateTime(const double DateTime);

    /*==========================================================================*/
    DEPRECATED("The IS_UNSET is deprecated. Use portable SCDateTime::IsUnset() instead.")
    inline bool IS_UNSET(const double DateTime)
    {
        return DateTime == DATETIME_UNSET_DOUBLE;
    }
    /*==========================================================================*/
    DEPRECATED("The IS_UNSET is deprecated. Use portable SCDateTime::IsUnset() instead.")
    inline bool IS_UNSET(const int64_t DateTime)
    {
        return DateTime == DATETIME_UNSET;
    }

    /*==========================================================================*/
    inline int64_t ADJUST(const int64_t Value, const int64_t Epsilon)
    {
        if (Value < 0)
            return Value - Epsilon;
        else
            return Value + Epsilon;
    }

    /*==========================================================================*/
    inline double ADJUST(const double Value, const double Epsilon = 0.5)
    {
        if (Value < 0)
            return Value - Epsilon;
        else
            return Value + Epsilon;
    }

    /*==========================================================================*/
    DEPRECATED("The ROUND_US is private and deprecated.")
    inline double ROUND_US(const double DateTime)
    {
        return ADJUST(DateTime, 1.0 / MICROSECONDS_PER_DAY / 2);
    }

    /*==========================================================================*/
    DEPRECATED("The ADJUST_ROUND_SECOND is private and deprecated.")
    inline int64_t ADJUST_ROUND_SECOND(int64_t DateTime)
    {
        return ADJUST(DateTime, MICROSECONDS_PER_SECOND / 2);
    }

    /*============================================================================
        Add 500 microseconds to the given DateTime value.
    ----------------------------------------------------------------------------*/
    DEPRECATED("The ADJUST_ROUND_MS is private and deprecated.")
    inline int64_t ADJUST_ROUND_MS(int64_t DateTime)
    {
        return ADJUST(DateTime, MICROSECONDS_PER_MILLISECOND / 2);
    }

    /*============================================================================
        Gets the date part of a SCDateTime.  Returns the number of days since
        1899-12-30.
    ----------------------------------------------------------------------------*/
    DEPRECATED("The DATE_PART is deprecated. Use portable SCDateTime::GetDate() instead.")
    inline int DATE_PART(const int64_t DateTime)
    {
        return static_cast<int>(ADJUST_ROUND_SECOND(DateTime) / MICROSECONDS_PER_DAY);
    }

    /*==========================================================================*/
    DEPRECATED("Usage of DATE_PART is deprecated. Use portable SCDateTime::GetDate() instead.")
    inline int DATE_PART(double DateTimeDouble)
    {
        const int64_t DateTime = SCDateTimeDoubleToSCDateTime(DateTimeDouble);

        return DATE_PART(DateTime);
    }

    /*============================================================================
        Returns only the time part (ignoring the date) of the given DateTime
        value as the number of seconds since midnight.  The return value will be
        in the range [0..86399].  The given value is rounded to the nearest
        second.
    ----------------------------------------------------------------------------*/
    DEPRECATED("Usage of TIME_PART is deprecated. Use portable SCDateTime::GetTime() instead.")
    inline int TIME_PART(const int64_t DateTime)
    {
        int64_t DateTimeAdjusted = ADJUST_ROUND_SECOND(DateTime);
        DateTimeAdjusted %= MICROSECONDS_PER_DAY; // remove the date part
        int64_t TimeInSeconds = DateTimeAdjusted / MICROSECONDS_PER_SECOND;

        if (TimeInSeconds >= SECONDS_PER_DAY)
            TimeInSeconds = 0;

        return static_cast<int>(TimeInSeconds);
    }

    /*==========================================================================*/
    DEPRECATED("Usage of TIME_PART is deprecated. Use portable SCDateTime::GetTime() instead.")
    inline int TIME_PART(double DateTimeDouble)
    {
        const int64_t DateTime = SCDateTimeDoubleToSCDateTime(DateTimeDouble);

        return TIME_PART(DateTime);
    }

    /*============================================================================
        Gets the date part of a SCDateTime with millisecond rounding.  Returns
        the number of days since EPOCH.
    ----------------------------------------------------------------------------*/
    DEPRECATED("Usage of DATE_PART_MS is deprecated. Use portable SCDateTime::GetDateMS() instead.")
    inline int DATE_PART_MS(const int64_t DateTime)
    {
        return static_cast<int>(DateTime / MICROSECONDS_PER_DAY);
    }

    /*==========================================================================*/
    DEPRECATED("Usage of DATE_PART_MS is deprecated. Use portable SCDateTime::GetDateMS() instead.")
    inline int DATE_PART_MS(double DateTimeDouble)
    {
        const int64_t DateTime = SCDateTimeDoubleToSCDateTime(DateTimeDouble);

        return DATE_PART_MS(DateTime);
    }
    /*============================================================================
        Returns only the time part (ignoring the date) of the given DateTime
        value as the number of seconds since midnight.  The return value will be
        in the range 0 to 86399. The microsecond component is discarded so that the
        value is truncated to the containing second.
    ----------------------------------------------------------------------------*/
    DEPRECATED("Usage of TIME_PART_MS is deprecated. Use portable SCDateTime::GetTime() instead.")
    inline int TIME_PART_MS(const int64_t DateTime)
    {
        int64_t TimeOnly = DateTime;
        TimeOnly %= MICROSECONDS_PER_DAY; // remove the date part
        int64_t TimeInSeconds = TimeOnly / MICROSECONDS_PER_SECOND;

        if (TimeInSeconds >= SECONDS_PER_DAY)
            TimeInSeconds = 0;

        return static_cast<int>(TimeInSeconds);
    }

    /*==========================================================================*/
    DEPRECATED("Usage of TIME_PART_MS is deprecated. Use portable SCDateTime::GetTime() instead.")
    inline int TIME_PART_MS(double DateTimeDouble)
    {
        const int64_t DateTime = SCDateTimeDoubleToSCDateTime(DateTimeDouble);

        return TIME_PART_MS(DateTime);
    }

    /*============================================================================
        Returns only the seconds part of the given DateTime, ignoring any
        date part or time part that is 1 minute or greater.  The return value
        will be in the range [0..59].  The given value is rounded to the nearest
        second.
    ----------------------------------------------------------------------------*/
    DEPRECATED("The SECONDS_PART is deprecated. Use portable SCDateTime::GetSecond() instead.")
    inline int SECONDS_PART(const int64_t DateTime)
    {
        // Round to the nearest second
        const int64_t DateTimeAdjusted = ADJUST_ROUND_SECOND(DateTime);
        int SecondsPart = (DateTimeAdjusted / MICROSECONDS_PER_SECOND) % SECONDS_PER_MINUTE;

        if (DateTime < 0)
            SecondsPart = -SecondsPart;

        return SecondsPart;
    }

    /*==========================================================================*/
    DEPRECATED("The SECONDS_PART is deprecated. Use portable SCDateTime::GetSecond() instead.")
    inline int SECONDS_PART(double DateTimeDouble)
    {
        const int64_t DateTime = SCDateTimeDoubleToSCDateTime(DateTimeDouble);

        return SECONDS_PART(DateTime);
    }

    /*============================================================================
        Returns only the milliseconds part of the given DateTime, ignoring any
        date part or time part that is 1 second or greater.  The return value
        will be in the range [0..999].
    ----------------------------------------------------------------------------*/
    DEPRECATED("The MS_PART is deprecated. Use portable SCDateTime::GetMillisecond() instead.")
    inline int MS_PART(const int64_t DateTime)
    {
        const int MillisecondsPart = (DateTime / MICROSECONDS_PER_MILLISECOND) % MILLISECONDS_PER_SECOND;

        return MillisecondsPart;
    }

    /*==========================================================================*/
    DEPRECATED("The MS_PART is deprecated. Use portable SCDateTime::GetMillisecond() instead.")
    inline int MS_PART(double DateTimeDouble)
    {
        const int64_t DateTime = SCDateTimeDoubleToSCDateTime(DateTimeDouble);

        return MS_PART(DateTime);
    }

    /*============================================================================
        Combines a date (days since 1899-12-30) and time (seconds since midnight)
        into a SCDateTime/OLE Date Time value.
    ----------------------------------------------------------------------------*/
    DEPRECATED("The COMBINE_DATE_TIME is deprecated. Use SCDateTime::SCDateTime(int Date, int TimeInSeconds) constructor instead.")
    inline double COMBINE_DATE_TIME(int Date, int Time)
    {
        return (Date) + Time / static_cast<double>(SECONDS_PER_DAY);
    }

    /*==========================================================================*/
    DEPRECATED("The COMBINE_DATE_TIME is deprecated. Use SCDateTime::SCDateTime(int Date, int TimeInSeconds) constructor instead.")
    inline int64_t COMBINE_DATE_TIME_US(int Date, int Time)
    {
        return (Date)* MICROSECONDS_PER_DAY + Time * MICROSECONDS_PER_SECOND;
    }

    /*==========================================================================*/
    DEPRECATED("The DAY_OF_WEEK is deprecated. Use SCDateTime::GetDayOfWeek() instead.")
    inline DayOfWeekEnum DAY_OF_WEEK(int Date)
    {
        Date -= 1;
        // Special handling for zero and negative values.
        if (Date < 0)
            Date = Date % DAYS_PER_WEEK + DAYS_PER_WEEK;

        return static_cast<DayOfWeekEnum>(Date % DAYS_PER_WEEK);
    }

    /*==========================================================================*/
    DEPRECATED("The DAY_OF_WEEK is deprecated. Use SCDateTime::GetDayOfWeek() instead.")
    inline DayOfWeekEnum DAY_OF_WEEK(double DateTime)
    {
        return DAY_OF_WEEK(DATE_PART(DateTime));
    }

    /*==========================================================================*/
    DEPRECATED("The DAY_OF_WEEK_MONDAY_BASED is deprecated. Use SCDateTime::GetDayOfWeekMondayBased() instead.")
    inline DayOfWeekMondayBasedEnum DAY_OF_WEEK_MONDAY_BASED(int Date)
    {
        Date -= 2;
        if (Date < 0)
            Date = DAYS_PER_WEEK + Date % DAYS_PER_WEEK ;

        return static_cast<DayOfWeekMondayBasedEnum>(Date % DAYS_PER_WEEK);
    }
    /*==========================================================================*/
    inline const char* GetFullNameForMonth(int Month)
    {
        if (Month < JANUARY || Month > DECEMBER)
            return FULL_NAME_FOR_MONTH[0];

        return FULL_NAME_FOR_MONTH[Month];
    }

    /*==========================================================================*/
    inline const char* GetShortNameForMonth(int Month)
    {
        if (Month < JANUARY || Month > DECEMBER)
            return SHORT_NAME_FOR_MONTH[0];

        return SHORT_NAME_FOR_MONTH[Month];
    }

    /*==========================================================================*/
    inline int GetMonthFromShortName(const char* ShortName)
    {
        if (ShortName == NULL)
            return 0;

        for (int Month = JANUARY; Month <= DECEMBER; ++Month)
        {
            #if _MSC_VER >= 1400
            if (_stricmp(ShortName, SHORT_NAME_FOR_MONTH[Month]) == 0)
            #elif __linux__
            if (strcasecmp(ShortName, SHORT_NAME_FOR_MONTH[Month]) == 0)
            #else
            if (stricmp(ShortName, SHORT_NAME_FOR_MONTH[Month]) == 0)
            #endif
                return Month;
        }

        return 0;
    }

    /*============================================================================
        Returns the month (JANUARY-DECEMBER) for the given MonthCode.  Returns 0
        if the given MonthCode does not match any of the futures codes for months.
    ----------------------------------------------------------------------------*/
    inline int GetMonthFromFuturesCode(char MonthCode)
    {
        // Make uppercase
        if (MonthCode >= 'a' && MonthCode <= 'z')
            MonthCode += 'A' - 'a';

        for (int Month = JANUARY; Month <= DECEMBER; ++Month)
        {
            if (MonthCode == FUTURES_CODE_FOR_MONTH[Month])
                return Month;
        }

        return 0;
    }

    /*==========================================================================*/
    inline bool IsValidFuturesMonthCode(char MonthCode)
    {
        return (GetMonthFromFuturesCode(MonthCode) != 0);
    }

    /*==========================================================================*/
    inline const char* GetFullNameForDayOfWeek(int DayOfWeek)
    {
        if (DayOfWeek < SUNDAY || DayOfWeek > SATURDAY)
            return "";

        return FULL_NAME_FOR_DAY_OF_WEEK[DayOfWeek];
    }

    /*==========================================================================*/
    inline const char* GetShortNameForDayOfWeek(int DayOfWeek)
    {
        if (DayOfWeek < SUNDAY || DayOfWeek > SATURDAY)
            return "";

        return SHORT_NAME_FOR_DAY_OF_WEEK[DayOfWeek];
    }

    /*==========================================================================*/
    inline const char* GetTwoCharNameForDayOfWeek(int DayOfWeek)
    {
        if (DayOfWeek < SUNDAY || DayOfWeek > SATURDAY)
            return "";

        return TWO_CHAR_NAME_FOR_DAY_OF_WEEK[DayOfWeek];
    }

    /*==========================================================================*/
    inline DayOfWeekEnum GetDayOfWeekFromInt(int DayOfWeek)
    {
        if (DayOfWeek < SUNDAY || DayOfWeek > SATURDAY)
            return DAY_OF_WEEK_NOT_SET;

        return static_cast<DayOfWeekEnum>(DayOfWeek);
    }

    /*==========================================================================*/
    inline DayOfWeekEnum GetDayOfWeekFromFullName(const char* FullName)
    {
        if (FullName == NULL)
            return DAY_OF_WEEK_NOT_SET;

        for (int DayOfWeek = SUNDAY; DayOfWeek <= SATURDAY; ++DayOfWeek)
        {
            #if _MSC_VER >= 1400
            if (_stricmp(FullName, FULL_NAME_FOR_DAY_OF_WEEK[DayOfWeek]) == 0)
            #elif __linux__
            if (strcasecmp(FullName, FULL_NAME_FOR_DAY_OF_WEEK[DayOfWeek]) == 0)
            #else
            if (stricmp(FullName, FULL_NAME_FOR_DAY_OF_WEEK[DayOfWeek]) == 0)
            #endif
                return static_cast<DayOfWeekEnum>(DayOfWeek);
        }

        return DAY_OF_WEEK_NOT_SET;
    }

    /*==========================================================================*/
    inline DayOfWeekEnum GetDayOfWeekFromShortName(const char* ShortName)
    {
        if (ShortName == NULL)
            return DAY_OF_WEEK_NOT_SET;

        for (int DayOfWeek = SUNDAY; DayOfWeek <= SATURDAY; ++DayOfWeek)
        {
            #if _MSC_VER >= 1400
            if (_stricmp(ShortName, SHORT_NAME_FOR_DAY_OF_WEEK[DayOfWeek]) == 0)
            #elif __linux__
            if (strcasecmp(ShortName, SHORT_NAME_FOR_DAY_OF_WEEK[DayOfWeek]) == 0)
            #else
            if (stricmp(ShortName, SHORT_NAME_FOR_DAY_OF_WEEK[DayOfWeek]) == 0)
            #endif
                return static_cast<DayOfWeekEnum>(DayOfWeek);
        }

        return DAY_OF_WEEK_NOT_SET;
    }

    /*==========================================================================*/
    DEPRECATED("The IsSaturday is deprecated. Use SCDateTime::IsSaturday() instead.")
    inline bool IsSaturday(int Date)
    {
        return (DAY_OF_WEEK(Date) == SATURDAY);
    }

    /*==========================================================================*/
    DEPRECATED("The IsSaturday is deprecated. Use SCDateTime::IsSaturday() instead.")
    inline bool IsSaturday(double DateTime)
    {
        return (DAY_OF_WEEK(DateTime) == SATURDAY);
    }

    /*==========================================================================*/
    DEPRECATED("The IsSunday is deprecated. Use SCDateTime::IsSunday() instead.")
    inline bool IsSunday(int Date)
    {
        return (DAY_OF_WEEK(Date) == SUNDAY);
    }

    /*==========================================================================*/
    DEPRECATED("The IsSunday is deprecated. Use SCDateTime::IsSunday() instead.")
    inline bool IsSunday(double DateTime)
    {
        return (DAY_OF_WEEK(DateTime) == SUNDAY);
    }

    /*==========================================================================*/
    DEPRECATED("The IsWeekend is deprecated. Use SCDateTime::IsWeekend() instead.")
    inline bool IsWeekend(int Date)
    {
        const int DayOfWeek = DAY_OF_WEEK(Date);

        return (DayOfWeek == SUNDAY || DayOfWeek == SATURDAY);
    }

    /*==========================================================================*/
    DEPRECATED("The IsWeekend is deprecated. Use SCDateTime::IsWeekend() instead.")
    inline bool IsWeekend(double DateTime)
    {
        const int DayOfWeek = DAY_OF_WEEK(DateTime);

        return (DayOfWeek == SUNDAY || DayOfWeek == SATURDAY);
    }

    /*==========================================================================*/
    inline bool IsWeekend(int Date, bool UseSaturdayData)
    {
        const int DayOfWeek = DAY_OF_WEEK(Date);

        return (DayOfWeek == SUNDAY || (!UseSaturdayData && DayOfWeek == SATURDAY));
    }

    /*==========================================================================*/
    inline bool IsWeekend(double DateTime, bool UseSaturdayData)
    {
        const int DayOfWeek = DAY_OF_WEEK(DateTime);

        return (DayOfWeek == SUNDAY || (!UseSaturdayData && DayOfWeek == SATURDAY));
    }

    /*==========================================================================*/
    inline bool IsBusinessDay(int Date)
    {
        return !IsWeekend(Date);
    }

    /*==========================================================================*/
    inline bool IsLeapYear(int Year)
    {
        return ((Year & 3) == 0) && ((Year % 100) != 0 || (Year % 400) == 0);
    }

    /*==========================================================================*/
    inline int GetDaysInMonth(int Month, int Year)
    {
        if (Month < JANUARY || Month > DECEMBER)
            return 0;

        if (Month == FEBRUARY && IsLeapYear(Year))
            return DAYS_IN_MONTH[Month] + 1;
        else
            return DAYS_IN_MONTH[Month];
    }

    /*============================================================================
        This function returns the number of weekdays within the given date span,
        including both the FirstDate and the LastDate.  Neither Saturdays nor
        Sundays are counted.
    ----------------------------------------------------------------------------*/
    inline int DaysInDateSpanNotIncludingWeekends(int FirstDate, int LastDate)
    {
        if (FirstDate > LastDate)
        {
            // Swap the dates
            const int EarlierDate = LastDate;
            LastDate = FirstDate;
            FirstDate = EarlierDate;
        }

        const int SpanDifference = LastDate - FirstDate;
        const int FirstDayOfWeek = DAY_OF_WEEK(FirstDate);
        const int SundayBasedSpan = SpanDifference + FirstDayOfWeek;

        int NumSaturdays;
        if (SundayBasedSpan - SATURDAY < 0)
            NumSaturdays = 0;
        else
            NumSaturdays = (SundayBasedSpan - SATURDAY) / DAYS_PER_WEEK + 1;

        int NumSundays = SundayBasedSpan / DAYS_PER_WEEK;
        if (FirstDayOfWeek == SUNDAY)
            ++NumSundays;

        return SpanDifference + 1 - NumSaturdays - NumSundays;
    }

    /*============================================================================
        SCDateTime values are the same as Excel DateTime values.  These are
        stored as a floating point value (double) representing the number of days
        since 1899-12-30 00:00:00.  (Time is represented as a fraction of a day.)
        Unix-style timestamps are stored as integer values representing the
        number of seconds since 1970-01-01 00:00:00.  These two functions are
        used to convert from one to the other.
    ----------------------------------------------------------------------------*/
    DEPRECATED("The SCDateTimeDoubleToUNIXTime is deprecated. Use SCDateTime::ToUNIXTime() instead.")
    inline time_t SCDateTimeDoubleToUNIXTime(double DateTimeDouble)
    {
        if (IS_UNSET(DateTimeDouble))
            return 0;

        return (time_t)ADJUST((DateTimeDouble - SCDATETIME_UNIX_EPOCH) * SECONDS_PER_DAY);
    }
    /*==========================================================================*/
    DEPRECATED("The SCDateTimeToFloatUNIXTime is deprecated. Use SCDateTime::ToFloatUNIXTime() instead.")
    inline double SCDateTimeToFloatUNIXTime(double DateTimeDouble)
    {
        if (IS_UNSET(DateTimeDouble))
            return DATETIME_UNSET_DOUBLE;

        return ((DateTimeDouble - SCDATETIME_UNIX_EPOCH) * SECONDS_PER_DAY);
    }
    /*==========================================================================*/
    DEPRECATED("The SCDateTimeDoubleToSCDateTime is private and deprecated")
    inline int64_t SCDateTimeDoubleToSCDateTime(const double DateTime)
    {
        if (IS_UNSET(DateTime))
            return DATETIME_UNSET;

        return static_cast<int64_t>(ADJUST(DateTime * MICROSECONDS_PER_DAY));
    }

    /*==========================================================================*/
    inline double SCUNIXTimeToSCDateTime(const int64_t SCUnixTime)
    {
        return double(SCUnixTime) / MICROSECONDS_PER_DAY;
    }

    /*==========================================================================*/
    // UNIXTime is in seconds.
    DEPRECATED("The UNIXTimeToSCDateTime is deprecated. Use SCDateTime::SetUNIXTime() instead.")
    inline double UNIXTimeToSCDateTime(time_t UnixTime)
    {
        if (UnixTime == 0)
            return DATETIME_UNSET_DOUBLE;

        return (UnixTime) / static_cast<double>(SECONDS_PER_DAY) + SCDATETIME_UNIX_EPOCH;
    }

    /*==========================================================================*/
    DEPRECATED("The UNIXTimeToSCDateTimeUNIX is deprecated. Use SCDateTime::SetUNIXTime() instead.")
    inline int64_t UNIXTimeToSCDateTimeUNIX(time_t UnixTime)
    {
        if (UnixTime == 0)
            return DATETIME_UNSET;

        return UnixTime * MICROSECONDS_PER_SECOND + SCDATETIME_UNIX_EPOCH_DATE * MICROSECONDS_PER_DAY;
    }

    /*==========================================================================*/
    DEPRECATED("The UNIXTimeWithMillisecondsToSCDateTime is deprecated. Use SCDateTime::SetUNIXTimeWithMilliseconds() instead.")
    inline double UNIXTimeWithMillisecondsToSCDateTime(double UnixTimeWithMilliseconds)
    {
        if (UnixTimeWithMilliseconds == 0.0)
            return DATETIME_UNSET_DOUBLE;

        return UnixTimeWithMilliseconds / SECONDS_PER_DAY + SCDATETIME_UNIX_EPOCH;
    }

    /*==========================================================================*/
    DEPRECATED("The UNIXTimeWithMillisecondsToSCDateTimeUNIX is deprecated. Use SCDateTime::SetUNIXTimeWithMilliseconds() instead.")
    inline int64_t UNIXTimeWithMillisecondsToSCDateTimeUNIX(double UnixTimeWithMilliseconds)
    {
        if (UnixTimeWithMilliseconds == 0.0)
            return DATETIME_UNSET;

        return static_cast<int64_t>(ADJUST(UnixTimeWithMilliseconds * MICROSECONDS_PER_SECOND)) + SCDATETIME_UNIX_EPOCH_DATE * MICROSECONDS_PER_DAY;
    }

    /*==========================================================================*/
    inline int64_t HMS_MS_DATETIME(int Hour, int Minute, int Second, int Millisecond)
    {
        return Hour * MICROSECONDS_PER_HOUR
            + Minute * MICROSECONDS_PER_MINUTE
            + Second * MICROSECONDS_PER_SECOND
            + Millisecond * MICROSECONDS_PER_MILLISECOND;
    }

    /*============================================================================
        This function expects one based values for Month and Day.
    ----------------------------------------------------------------------------*/
    inline int64_t YMDHMS_MS_DATETIME(int Year, int Month, int Day, int Hour, int Minute, int Second, int Millisecond)
    {
        // Validate year and month (ignore day of week)
        if (Year > 9999 || Year < -9999 || Month < 1 || Month > 12)
            return DATETIME_UNSET;

        //  Check for leap year and set the number of days in the month
        const bool bLeapYear = IsLeapYear(Year);

        const int nDaysInMonth
            = DAYS_IN_YEAR_AT_MONTH_END[Month] - DAYS_IN_YEAR_AT_MONTH_END[Month - 1]
            + ((bLeapYear && Day == 29 && Month == 2) ? 1 : 0);

        // Finish validating the date
        if ( Day < 1 || Day > nDaysInMonth
        )
        {
            return DATETIME_UNSET;
        }

        //It is a valid date; make Jan 1, 1AD be 1
        int nDate = DaysSince1Jan0AtYearBeginning(Year)
            + DAYS_IN_YEAR_AT_MONTH_END[Month - 1]
            + Day;

        //  If leap year and it's before March, subtract 1:
        if (Month <= 2 && bLeapYear)
            --nDate;

        //  Offset so that 12/30/1899 is 0
        nDate -= DAYS_BEFORE_SC_EPOCH;

        const int64_t Time = HMS_MS_DATETIME(Hour, Minute, Second, Millisecond);

        return nDate * MICROSECONDS_PER_DAY + ((nDate >= 0) ? Time : -Time);
    }

    /*==========================================================================*/
    DEPRECATED("The YMDHMS_DATETIME is deprecated. Use SCDateTime::GetDateYMD() instead.")
    inline int64_t YMDHMS_DATETIME(int Year, int Month, int Day, int Hour, int Minute, int Second)
    {
        return YMDHMS_MS_DATETIME(Year, Month, Day, Hour, Minute, Second, 0);
    }

    /*============================================================================
        This function is thread safe.
    ----------------------------------------------------------------------------*/
    inline void DATETIME_TO_YMDHMS_MS(int64_t DateTime, int& Year, int& Month, int& Day, int& Hour, int& Minute, int& Second, int& MillisecondOrMicrosecond, const bool GetMicroseconds = false)
    {
        Year = Month = Day = Hour = Minute = Second = 0;

        int n400Years;          // Number of 400 year increments since 1/1/0
        int n400Century;        // Century within 400 year block (0,1,2 or 3)
        int n4Years;            // Number of 4 year increments since 1/1/0
        int n4Day;              // Day within 4 year block
                                //  (0 is 1/1/yr1, 1460 is 12/31/yr4)
        int n4Yr;               // Year within 4 year block (0,1,2 or 3)
        int bLeap4 = 1;         // TRUE if 4 year block includes leap year

        int64_t TempDateTime = DateTime; // temporary serial date

        if (DateTime != DATETIME_UNSET)
        {
            // If resolving for second fractions
            if (MillisecondOrMicrosecond != -1)
            {
                // DateTime is rounded to microsecond by default
                if (!GetMicroseconds)
                {
                    // Round to the millisecond.
                    TempDateTime = ADJUST_ROUND_MS(DateTime);
                }
            }
            else
            {
                // Round to the second
                TempDateTime = ADJUST_ROUND_SECOND(DateTime);
            }
        }

        MillisecondOrMicrosecond = 0;

        // Number of days from 1970-01-01
        const int nAllDays = static_cast<int>(TempDateTime / MICROSECONDS_PER_DAY);

        int nDaysAbsolute = nAllDays + DAYS_BEFORE_SC_EPOCH;    // Add days from 1/1/0 to 12/30/1899

        TempDateTime = abs(TempDateTime);
        int64_t Time = TempDateTime % MICROSECONDS_PER_DAY;

        const int NumberOfDaysin400Years = DaysSince1Jan0AtYearBeginning(400);

        // Leap years every 4 yrs except centuries not multiples of 400.
        n400Years = nDaysAbsolute / NumberOfDaysin400Years;

        // Set nDaysAbsolute to day within 400-year block
        nDaysAbsolute %= NumberOfDaysin400Years;

        // -1 because first century has extra day
        n400Century = ((nDaysAbsolute - 1) / 36524);

        // Non-leap century
        if (n400Century != 0)
        {
            // Set nDaysAbsolute to day within century
            nDaysAbsolute = (nDaysAbsolute - 1) % 36524;

            // +1 because 1st 4 year increment has 1460 days
            n4Years = ((nDaysAbsolute + 1) / 1461);

            if (n4Years != 0)
                n4Day = ((nDaysAbsolute + 1) % 1461);
            else
            {
                bLeap4 = 0;
                n4Day = nDaysAbsolute;
            }
        }
        else
        {
            // Leap century - not special case!
            n4Years = nDaysAbsolute / 1461;
            n4Day = nDaysAbsolute % 1461;
        }

        if (bLeap4)
        {
            // -1 because first year has 366 days
            n4Yr = (n4Day - 1) / 365;

            if (n4Yr != 0)
                n4Day = (n4Day - 1) % 365;
        }
        else
        {
            n4Yr = n4Day / 365;
            n4Day %= 365;
        }

        // n4Day is now 0-based day of year. Save 1-based day of year, year number
        Year = n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr;

        do
        {
            // Handle leap year: before, on, and after Feb. 29.
            if (n4Yr == 0 && bLeap4)
            {
                // Leap Year
                if (n4Day == 59)
                {
                    /* Feb. 29 */
                    Month = 2;
                    Day = 29;

                    break;
                }

                // Pretend it's not a leap year for month/day comp.
                if (n4Day >= 60)
                    --n4Day;
            }

            // Make n4DaY a 1-based day of non-leap year and compute
            //  month/day for everything but Feb. 29.
            ++n4Day;

            // Month number always >= n/32, so save some loop time */
            for (Month = (n4Day >> 5) + 1;
                n4Day > DAYS_IN_YEAR_AT_MONTH_END[Month]; Month++);

            Day = (n4Day - DAYS_IN_YEAR_AT_MONTH_END[Month - 1]);
        } while (false);

        if (Time != 0)
        {
            Hour = static_cast<int>(Time / MICROSECONDS_PER_HOUR);
            Time -= Hour * MICROSECONDS_PER_HOUR;
            Minute = static_cast<int>(Time / MICROSECONDS_PER_MINUTE);
            Time -= Minute * MICROSECONDS_PER_MINUTE;
            Second = static_cast<int>(Time / MICROSECONDS_PER_SECOND);
            Time -= Second * MICROSECONDS_PER_SECOND;

            if (GetMicroseconds)
                MillisecondOrMicrosecond = static_cast<int>(Time);
            else
                MillisecondOrMicrosecond = static_cast<int>(Time / MICROSECONDS_PER_MILLISECOND);
        }
    }

    /*============================================================================
        This function is thread safe.
    ----------------------------------------------------------------------------*/
    DEPRECATED("The DATETIME_TO_YMDHMS is deprecated. Use SCDateTime::GetDateTimeYMDHMS() instead.")
    inline void DATETIME_TO_YMDHMS(int64_t DateTime, int& Year, int& Month, int& Day, int& Hour, int& Minute, int& Second)
    {
        int Millisecond = -1;
        DATETIME_TO_YMDHMS_MS(DateTime, Year, Month, Day,  Hour, Minute, Second, Millisecond);
    }

    DEPRECATED("The DATETIME_TO_YMDHMS is deprecated. Use SCDateTime::GetDateTimeYMDHMS() instead.")
    inline void DATETIME_TO_YMDHMS(double DateTime, int& Year, int& Month, int& Day, int& Hour, int& Minute, int& Second)
    {
        DATETIME_TO_YMDHMS(SCDateTimeDoubleToSCDateTime(DateTime), Year, Month, Day, Hour, Minute, Second);
    }

    /*==========================================================================*/
    DEPRECATED("The YMD_DATE is deprecated. Use SCDateTime::SCDateTime(int Year, int Month, int Day, int Hour, int Minute, int Second).GetDate() instead.")
    inline int YMD_DATE(int Year, int Month, int Day)
    {
        return static_cast<int>(YMDHMS_DATETIME(Year, Month, Day, 0, 0, 0) / MICROSECONDS_PER_DAY);
    }

    /*==========================================================================*/
    DEPRECATED("The DATE_TO_YMD is deprecated. Use SCDateTime::GetDateYMD() instead.")
    inline void DATE_TO_YMD(int Date, int& Year, int& Month, int& Day)
    {
        int Hour, Minute, Second;
        DATETIME_TO_YMDHMS(Date * MICROSECONDS_PER_DAY, Year, Month, Day, Hour, Minute, Second);
    }

    /*============================================================================
        Converts hours, minutes, seconds to an integer time.  This is seconds
        since midnight.
    ----------------------------------------------------------------------------*/
    DEPRECATED("The HMS_TIME is deprecated. Use SCDateTime(int Hour, int Minute, int Second, int Millisecond).GetTime() instead.")
    inline int HMS_TIME(int Hour, int Minute, int Second)
    {
        return (Hour * SECONDS_PER_HOUR + Minute * SECONDS_PER_MINUTE + Second);
    }

    /*==========================================================================*/
    inline int HMS_TIME_WITH_VALIDATION(int Hour, int Minute, int Second)
    {
        if (Hour < 0 || Hour > 23 || Minute < 0 || Minute > 59 || Second < 0 || Second > 59)
            return 0;

        return HMS_TIME(Hour, Minute, Second);
    }

    /*==========================================================================*/
    inline int HOUR_OF_TIME(int Time)
    {
        return ((Time / SECONDS_PER_HOUR) % HOURS_PER_DAY);
    }

    /*==========================================================================*/
    inline int MINUTE_OF_TIME(int Time)
    {
        return ((Time / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR);
    }

    /*==========================================================================*/
    inline int SECOND_OF_TIME(int Time)
    {
        return (Time % SECONDS_PER_MINUTE);
    }

    /*==========================================================================*/
    DEPRECATED("The TIME_TO_HMS is deprecated. Use SCDateTime::GetTimeHMS() instead.")
    inline void TIME_TO_HMS(int Time, int& Hour, int& Minute, int& Second)
    {
        Hour = HOUR_OF_TIME(Time);
        Minute = MINUTE_OF_TIME(Time);
        Second = SECOND_OF_TIME(Time);
    }

    /*****************************************************************************
    // SCDateTime

    The SCDateTime object wraps a single 8-byte integer value
    representing a complete date and time in form of a number of microseconds
    elapsed from the SC epoch, 30 December 1899 00:00:00.

    Comparison operators on this class are designed to compare date-time values
    (including doubles) within half a second.  For best results, at least one of
    the date-time values should be as close to the exact second as possible,
    meaning avoid any milliseconds.
    ----------------------------------------------------------------------------*/

    class SCDateTime
    {
        private:
            int64_t m_dt;  // microseconds

        public:
            SCDateTime();
            #ifdef SCDATETIME_SUPPORT_CHRONO
            template<typename t_Rep, typename t_Period>
                SCDateTime(const std::chrono::duration<t_Rep, t_Period> Duration);
            SCDateTime(const std::chrono::system_clock::time_point TimePoint);
            #endif
            SCDateTime(double DateTime);
            SCDateTime(const SCDateTime& DateTime);
            SCDateTime(int Date, int TimeInSeconds);
            SCDateTime(int Hour, int Minute, int Second, int Millisecond);
            SCDateTime(int Year, int Month, int Day, int Hour, int Minute, int Second);
            SCDateTime(int Year, int Month, int Day, int Hour, int Minute, int Second, int Millisecond);

            void ValidateAsCorrectDateTime();

            const SCDateTime& operator = (double dt);
            const SCDateTime& operator = (const SCDateTime& DateTime);
            const SCDateTime& operator += (double dt);
            const SCDateTime& operator += (const SCDateTime& DateTime);
            const SCDateTime& operator -= (double dt);
            const SCDateTime& operator -= (const SCDateTime& DateTime);

            bool operator == (int Date) const;
            bool operator != (int Date) const;
            bool operator < (int Date) const;
            bool operator <= (int Date) const;
            bool operator > (int Date) const;
            bool operator >= (int Date) const;

            bool operator == (double dt) const;
            bool operator != (double dt) const;
            bool operator < (double dt) const;
            bool operator <= (double dt) const;
            bool operator > (double dt) const;
            bool operator >= (double dt) const;

            bool operator == (const SCDateTime& DateTime) const;
            bool operator != (const SCDateTime& DateTime) const;
            bool operator < (const SCDateTime& DateTime) const;
            bool operator <= (const SCDateTime& DateTime) const;
            bool operator > (const SCDateTime& DateTime) const;
            bool operator >= (const SCDateTime& DateTime) const;

            void Clear();
            void SetToMaximum();
            bool IsMaximum() const;
            bool IsUnset() const;
            bool IsDateSet() const;
            bool IsTimeAtMidnight() const;
            void ClearDate();
            void SetAsNegative();
            int GetDate() const;
            int GetDateMS() const;
            int GetDateUS() const;
            SCDateTime GetDateAsSCDateTime() const;
            int GetDays() const;

            int GetTime() const;
            int GetTimeInSeconds() const;
            int GetTimeInMilliseconds() const;
            int GetTimeInSecondsWithoutMilliseconds() const;

            SCDateTime GetTimeAsSCDateTime() const;
            SCDateTime GetTimeAsSCDateTimeMS() const;
            double GetTimeAsDouble() const;

            SCDateTime GetDateTimeRoundedToSeconds() const;

            void GetDateYMD(int& Year, int& Month, int& Day) const;
            void GetTimeHMS(int& Hour, int& Minute, int& Second) const;
            void GetDateTimeYMDHMS(int& Year, int& Month, int& Day, int& Hour, int& Minute, int& Second) const;
            void GetDateTimeYMDHMS_MS(int& Year, int& Month, int& Day, int& Hour, int& Minute, int& Second, int& Millisecond) const;
            void GetDateTimeYMDHMS_US(int& Year, int& Month, int& Day, int& Hour, int& Minute, int& Second, int& Microsecond) const;
            int GetYear() const;
            int GetMonth() const;
            int GetDay() const;
            int GetHour() const;
            int GetMinute() const;
            int GetSecond() const;
            int GetMicrosecond() const;
            int GetMillisecond() const;
            int GetDayOfWeek() const;
            int GetDayOfWeekMondayBased() const;
            SCDateTime& SetToPriorSundayForDateTime(const SCDateTime& OriginalDateTime);

            // Note: These truncate to the containing unit.
            std::int64_t AsMicrosecondsSinceBaseDate() const;
            std::int64_t AsMillisecondsSinceBaseDate() const;
            std::int64_t AsSecondsSinceBaseDate() const;

            // Note: These round to the nearest unit.
            std::int64_t GetMillisecondsSinceBaseDate() const;
            std::int64_t GetSecondsSinceBaseDate() const;
            int GetMinutesSinceBaseDate() const;
            int GetHoursSinceBaseDate() const;
            int GetDaysSinceBaseDate() const;
            int GetWeeksSinceBaseDate() const;
            int GetYearsSinceBaseDate() const;

            double GetFloatMillisecondsSinceBaseDate() const;
            double GetFloatSecondsSinceBaseDate() const;
            double GetFloatMinutesSinceBaseDate() const;
            double GetFloatHoursSinceBaseDate() const;
            double GetFloatDaysSinceBaseDate() const;
            double GetFloatWeeksSinceBaseDate() const;
            double GetFloatYearsSinceBaseDate() const;

            int GetDateDifferenceInDays(const SCDateTime& DateTime) const;

            bool IsNegative() const;

            SCDateTime GetAbsoluteValue() const;
            double GetAsDouble() const;

            bool IsWeekend(const bool UseSaturdayData = false) const;
            bool IsSaturday() const;
            bool IsSunday() const;
            bool IsMonday() const;
            bool IsGivenTimeWithinGivenTimeRange(const SCDateTime& DateTimeToCompareTo, const SCDateTime& TimeWithin);

            int GetBusinessDaysBetweenDates(const SCDateTime& FutureDate) const;
            bool IsSameDate(const SCDateTime& DateTime) const;

            bool IsSameTimeToHour(const SCDateTime& DateTime) const;
            bool IsSameTimeToMinute(const SCDateTime& DateTime) const;
            bool IsSameTimeToSecond(const SCDateTime& DateTime) const;
            bool IsSameTimeToMillisecond(const SCDateTime& DateTime) const;

            void RoundDateTimeDownToMinute();
            void RoundDateTimeDownToSecond();
            void RoundDateTimeDownToMillisecond();
            void RoundToNearestSecond();
            void RoundToNearestMillisecond();
            SCDateTime& SetDateTimeAsDouble(double DateTime);
            SCDateTime& SetDateTime(int Date, int Time);
            SCDateTime& SetDate(int Date);
            SCDateTime& SetDate(const SCDateTime& Date);
            SCDateTime& SetTime(int Time);
            SCDateTime& SetTimeFromSCDateTime(const SCDateTime& Time);
            SCDateTime& SetDateYMD(int Year, int Month, int Day);
            SCDateTime& SetTimeHMS(int Hour, int Minute, int Second);
            SCDateTime& SetTimeHMS_MS(int Hour, int Minute, int Second, int Millisecond);
            SCDateTime& SetTimeHMS_US(int Hour, int Minute, int Second, int Microsecond);
            SCDateTime& SetDateTimeYMDHMS(int Year, int Month, int Day, int Hour, int Minute, int Second);
            SCDateTime& SetDateTimeYMDHMS_MS(int Year, int Month, int Day, int Hour, int Minute, int Second, int Millisecond);
            SCDateTime& SetDateTimeYMDHMS_US(int Year, int Month, int Day, int Hour, int Minute, int Second, int Microsecond);
            SCDateTime& SetFromUNIXTimeInSeconds(time_t UNIXTime);
            SCDateTime& SetUNIXTimeWithMilliseconds(double UNIXTime);

            SCDateTime& AddNanoseconds(const std::uint64_t Nanoseconds);
            SCDateTime& AddMicroseconds(int64_t Microseconds);
            SCDateTime& SubtractMicroseconds(int Microseconds);
            SCDateTime& AddMilliseconds(int Milliseconds);
            SCDateTime& SubtractMilliseconds(int Milliseconds);
            SCDateTime& AddSeconds(int Seconds);
            SCDateTime& SubtractSeconds(int Seconds);
            SCDateTime& AddMinutes(int Minutes);
            SCDateTime& SubtractMinutes(int Minutes);
            SCDateTime& AddHours(int Hours);
            SCDateTime& SubtractHours(int Hours);

            SCDateTime& AddDays(int Days);
            SCDateTime& SubtractDays(int Days);
            SCDateTime& AddYears(int Years);
            SCDateTime& SubtractYears(int Years);
            SCDateTime& SetDayToLastDayInMonth();
            SCDateTime& MultiplyTime(float Multiplier);

            time_t ToUNIXTime() const;
            double ToFloatUNIXTime() const;
            int64_t ToUNIXTimeInMilliseconds() const;
            int64_t ToUNIXTimeInMicroseconds() const;
            double ToUNIXTimeWithMillisecondsFraction() const;

            void SetFromUNIXTimeMilliseconds(int64_t UNIXTimeMilliseconds);
            void SetFromUNIXTimeMicroseconds(int64_t UNIXTimeMicroseconds);
            void SetFromUnixTimeInDays(const int Days);
            void SetFromUNIXTimeMillisecondsFraction(double UNIXTimeMillisecondsFraction);

            static SCDateTime GetMinimumDate();
            static SCDateTime GetMaximumDate();

            static inline SCDateTime YEARS(const int Years)
            {
                SCDateTime DT;
                DT.GetInternalDateTime() = static_cast<int64_t>(ROUND_US(Years * 365.25 * MICROSECONDS_PER_DAY));

                return DT;
            }

            static inline SCDateTime WEEKS(const int Weeks)
            {
                return DAYS(Weeks * DAYS_PER_WEEK);
            }

            static inline SCDateTime DAYS(const int Days)
            {
                SCDateTime DT;
                DT.GetInternalDateTime() = Days * MICROSECONDS_PER_DAY;

                return DT;
            }

            static inline SCDateTime HOURS(const int Hours)
            {
                SCDateTime DT;
                DT.GetInternalDateTime() = Hours * MICROSECONDS_PER_HOUR;

                return DT;
            }

            static inline SCDateTime MINUTES(const int Minutes)
            {
                SCDateTime DT;
                DT.GetInternalDateTime() = Minutes * MICROSECONDS_PER_MINUTE;

                return DT;
            }

            static inline SCDateTime SECONDS(const int Seconds)
            {
                SCDateTime DT;
                DT.GetInternalDateTime() = Seconds * MICROSECONDS_PER_SECOND;

                return DT;
            }

            static inline SCDateTime SECONDS_Fraction(const double Seconds)
            {
                SCDateTime DT;
                DT.GetInternalDateTime() = static_cast<int64_t>(ROUND_US(Seconds * MICROSECONDS_PER_SECOND));

                return DT;
            }

            static inline SCDateTime MILLISECONDS(const int Milliseconds)
            {
                SCDateTime DT;
                DT.GetInternalDateTime() = Milliseconds * MICROSECONDS_PER_MILLISECOND;

                return DT;
            }

            static inline SCDateTime MICROSECONDS(const int64_t Microseconds)
            {
                SCDateTime DT;
                DT.GetInternalDateTime() = Microseconds;

                return DT;
            }

            static inline SCDateTime NANOSECONDS(const int64_t Nanoseconds)
            {
                SCDateTime DT;
                DT.GetInternalDateTime() = Nanoseconds / 1000;

                return DT;
            }

        protected:

            inline int64_t& GetInternalDateTime()
            {
                return m_dt;
            }

        public:
            inline int64_t GetInternalDateTime() const
            {
                return m_dt;
            }

            inline void SetInternalDateTime(int64_t InternalDateTimeValue)
            {
                m_dt = InternalDateTimeValue;
            }
    };

    typedef SCDateTime SCDateTimeMS;

    /****************************************************************************/
    // c_SCDateTime

    /*==========================================================================*/
    inline SCDateTime::SCDateTime()
        : m_dt(DATETIME_UNSET)
    {
    }

    #ifdef SCDATETIME_SUPPORT_CHRONO
    /*============================================================================
        This constructor supports converting from any std::chrono::duration.
    ----------------------------------------------------------------------------*/
    template<typename t_Rep, typename t_Period>
    inline SCDateTime::SCDateTime
    ( const std::chrono::duration<t_Rep, t_Period> Duration
    )
        : m_dt(std::chrono::duration_cast<std::chrono::microseconds>(Duration).count())
    {
    }

    /*==========================================================================*/
    inline SCDateTime::SCDateTime
    ( const std::chrono::system_clock::time_point TimePoint
    )
        : SCDateTime(TimePoint - SCDATETIME_EPOCH_SYSTEM_CLOCK)
    {
    }
    #endif

    /*==========================================================================*/
    inline SCDateTime::SCDateTime(double DateTime)
        : m_dt(SCDateTimeDoubleToSCDateTime(DateTime))
    {
    }

    /*==========================================================================*/
    inline SCDateTime::SCDateTime(const SCDateTime& DateTime)
        : m_dt(DateTime.m_dt)
    {
    }

    /*==========================================================================*/
    inline SCDateTime::SCDateTime(int Date, int TimeInSeconds)
        : m_dt(COMBINE_DATE_TIME_US(Date, TimeInSeconds))
    {
    }

    /*==========================================================================*/
    inline SCDateTime::SCDateTime(int Year, int Month, int Day, int Hour, int Minute, int Second)
        : m_dt(YMDHMS_DATETIME(Year, Month, Day, Hour, Minute, Second))
    {
    }

    /*==========================================================================*/
    inline SCDateTime::SCDateTime(int Year, int Month, int Day, int Hour, int Minute, int Second, int Millisecond)
        : m_dt(YMDHMS_MS_DATETIME(Year, Month, Day, Hour, Minute, Second, Millisecond))
    {
    }

    /*==========================================================================*/
    inline SCDateTime::SCDateTime(int Hour, int Minute, int Second, int Millisecond)
        : m_dt(DATETIME_UNSET)
    {
        SetTimeHMS_MS(Hour, Minute, Second, Millisecond);
    }

    /*==========================================================================*/
    inline void SCDateTime::ValidateAsCorrectDateTime()
    {
        if (IsUnset())
            return;

        const char UpperByte = (m_dt >> (sizeof(m_dt) - 1) * 8) & 0xFF;

        // Upper byte between 0x3E and 0x41 means positive double values of DateTime between 1899 and 9999 years
        // Upper byte between 0xBD and 0xC1 means negative double values of DateTime between -9999 and 1899 years
        if ((0x3E <= UpperByte && UpperByte <= 0x41) || (-67 <= UpperByte && UpperByte <= -63))
        {
            *this = SCDateTime(*reinterpret_cast<double*>(&m_dt));
            //Due to the fact that microseconds cannot be precisely represented with SCDateTime as a double, we need to remove them.  Otherwise, we will have erroneous microsecond values showing up.
            RoundToNearestMillisecond();
        }
    }

    /*==========================================================================*/
    inline const SCDateTime& SCDateTime::operator = (double dt)
    {
        *this = SCDateTime(dt);
        return *this;
    }

    /*==========================================================================*/
    inline const SCDateTime& SCDateTime::operator = (const SCDateTime& DateTime)
    {
        m_dt = DateTime.m_dt;
        return *this;
    }

    /*==========================================================================*/
    inline const SCDateTime& SCDateTime::operator += (double dt)
    {
        *this += SCDateTime(dt);
        return *this;
    }

    /*==========================================================================*/
    inline const SCDateTime& SCDateTime::operator += (const SCDateTime& DateTime)
    {
        m_dt += DateTime.m_dt;
        return *this;
    }

    /*==========================================================================*/
    inline const SCDateTime& SCDateTime::operator -= (double dt)
    {
        *this -= SCDateTime(dt);
        return *this;
    }

    /*==========================================================================*/
    inline const SCDateTime& SCDateTime::operator -= (const SCDateTime& DateTime)
    {
        m_dt -= DateTime.m_dt;
        return *this;
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator == (int Date) const
    {
        return *this == SCDateTime(Date, 0);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator != (int Date) const
    {
        return *this != SCDateTime(Date, 0);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator < (int Date) const
    {
        return *this < SCDateTime(Date, 0);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator <= (int Date) const
    {
        return *this <= SCDateTime(Date, 0);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator > (int Date) const
    {
        return *this > SCDateTime(Date, 0);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator >= (int Date) const
    {
        return *this >= SCDateTime(Date, 0);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator == (double dt) const
    {
        return *this == SCDateTime(dt);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator != (double dt) const
    {
        return *this != SCDateTime(dt);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator < (double dt) const
    {
        return *this < SCDateTime(dt);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator <= (double dt) const
    {
        return *this <= SCDateTime(dt);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator > (double dt) const
    {
        return *this > SCDateTime(dt);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator >= (double dt) const
    {
        return *this >= SCDateTime(dt);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator == (const SCDateTime& DateTime) const
    {
        return GetInternalDateTime() == DateTime.GetInternalDateTime();
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator != (const SCDateTime& DateTime) const
    {
        return !this->operator ==(DateTime);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator < (const SCDateTime& DateTime) const
    {
        return GetInternalDateTime() < DateTime.GetInternalDateTime();
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator <= (const SCDateTime& DateTime) const
    {
        return !this->operator >(DateTime);
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator > (const SCDateTime& DateTime) const
    {
        return GetInternalDateTime() > DateTime.GetInternalDateTime();
    }

    /*==========================================================================*/
    inline bool SCDateTime::operator >= (const SCDateTime& DateTime) const
    {
        return !this->operator <(DateTime);
    }

    /*==========================================================================*/
    inline void SCDateTime::Clear()
    {
        m_dt = DATETIME_UNSET;
    }

    /*==========================================================================*/
    inline void SCDateTime::SetToMaximum()
    {
        *this = GetMaximumDate();
    }

    /*==========================================================================*/
    inline bool SCDateTime::IsMaximum() const
    {
        return GetInternalDateTime() == GetMaximumDate().GetInternalDateTime();
    }
    /*==========================================================================*/
    inline bool SCDateTime::IsUnset() const
    {
        return m_dt == DATETIME_UNSET;
    }

    /*============================================================================
        Returns true only if the date is not at or before the base date of
        1900-01-01.
    ----------------------------------------------------------------------------*/
    inline bool SCDateTime::IsDateSet() const
    {
        return (GetDate() > 0);
    }
    /*==========================================================================*/
    inline bool SCDateTime::IsTimeAtMidnight() const
    {
        return GetTimeInSeconds() == 0;
    }

    /*==========================================================================*/
    inline void SCDateTime::ClearDate()
    {
        m_dt %= MICROSECONDS_PER_DAY;   // drop date part to keep time part
    }

    /*==========================================================================*/
    inline void SCDateTime::SetAsNegative()
    {
        if (m_dt <= 0)
            return;

        m_dt = -m_dt;
    }

    /*==========================================================================*/
    inline int SCDateTime::GetDate() const
    {
        // Always get the date by rounding only to the nearest microsecond.
        return DATE_PART_MS(GetInternalDateTime());
    }

    /*==========================================================================*/
    inline int SCDateTime::GetDateMS() const
    {
        return DATE_PART_MS(GetInternalDateTime());
    }

    /*============================================================================
        Returns the date and ignores the time.  There is no rounding.  If the
        time is at the last microsecond of the date, then the same date is
        returned.
    ----------------------------------------------------------------------------*/
    inline int SCDateTime::GetDateUS() const
    {
        return static_cast<int>(GetInternalDateTime() / MICROSECONDS_PER_DAY);
    }

    /*==========================================================================*/
    inline SCDateTime SCDateTime::GetDateAsSCDateTime() const
    {
        return SCDateTime(GetDate(), 0);
    }
    /*==========================================================================*/
    inline int SCDateTime::GetDays() const
    {
        return GetDate();
    }

    /*==========================================================================*/
    inline int SCDateTime::GetTime() const
    {
        return TIME_PART_MS(GetInternalDateTime());
    }

    /*==========================================================================*/
    inline int SCDateTime::GetTimeInSeconds() const
    {
        return GetTime();
    }

    /*==========================================================================*/
    inline int SCDateTime::GetTimeInMilliseconds() const
    {
        int64_t TimeInMilliseconds = 0;
        int64_t DateTime = ADJUST_ROUND_MS(m_dt);

        DateTime %= MICROSECONDS_PER_DAY; // remove the date part

        TimeInMilliseconds = DateTime / MICROSECONDS_PER_MILLISECOND;

        if (TimeInMilliseconds >= MILLISECONDS_PER_DAY)
            TimeInMilliseconds = 0;

        return static_cast<int>(TimeInMilliseconds);
    }

    /*==========================================================================*/
    inline int SCDateTime::GetTimeInSecondsWithoutMilliseconds() const
    {
        return TIME_PART_MS(GetInternalDateTime());
    }

    /*==========================================================================*/
    inline SCDateTime SCDateTime::GetTimeAsSCDateTime() const
    {
        SCDateTime DateTime = GetAbsoluteValue();
        DateTime.m_dt %= MICROSECONDS_PER_DAY;  // remove date part
        return DateTime;
    }

    /*==========================================================================*/
    inline SCDateTime SCDateTime::GetTimeAsSCDateTimeMS() const
    {
        return GetTimeAsSCDateTime();
    }

    /*==========================================================================*/
    inline double SCDateTime::GetTimeAsDouble() const
    {
        return GetTimeAsSCDateTime().GetInternalDateTime() / static_cast<double>(MICROSECONDS_PER_DAY);
    }

    /*==========================================================================*/
    inline SCDateTime SCDateTime::GetDateTimeRoundedToSeconds() const
    {
        SCDateTime RoundedDateTime(*this);

        RoundedDateTime.m_dt = ADJUST_ROUND_SECOND(RoundedDateTime.m_dt);
        RoundedDateTime.m_dt -= RoundedDateTime.m_dt % MICROSECONDS_PER_SECOND;

        return RoundedDateTime;
    }

    /*==========================================================================*/
    inline void SCDateTime::GetDateYMD(int& Year, int& Month, int& Day) const
    {
        DATE_TO_YMD(GetDate(), Year, Month, Day);
    }

    /*==========================================================================*/
    inline void SCDateTime::GetTimeHMS(int& Hour, int& Minute, int& Second) const
    {
        TIME_TO_HMS(GetTime(), Hour, Minute, Second);
    }

    /*==========================================================================*/
    inline void SCDateTime::GetDateTimeYMDHMS(int& Year, int& Month, int& Day, int& Hour, int& Minute, int& Second) const
    {
        int Millisecond = 0;
        DATETIME_TO_YMDHMS_MS(m_dt, Year, Month, Day, Hour, Minute, Second, Millisecond);
    }

    /*==========================================================================*/
    inline void SCDateTime::GetDateTimeYMDHMS_MS(int& Year, int& Month, int& Day, int& Hour, int& Minute, int& Second, int& Millisecond) const
    {
        DATETIME_TO_YMDHMS_MS(m_dt, Year, Month, Day, Hour, Minute, Second, Millisecond);
    }

    /*==========================================================================*/
    inline void SCDateTime::GetDateTimeYMDHMS_US(int& Year, int& Month, int& Day, int& Hour, int& Minute, int& Second, int& Microsecond) const
    {
        DATETIME_TO_YMDHMS_MS(m_dt, Year, Month, Day, Hour, Minute, Second, Microsecond, true);
    }

    /*==========================================================================*/
    inline int SCDateTime::GetYear() const
    {
        int Year, Month, Day;
        GetDateYMD(Year, Month, Day);
        return Year;
    }

    /*==========================================================================*/
    inline int SCDateTime::GetMonth() const
    {
        int Year, Month, Day;
        GetDateYMD(Year, Month, Day);
        return Month;
    }

    /*==========================================================================*/
    inline int SCDateTime::GetDay() const
    {
        int Year, Month, Day;
        GetDateYMD(Year, Month, Day);
        return Day;
    }

    /*==========================================================================*/
    inline int SCDateTime::GetHour() const
    {
        return HOUR_OF_TIME(GetTime());
    }

    /*==========================================================================*/
    inline int SCDateTime::GetMinute() const
    {
        return MINUTE_OF_TIME(GetTime());
    }

    /*==========================================================================*/
    inline int SCDateTime::GetSecond() const
    {
        return SECOND_OF_TIME(GetTime());
    }

    /*==========================================================================*/
    inline int SCDateTime::GetMicrosecond() const
    {
        return static_cast<int>(GetInternalDateTime() % MICROSECONDS_PER_MILLISECOND);
    }

    /*==========================================================================*/
    inline int SCDateTime::GetMillisecond() const
    {
        return MS_PART(GetInternalDateTime());
    }

    /*==========================================================================*/
    // Returns DayOfWeekEnum
    inline int SCDateTime::GetDayOfWeek() const
    {
        return DAY_OF_WEEK(GetDate());
    }

    /*==========================================================================*/
    inline int SCDateTime::GetDayOfWeekMondayBased() const
    {
        return DAY_OF_WEEK_MONDAY_BASED(GetDate());
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetToPriorSundayForDateTime(const SCDateTime& OriginalDateTime)
    {
        m_dt = OriginalDateTime.GetInternalDateTime();
        SetTime(0);
        SubtractDays(OriginalDateTime.GetDayOfWeek());
        return *this;
    }

    /*==========================================================================*/
    inline std::int64_t SCDateTime::AsMicrosecondsSinceBaseDate() const
    {
        return m_dt;
    }

    /*==========================================================================*/
    inline std::int64_t SCDateTime::AsMillisecondsSinceBaseDate() const
    {
        return m_dt / MICROSECONDS_PER_MILLISECOND;
    }

    /*==========================================================================*/
    inline std::int64_t SCDateTime::AsSecondsSinceBaseDate() const
    {
        return m_dt / MICROSECONDS_PER_SECOND;
    }

    /*==========================================================================*/
    inline std::int64_t SCDateTime::GetMillisecondsSinceBaseDate() const
    {
        return static_cast<int64_t>(ADJUST(GetFloatMillisecondsSinceBaseDate()));
    }

    /*==========================================================================*/
    inline std::int64_t SCDateTime::GetSecondsSinceBaseDate() const
    {
        return static_cast<int64_t>(ADJUST(GetFloatSecondsSinceBaseDate()));
    }

    /*==========================================================================*/
    inline int SCDateTime::GetMinutesSinceBaseDate() const
    {
        return static_cast<int>(ADJUST(GetFloatMinutesSinceBaseDate()));
    }

    /*==========================================================================*/
    inline int SCDateTime::GetHoursSinceBaseDate() const
    {
        return static_cast<int>(ADJUST(GetFloatHoursSinceBaseDate()));
    }

    /*==========================================================================*/
    inline int SCDateTime::GetDaysSinceBaseDate() const
    {
        return static_cast<int>(ADJUST(GetFloatDaysSinceBaseDate()));
    }

    /*==========================================================================*/
    inline int SCDateTime::GetWeeksSinceBaseDate() const
    {
        return static_cast<int>(ADJUST(GetFloatWeeksSinceBaseDate()));
    }

    /*==========================================================================*/
    inline int SCDateTime::GetYearsSinceBaseDate() const
    {
        return static_cast<int>(ADJUST(GetFloatYearsSinceBaseDate()));
    }

    /*==========================================================================*/
    inline double SCDateTime::GetFloatMillisecondsSinceBaseDate() const
    {
        return static_cast<double>(GetInternalDateTime()) / MICROSECONDS_PER_MILLISECOND;
    }

    /*==========================================================================*/
    inline double SCDateTime::GetFloatSecondsSinceBaseDate() const
    {
        return static_cast<double>(GetInternalDateTime()) / MICROSECONDS_PER_SECOND;
    }

    /*==========================================================================*/
    inline double SCDateTime::GetFloatMinutesSinceBaseDate() const
    {
        return static_cast<double>(GetInternalDateTime()) / MICROSECONDS_PER_MINUTE;
    }

    /*==========================================================================*/
    inline double SCDateTime::GetFloatHoursSinceBaseDate() const
    {
        return static_cast<double>(GetInternalDateTime()) / MICROSECONDS_PER_HOUR;
    }

    /*==========================================================================*/
    inline double SCDateTime::GetFloatDaysSinceBaseDate() const
    {
        return static_cast<double>(GetInternalDateTime()) / MICROSECONDS_PER_DAY;
    }

    /*==========================================================================*/
    inline double SCDateTime::GetFloatWeeksSinceBaseDate() const
    {
        return static_cast<double>(GetInternalDateTime()) / MICROSECONDS_PER_DAY / DAYS_PER_WEEK;
    }

    /*==========================================================================*/
    inline double SCDateTime::GetFloatYearsSinceBaseDate() const
    {
        return static_cast<double>(GetInternalDateTime()) / MICROSECONDS_PER_DAY / DAYS_IN_YEAR;
    }

    /*==========================================================================*/
    inline int SCDateTime::GetDateDifferenceInDays(const SCDateTime& DateTime) const
    {
        return GetDate() - DateTime.GetDate();
    }

    /*==========================================================================*/
    inline bool SCDateTime::IsNegative() const
    {
        return m_dt < 0;
    }

    /*==========================================================================*/
    inline SCDateTime SCDateTime::GetAbsoluteValue() const
    {
        SCDateTime DateTime = *this;
        DateTime.m_dt = abs(DateTime.m_dt);
        return DateTime;
    }

    /*==========================================================================*/
    inline double SCDateTime::GetAsDouble() const
    {
        return SCUNIXTimeToSCDateTime(m_dt);
    }

    /*==========================================================================*/
    // When UseSaturdayData is true, then Saturday data is not considered part of the weekend.
    inline bool SCDateTime::IsWeekend(const bool UseSaturdayData) const
    {
        const int DayOfWeek = GetDayOfWeek();

        return ((!UseSaturdayData && DayOfWeek == SATURDAY) || DayOfWeek == SUNDAY);
    }

    /*==========================================================================*/
    inline bool SCDateTime::IsSaturday() const
    {
        return (GetDayOfWeek() == SATURDAY);
    }

    /*==========================================================================*/
    inline bool SCDateTime::IsSunday() const
    {
        return (GetDayOfWeek() == SUNDAY);
    }

    /*==========================================================================*/
    inline bool SCDateTime::IsMonday() const
    {
        return (GetDayOfWeek() == MONDAY);
    }

    /*==========================================================================*/
    inline bool SCDateTime::IsGivenTimeWithinGivenTimeRange(const SCDateTime& DateTimeToCompareTo, const SCDateTime& TimeWithin)
    {
        return abs(GetInternalDateTime() - DateTimeToCompareTo.GetInternalDateTime()) <= TimeWithin.GetInternalDateTime();
    }

    /*==========================================================================*/
    inline int SCDateTime::GetBusinessDaysBetweenDates(const SCDateTime& FutureDate) const
    {
        if (*this >= FutureDate)
            return 0;

        int NumberOfBusinessDays = 0;
        const int StartDate = GetDate();
        const int EndDate = FutureDate.GetDate();

        for (int DateValue = StartDate; DateValue < EndDate; DateValue++)
        {
            const SCDateTime BusinessDayCheck(DateValue, 0);
            if (BusinessDayCheck.IsWeekend())
                continue;

            NumberOfBusinessDays++;
        }

        return NumberOfBusinessDays;
    }

    /*==========================================================================*/
    inline bool SCDateTime::IsSameDate(const SCDateTime& DateTime) const
    {
        return GetDate() == DateTime.GetDate();
    }

    /*============================================================================
        Returns true only if the given DateTime is at exactly the same date and
        hour as this SCDateTime.  Any minutes, seconds, or smaller components are
        excluded from the comparison.
    ----------------------------------------------------------------------------*/
    inline bool SCDateTime::IsSameTimeToHour(const SCDateTime& DateTime) const
    {
        const int64_t ThisHour = GetInternalDateTime() / MICROSECONDS_PER_HOUR;
        const int64_t ThatHour = DateTime.GetInternalDateTime() / MICROSECONDS_PER_HOUR;

        return (ThatHour == ThisHour);
    }

    /*============================================================================
        Returns true only if the given DateTime is at exactly the same date, hour,
        and minute as this SCDateTime.  Any seconds, milliseconds, or smaller
        components are excluded from the comparison.
    ----------------------------------------------------------------------------*/
    inline bool SCDateTime::IsSameTimeToMinute(const SCDateTime& DateTime) const
    {
        const int64_t ThisMinute = GetInternalDateTime() / MICROSECONDS_PER_MINUTE;
        const int64_t ThatMinute = DateTime.GetInternalDateTime() / MICROSECONDS_PER_MINUTE;

        return (ThatMinute == ThisMinute);
    }

    /*============================================================================
        Returns true only if the given DateTime is at exactly the same date, hour,
        minute, and second as this SCDateTime.  Any milliseconds, or smaller
        components are excluded from the comparison.
    ----------------------------------------------------------------------------*/
    inline bool SCDateTime::IsSameTimeToSecond(const SCDateTime& DateTime) const
    {
        const int64_t ThisSecond = GetInternalDateTime() / MICROSECONDS_PER_SECOND;
        const int64_t ThatSecond = DateTime.GetInternalDateTime() / MICROSECONDS_PER_SECOND;

        return (ThatSecond == ThisSecond);
    }

    /*============================================================================
        Returns true only if the given DateTime is at exactly the same date, hour,
        minute, second, and millisecond as this SCDateTime.  Any smaller
        components are excluded from the comparison.
    ----------------------------------------------------------------------------*/
    inline bool SCDateTime::IsSameTimeToMillisecond(const SCDateTime& DateTime) const
    {
        const int64_t ThisMillisecond = GetInternalDateTime() / MICROSECONDS_PER_MILLISECOND;
        const int64_t ThatMillisecond = DateTime.GetInternalDateTime() / MICROSECONDS_PER_MILLISECOND;

        return (ThatMillisecond == ThisMillisecond);
    }

    /*==========================================================================*/
    inline void SCDateTime::RoundDateTimeDownToMinute()
    {
        m_dt -= m_dt % MICROSECONDS_PER_MINUTE;
    }

    /*==========================================================================*/
    inline void SCDateTime::RoundDateTimeDownToSecond()
    {
        m_dt -= m_dt % MICROSECONDS_PER_SECOND;
    }

    /*==========================================================================*/
    inline void SCDateTime::RoundDateTimeDownToMillisecond()
    {
        m_dt -= m_dt % MICROSECONDS_PER_MILLISECOND;
    }

    /*==========================================================================*/
    inline void SCDateTime::RoundToNearestSecond()
    {
        m_dt = ADJUST_ROUND_SECOND(GetInternalDateTime());
        m_dt -= m_dt % MICROSECONDS_PER_SECOND;
    }

    /*==========================================================================*/
    inline void SCDateTime::RoundToNearestMillisecond()
    {
        m_dt = ADJUST_ROUND_MS(GetInternalDateTime());
        m_dt -= m_dt % MICROSECONDS_PER_MILLISECOND;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetDateTimeAsDouble(double DateTime)
    {
        m_dt = SCDateTimeDoubleToSCDateTime(DateTime);
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetDateTime(int Date, int Time)
    {
        m_dt = Date * MICROSECONDS_PER_DAY + Time * MICROSECONDS_PER_SECOND;
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetDate(int Date)
    {
        m_dt %= MICROSECONDS_PER_DAY;   // drop date part to keep time part
        m_dt += Date * MICROSECONDS_PER_DAY;    // add date part
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetDate(const SCDateTime& Date)
    {
        m_dt %= MICROSECONDS_PER_DAY;   // drop date part to keep time part
        m_dt += Date.m_dt - Date.m_dt % MICROSECONDS_PER_DAY;   // add date part

        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetTime(int Time)
    {
        m_dt += Time * MICROSECONDS_PER_SECOND - m_dt % MICROSECONDS_PER_DAY;
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetTimeFromSCDateTime(const SCDateTime& Time)
    {
        m_dt += Time.m_dt % MICROSECONDS_PER_DAY - m_dt % MICROSECONDS_PER_DAY;
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetDateYMD(int Year, int Month, int Day)
    {
        return SetDate(YMD_DATE(Year, Month, Day));
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetTimeHMS(int Hour, int Minute, int Second)
    {
        return SetTime(HMS_TIME(Hour, Minute, Second));
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetTimeHMS_MS(int Hour, int Minute, int Second, int Millisecond)
    {
        SetTimeHMS(Hour, Minute, Second);
        m_dt += (Millisecond * MICROSECONDS_PER_MILLISECOND);
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetTimeHMS_US(int Hour, int Minute, int Second, int Microsecond)
    {
        SetTimeHMS(Hour, Minute, Second);
        AddMicroseconds(Microsecond);

        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetDateTimeYMDHMS(int Year, int Month, int Day, int Hour, int Minute, int Second)
    {
        m_dt = YMDHMS_DATETIME(Year, Month, Day, Hour, Minute, Second);
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetDateTimeYMDHMS_MS(int Year, int Month, int Day, int Hour, int Minute, int Second, int Millisecond)
    {
        m_dt = YMDHMS_MS_DATETIME(Year, Month, Day, Hour, Minute, Second, Millisecond);
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetDateTimeYMDHMS_US(int Year, int Month, int Day, int Hour, int Minute, int Second, int Microsecond)
    {
        m_dt = YMDHMS_DATETIME(Year, Month, Day, Hour, Minute, Second);
        AddMicroseconds(Microsecond);

        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetFromUNIXTimeInSeconds(time_t UNIXTime)
    {
        m_dt = UNIXTimeToSCDateTimeUNIX(UNIXTime);
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetUNIXTimeWithMilliseconds(double UNIXTimeWithMilliseconds)
    {
        m_dt = UNIXTimeWithMillisecondsToSCDateTimeUNIX(UNIXTimeWithMilliseconds);
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::AddMicroseconds(int64_t Microseconds)
    {
        m_dt += Microseconds;

        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SubtractMicroseconds(int Microseconds)
    {
        m_dt -= Microseconds;

        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::AddMilliseconds(int Milliseconds)
    {
        m_dt += Milliseconds * MICROSECONDS_PER_MILLISECOND;
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SubtractMilliseconds(int Milliseconds)
    {
        m_dt -= Milliseconds * MICROSECONDS_PER_MILLISECOND;
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::AddSeconds(int Seconds)
    {
        m_dt += Seconds * MICROSECONDS_PER_SECOND;
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SubtractSeconds(int Seconds)
    {
        m_dt -= Seconds * MICROSECONDS_PER_SECOND;
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::AddMinutes(int Minutes)
    {
        m_dt += Minutes * MICROSECONDS_PER_MINUTE;

        return *this;
    }
    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SubtractMinutes(int Minutes)
    {
        m_dt -= Minutes * MICROSECONDS_PER_MINUTE;
        return *this;
    }
    /*==========================================================================*/
    inline SCDateTime& SCDateTime::AddHours(int Hours)
    {
        m_dt += Hours * MICROSECONDS_PER_HOUR;
        return *this;
    }
    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SubtractHours(int Hours)
    {
        m_dt -= Hours * MICROSECONDS_PER_HOUR;
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::AddDays(int Days)
    {
        m_dt += Days * MICROSECONDS_PER_DAY;
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SubtractDays(int Days)
    {
        m_dt -= Days * MICROSECONDS_PER_DAY;
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::AddYears(int Years)
    {
        int CurrentYear = 0;
        int CurrentMonth = 0;
        int CurrentDay = 0;
        int CurrentHour = 0;
        int CurrentMinute = 0;
        int CurrentSecond = 0;
        int CurrentMicrosecond = 0;

        GetDateTimeYMDHMS_US(CurrentYear, CurrentMonth, CurrentDay, CurrentHour, CurrentMinute, CurrentSecond, CurrentMicrosecond);

        CurrentYear += Years;

        SetDateTimeYMDHMS_US(CurrentYear, CurrentMonth, CurrentDay, CurrentHour, CurrentMinute, CurrentSecond, CurrentMicrosecond);

        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SubtractYears(int Years)
    {
        return AddYears(-Years);
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::SetDayToLastDayInMonth()
    {
        int Year, Month, Day;
        GetDateYMD(Year, Month, Day);

        Day = GetDaysInMonth(Month, Year);

        SetDateYMD(Year, Month, Day);
        return *this;
    }

    /*==========================================================================*/
    inline SCDateTime& SCDateTime::MultiplyTime(float Multiplier)
    {
        m_dt = static_cast<int64_t>(ADJUST(m_dt * static_cast<double>(Multiplier)));
        return *this;
    }

    /*==========================================================================*/
    inline time_t SCDateTime::ToUNIXTime() const
    {
        if (IsUnset())
            return 0;

        return (time_t)ADJUST(ToFloatUNIXTime());
    }

    /*==========================================================================*/
    inline double SCDateTime::ToFloatUNIXTime() const
    {
        if (IsUnset())
            return 0.0;

        return (m_dt - SCDATETIME_UNIX_EPOCH_DATE * MICROSECONDS_PER_DAY) / static_cast<double>(MICROSECONDS_PER_SECOND);
    }

    /*==========================================================================*/
    inline int64_t SCDateTime::ToUNIXTimeInMilliseconds() const
    {
        if (IsUnset())
            return 0;

        return static_cast<int64_t>(ADJUST((m_dt - SCDATETIME_UNIX_EPOCH_DATE * MICROSECONDS_PER_DAY) / static_cast<double>(MICROSECONDS_PER_MILLISECOND)));
    }

    /*==========================================================================*/
    inline int64_t SCDateTime::ToUNIXTimeInMicroseconds() const
    {
        if (IsUnset())
            return DATETIME_UNSET;

        return m_dt - SCDATETIME_UNIX_EPOCH_DATE * MICROSECONDS_PER_DAY;
    }

    /*==========================================================================*/
    inline double SCDateTime::ToUNIXTimeWithMillisecondsFraction() const
    {
        if (IsUnset())
            return DATETIME_UNSET_DOUBLE;

        return ToUNIXTimeInMilliseconds() / static_cast<double>(MILLISECONDS_PER_SECOND);
    }

    /*==========================================================================*/
    inline void SCDateTime::SetFromUNIXTimeMilliseconds(int64_t UNIXTimeMilliseconds)
    {
        if (IS_UNSET(UNIXTimeMilliseconds))
            m_dt = DATETIME_UNSET;
        else
            m_dt = UNIXTimeMilliseconds * MICROSECONDS_PER_MILLISECOND + SCDATETIME_UNIX_EPOCH_DATE * MICROSECONDS_PER_DAY;
    }

    /*==========================================================================*/
    inline void SCDateTime::SetFromUNIXTimeMicroseconds(int64_t UNIXTimeMicroseconds)
    {
        if (IS_UNSET(UNIXTimeMicroseconds))
            m_dt = DATETIME_UNSET;
        else
            m_dt = UNIXTimeMicroseconds + SCDATETIME_UNIX_EPOCH_DATE * MICROSECONDS_PER_DAY;
    }

    /*==========================================================================*/
    inline void SCDateTime::SetFromUnixTimeInDays(const int Days)
    {
        if (Days != 0)
            m_dt = Days * MICROSECONDS_PER_DAY + SCDATETIME_UNIX_EPOCH_DATE * MICROSECONDS_PER_DAY;
        else
            m_dt = 0;
    }
    /*==========================================================================*/
    inline void SCDateTime::SetFromUNIXTimeMillisecondsFraction(double UNIXTimeMillisecondsFraction)
    {
        if (UNIXTimeMillisecondsFraction == 0)
        {
            m_dt = DATETIME_UNSET;
            return;
        }

        m_dt = static_cast<int64_t>(ADJUST(UNIXTimeMillisecondsFraction * MILLISECONDS_PER_SECOND)) * MICROSECONDS_PER_MILLISECOND + SCDATETIME_UNIX_EPOCH_DATE * MICROSECONDS_PER_DAY;
    }

    /*==========================================================================*/
    //Static
    inline SCDateTime SCDateTime::GetMinimumDate()
    {
        return -0x7FFFFFFFFFFFFFFF / MICROSECONDS_PER_DAY;
    }

    /*==========================================================================*/
    //Static
    inline SCDateTime SCDateTime::GetMaximumDate()
    {
        return 0x7FFFFFFFFFFFFFFF / MICROSECONDS_PER_DAY;
    }

    /*==========================================================================*/
    inline std::int64_t SCDateTimeToUNIXTimeRemoveMilliseconds(SCDateTime DateTime)
    {
        DateTime.RoundDateTimeDownToSecond();
        return DateTime.ToUNIXTimeInMicroseconds() / MICROSECONDS_PER_SECOND;
    }

    /*==========================================================================*/
    inline SCDateTime operator + (const SCDateTime& DateTimeA, const SCDateTime& DateTimeB)
    {
        SCDateTime Result = DateTimeA;
        Result += DateTimeB;

        return Result;
    }

    /*==========================================================================*/
    inline SCDateTime operator - (const SCDateTime& DateTimeA, const SCDateTime& DateTimeB)
    {
        SCDateTime Result = DateTimeA;
        Result -= DateTimeB;

        return Result;
    }

    /****************************************************************************/
    // Integer comparison operators

    /*==========================================================================*/
    inline bool operator == (int IntDateTime, const SCDateTime& DateTime)
    {
        return SCDateTime(IntDateTime, 0) == DateTime;
    }

    /*==========================================================================*/
    inline bool operator != (int IntDateTime, const SCDateTime& DateTime)
    {
        return SCDateTime(IntDateTime, 0) != DateTime;
    }

    /*==========================================================================*/
    inline bool operator < (int IntDateTime, const SCDateTime& DateTime)
    {
        return SCDateTime(IntDateTime, 0) < DateTime;
    }

    /*==========================================================================*/
    inline bool operator <= (int IntDateTime, const SCDateTime& DateTime)
    {
        return SCDateTime(IntDateTime, 0) <= DateTime;
    }

    /*==========================================================================*/
    inline bool operator > (int IntDateTime, const SCDateTime& DateTime)
    {
        return SCDateTime(IntDateTime, 0) > DateTime;
    }

    /*==========================================================================*/
    inline bool operator >= (int IntDateTime, const SCDateTime& DateTime)
    {
        return SCDateTime(IntDateTime, 0) >= DateTime;
    }

    /****************************************************************************/
    // Double comparison operators

    /*==========================================================================*/
    inline bool operator == (double dt, const SCDateTime& DateTime)
    {
        return SCDateTime(dt) == DateTime;
    }

    /*==========================================================================*/
    inline bool operator != (double dt, const SCDateTime& DateTime)
    {
        return SCDateTime(dt) != DateTime;
    }

    /*==========================================================================*/
    inline bool operator < (double dt, const SCDateTime& DateTime)
    {
        return SCDateTime(dt) < DateTime;
    }

    /*==========================================================================*/
    inline bool operator <= (double dt, const SCDateTime& DateTime)
    {
        return SCDateTime(dt) <= DateTime;
    }

    /*==========================================================================*/
    inline bool operator > (double dt, const SCDateTime& DateTime)
    {
        return SCDateTime(dt) > DateTime;
    }

    /*==========================================================================*/
    inline bool operator >= (double dt, const SCDateTime& DateTime)
    {
        return SCDateTime(dt) >= DateTime;
    }

    /*==========================================================================*/
    inline SCDateTime GetNextMillisecondForSameSecondDateTime(const SCDateTime& PreviousDateTime, SCDateTime NextDateTime)
    {
        //Purpose: We need to make a new record timestamp unique by using milliseconds.
        const SCDateTime PreviousDateTimeCopy(PreviousDateTime);

        if (PreviousDateTimeCopy.IsSameTimeToSecond(NextDateTime)) //Timestamp to the second is the same.
        {
            const int Milliseconds = PreviousDateTimeCopy.GetMillisecond();

            if (Milliseconds >= MILLISECONDS_PER_SECOND - 1)
                NextDateTime = PreviousDateTimeCopy;
            else
                NextDateTime = PreviousDateTimeCopy + SCDateTime::MILLISECONDS(1);
        }

        return NextDateTime;
    }

    /*==========================================================================*/
    inline SCDateTime GetNextMicrosecondForSameMillisecondDateTime_AllowSkippedMicroseconds(const SCDateTime PreviousDateTime, SCDateTime NextDateTime)
    {
        //Purpose: We need to make a new record timestamp unique by using microseconds.

        if (PreviousDateTime.IsSameTimeToMillisecond(NextDateTime) //Timestamp to the millisecond is the same.
            && NextDateTime <= PreviousDateTime)// Skip this if NextDateTime is greater than PreviousDateTime
        {
            const int Microseconds = PreviousDateTime.GetMicrosecond();

            if (Microseconds >= MICROSECONDS_PER_MILLISECOND - 1)
                NextDateTime = PreviousDateTime;
            else
                NextDateTime = PreviousDateTime + SCDateTime::MICROSECONDS(1);
        }

        return NextDateTime;
    }

    /*==========================================================================*/
    //  Purpose: We need to make a new record timestamp unique by using microseconds.
    inline SCDateTime GetNextMicrosecondForSameMillisecondDateTime(const SCDateTime& PreviousDateTime, SCDateTime NextDateTime)
    {
        if (PreviousDateTime.IsSameTimeToMillisecond(NextDateTime)) //Timestamp to the millisecond is the same.
        {
            NextDateTime = PreviousDateTime;

            const int Microseconds = PreviousDateTime.GetMicrosecond();
            if (Microseconds < MICROSECONDS_PER_MILLISECOND - 1)
                NextDateTime.AddMicroseconds(1);
        }

        return NextDateTime;
    }

    /*****************************************************************************
    // SCDateTimeSpan

    The SCDateTimeSpan object wraps a int64_t value
    representing a time span between two SCDateTime objects.

    ----------------------------------------------------------------------------*/
    class SCDateTimeSpan
    {
    public:
        SCDateTime m_TimeSpan;

        SCDateTimeSpan SetTimeSpan(const SCDateTime& FirstDateTime, const SCDateTime& SecondDateTime)
        {
            m_TimeSpan = FirstDateTime;
            m_TimeSpan -= SecondDateTime;

            return *this;
        }

        SCDateTime GetTimeSpan() const
        {
            return m_TimeSpan;
        }

        SCDateTimeSpan& operator = (double TimeSpan)
        {
            m_TimeSpan = TimeSpan;

            return *this;
        }
    };

    #if SHOW_WARNING_IF_DEPRECATED
    // Re enable warning outside of the SCDateTime.h file because we want to see warning `deprecated`
    # pragma warning(pop)
    #endif