Click here to Skip to main content
15,894,896 members
Articles / Desktop Programming / Win32

Stopwatch

Rate me:
Please Sign up or sign in to vote.
4.97/5 (29 votes)
3 Jan 2015CPOL6 min read 66.3K   1.5K   43  
Benchmark C++ std::vector vs raw arrays, move assignable/constructable & copy assignable/constructable
#include "stdafx.h"

#include "hwindatetime.h"
#include "hwinenvironment.h"
#include "hwinexception.h"
#include "hwincalendar.h"
#include "hwinresources.h"
#include "hwinBinaryReader.h"
#include "hwinBinaryWriter.h"


namespace harlinn
{
    namespace windows
    {
        const double TimeBase::MillisecondsPerTick = 1.0 / TimeBase::TicksPerMillisecond;
        const double TimeBase::SecondsPerTick = 1.0 / TimeBase::TicksPerSecond;
        const double TimeBase::MinutesPerTick = 1.0 / TimeBase::TicksPerMinute;
        const double TimeBase::HoursPerTick = 1.0 / TimeBase::TicksPerHour;
        const double TimeBase::DaysPerTick = 1.0 / TimeBase::TicksPerDay;

        const double TimeBase::OADateMinAsDouble = -657435.0;
        const double TimeBase::OADateMaxAsDouble = 2958466.0;

        const int TimeBase::DaysToMonth365[13] =
        {
            0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
        };
        const int TimeBase::DaysToMonth366[13] =
        {
            0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
        };



        // ----------------------------------------------------------------------
        // TimeSpan
        // ----------------------------------------------------------------------
        const TimeSpan TimeSpan::Zero( 0 );



        const TimeSpan TimeSpan::MaxValue( MaxInt64 );
        const TimeSpan TimeSpan::MinValue( MinInt64 );

        long long TimeSpan::TimeToTicks( int theDays, int theHours, int theMinutes, int theSeconds, int theMilliseconds )
        {
            long long milliSeconds = ( ( long long )theDays * 3600 * 24 +
                                       ( long long )theHours * 3600 +
                                       ( long long )theMinutes * 60 + theSeconds ) * 1000 +
                                       theMilliseconds;

            if ( milliSeconds > MaxMilliSeconds || milliSeconds < MinMilliSeconds )
            {
                throw ArgumentOutOfRangeException( "", Environment::GetResourceString( ApplicationResources::OVERFLOW_TIMESPANTOOLONG ) );
            }
            long long result = milliSeconds * TicksPerMillisecond;
            return result;
        }

        TimeSpan TimeSpan::Add( const TimeSpan& theOther ) const
        {
            long long result = ticks + theOther.ticks;
            if ( ( ticks >> 63 == theOther.ticks >> 63 ) && ( ticks >> 63 != result >> 63 ) )
            {
                throw OverflowException( Environment::GetResourceString( ApplicationResources::OVERFLOW_TIMESPANTOOLONG ) );
            }
            return TimeSpan( result );
        }

        TimeSpan TimeSpan::Interval( double theValue, int theScale )
        {
            if ( _isnan( theValue ) )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARG_CANNOTBENAN ) );
            }
            double milliSeconds = theValue * theScale;
            milliSeconds = milliSeconds + ( theValue >= 0 ? 0.5 : -0.5 );

            if ( ( milliSeconds > MAXINT64 / TicksPerMillisecond ) || ( milliSeconds < MININT64 / TicksPerMillisecond ) )
            {
                throw OverflowException( Environment::GetResourceString( ApplicationResources::OVERFLOW_NEGATETWOSCOMPNUM ) );
            }
            return TimeSpan( ( long long )milliSeconds * TicksPerMillisecond );
        }


        TimeSpan TimeSpan::Duration( ) const
        {
            if ( ticks == MinValue.ticks )
            {
                throw OverflowException( Environment::GetResourceString( ApplicationResources::OVERFLOW_DURATION ) );
            }
            return TimeSpan( ticks >= 0 ? ticks : -ticks );
        }

        TimeSpan TimeSpan::Negate( ) const
        {
            if ( ticks == MinValue.ticks )
            {
                throw OverflowException( Environment::GetResourceString( ApplicationResources::OVERFLOW_NEGATETWOSCOMPNUM ) );
            }
            return TimeSpan( -ticks );
        }

        TimeSpan TimeSpan::Subtract( const TimeSpan& theOther ) const
        {
            long long result = ticks - theOther.ticks;
            if ( ( ticks >> 63 != theOther.ticks >> 63 ) && ( ticks >> 63 != result >> 63 ) )
            {
                throw OverflowException( Environment::GetResourceString( ApplicationResources::OVERFLOW_TIMESPANTOOLONG ) );
            }
            return TimeSpan( result );
        }

        WideString TimeSpan::ToString( ) const
        {
            wchar_t buffer[128];
            size_t length = GetDurationFormat( LOCALE_USER_DEFAULT, 0, nullptr, ticks, nullptr, buffer, 128 );
            if ( length == 0 )
            {
                ThrowLastOSError( );
            }
            return WideString( buffer, length );
        }

        double TimeSpan::TotalDays( ) const
        {
            return ( double( ticks ) ) / double( TicksPerDay );
        }

        double TimeSpan::TotalHours( ) const
        {
            return ( double( ticks ) ) / double( TicksPerHour );
        }

        double TimeSpan::TotalMilliseconds( ) const
        {
            double result = ( ( double )ticks ) / double( TicksPerMillisecond );
            if ( result > MaxMilliSeconds )
            {
                return ( double )MaxMilliSeconds;
            }

            if ( result < MinMilliSeconds )
            {
                return ( double )MinMilliSeconds;
            }

            return result;
        }

        double TimeSpan::TotalMinutes( ) const
        {
            return ( double )ticks / double( TicksPerMinute );
        }

        double TimeSpan::TotalSeconds( ) const
        {
            return ( double )ticks / double( TicksPerSecond );
        }


        // ----------------------------------------------------------------------
        // DateTime
        // ----------------------------------------------------------------------



        const DateTime DateTime::MinValue( MinTicks, DateTimeKind::Unspecified );
        const DateTime DateTime::MaxValue( MaxTicks, DateTimeKind::Unspecified );


        long long DateTime::ToLocalTicks( long long ticksInUtc )
        {
            auto fileTime = ticksInUtc - FileTimeOffset;
            long long localFileTime = 0;
            FileTimeToLocalFileTime( ( FILETIME* )&fileTime, ( FILETIME* )&localFileTime );
            return localFileTime + FileTimeOffset;
        }
        long long DateTime::ToUniversalTicks( long long ticksInLocalTime )
        {
            auto localFileTime = ticksInLocalTime - FileTimeOffset;
            long long fileTime = 0;
            LocalFileTimeToFileTime( ( FILETIME* )&localFileTime, ( FILETIME* )&fileTime );
            return fileTime + FileTimeOffset;
        }

        DateTime::DateTime( long long ticks )
        {
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                throw ArgumentOutOfRangeException( "ticks", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_DATETIMEBADTICKS ) );
            }
            data = ( unsigned long long )ticks;
        }

        DateTime::DateTime( unsigned long long theDateData )
            : data( theDateData )
        {

        }

        DateTime::DateTime( double days )
        {
            data = ( unsigned long long )DoubleDateToTicks( days );
        }


        DateTime::DateTime( long long ticks, DateTimeKind kind )
        {
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                throw ArgumentOutOfRangeException( "ticks", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_DATETIMEBADTICKS ) );
            }
            if ( kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARGUMENT_INVALIDDATETIMEKIND ), "kind" );
            }

            data = ( ( unsigned long long )ticks | ( ( unsigned long long )kind << KindShift ) );
        }


        long long DateTime::ToTicks( int year, int month, int day, const globalization::Calendar& calendar )
        {
            return ToTicks( year, month, day, 0, 0, 0, 0, calendar );
        }

        long long DateTime::ToTicks( int year, int month, int day, int hour, int minute, int second, int millisecond, const globalization::Calendar& calendar )
        {
            if ( millisecond < 0 || millisecond >= MillisPerSecond )
            {
                throw ArgumentOutOfRangeException( "millisecond", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1 ) );
            }
            long long ticks = calendar.ToDateTime( year, month, day, hour, minute, second, 0 ).data & TicksMask;
            ticks += millisecond * TicksPerMillisecond;
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARG_DATETIMERANGE ) );
            }
            return ticks;
        }

        long long DateTime::ToTicks( int year, int month, int day, int hour, int minute, int second, int millisecond )
        {
            if ( millisecond < 0 || millisecond >= MillisPerSecond )
            {
                throw ArgumentOutOfRangeException( "millisecond", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1 ) );
            }
            long long ticks = DateToTicks( year, month, day ) + TimeToTicks( hour, minute, second );
            ticks += millisecond * TicksPerMillisecond;
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARG_DATETIMERANGE ) );
            }
            return ticks;
        }


        long long DateTime::JulianDateToTicks( int year, int month, int day )
        {
            const int* days = ( year % 4 == 0 ) ? DaysToMonth366 : DaysToMonth365;
            int y = year - 1;
            int n = y * 365 + y / 4 + days[month - 1] + day - 1;

            // Gregorian 1/1/0001 is Julian 1/3/0001 and n * TicksPerDay 
            // is the ticks in JulianCalendar. So by subtracting two days in 
            // the following we convert the ticks in JulianCalendar 
            // to ticks in Gregorian calendar.
            __int64 result = __int64( n - 2 ) * TicksPerDay;

            return result;

        }

        long long DateTime::DateToTicks( int year, int month, int day )
        {
            if ( year >= 1 && year <= 9999 && month >= 1 && month <= 12 )
            {
                const int* days = IsLeapYear( year ) ? DaysToMonth366 : DaysToMonth365;
                if ( day >= 1 && day <= days[month] - days[month - 1] )
                {
                    int y = year - 1;
                    int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
                    return n * TicksPerDay;
                }
            }
            throw ArgumentOutOfRangeException( static_cast<CharType*>( nullptr ), Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_BADYEARMONTHDAY ) );
        }

        long long DateTime::SystemTimeToTicks( const SYSTEMTIME& systemTime )
        {
            if ( systemTime.wMilliseconds >= MillisPerSecond )
            {
                throw ArgumentOutOfRangeException( HWIN_TEXT( "systemTime.wMilliseconds" ), Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1 ) );
            }
            unsigned long long ticks = DateToTicks( systemTime.wYear, systemTime.wMonth, systemTime.wDay ) + TimeToTicks( systemTime.wHour, systemTime.wMinute, systemTime.wSecond );
            ticks += systemTime.wMilliseconds * TicksPerMillisecond;
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                throw new ArgumentException( Environment::GetResourceString( ApplicationResources::ARG_DATETIMERANGE ) );
            }
            return ticks;
        }

        long long DateTime::TimeToTicks( int hour, int minute, int second )
        {
            if ( hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60 )
            {
                return TimeSpan::TimeToTicks( 0, hour, minute, second );
            }
            throw ArgumentOutOfRangeException( static_cast<CharType*>( nullptr ), Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_BADHOURMINUTESECOND ) );
        }


        DateTime::DateTime( int year, int month, int day )
        {
            data = ( unsigned long long ) DateToTicks( year, month, day );
        }

        DateTime::DateTime( int year, int month, int day, const globalization::Calendar& calendar )
            : data( ToTicks( year, month, day, 0, 0, 0, 0, calendar ) )
        {
        }


        DateTime::DateTime( int year, int month, int day, int hour, int minute, int second )
            : data( DateToTicks( year, month, day ) + TimeToTicks( hour, minute, second ) )
        {
        }

        DateTime::DateTime( int year, int month, int day, int hour, int minute, int second, DateTimeKind kind )
        {
            if ( kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARGUMENT_INVALIDDATETIMEKIND ), "kind" );
            }
            long long ticks = DateToTicks( year, month, day ) + TimeToTicks( hour, minute, second );
            data = ( ( long long )ticks | ( ( long long )kind << KindShift ) );
        }

        DateTime::DateTime( int year, int month, int day, int hour, int minute, int second, const globalization::Calendar& calendar )
        {
            data = ( unsigned long long )calendar.ToDateTime( year, month, day, hour, minute, second, 0 ).Ticks( );
        }

        DateTime::DateTime( int year, int month, int day, int hour, int minute, int second, int millisecond )
        {
            if ( millisecond < 0 || millisecond >= MillisPerSecond )
            {
                throw ArgumentOutOfRangeException( "millisecond", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1 ) );
            }
            long long ticks = DateToTicks( year, month, day ) + TimeToTicks( hour, minute, second );
            ticks += millisecond * TicksPerMillisecond;
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                throw new ArgumentException( Environment::GetResourceString( ApplicationResources::ARG_DATETIMERANGE ) );
            }
            data = ( unsigned long long )ticks;
        }



        DateTime::DateTime( int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind )
        {
            if ( millisecond < 0 || millisecond >= MillisPerSecond )
            {
                throw ArgumentOutOfRangeException( "millisecond", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1 ) );
            }
            if ( kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARGUMENT_INVALIDDATETIMEKIND ), "kind" );
            }
            long long ticks = DateToTicks( year, month, day ) + TimeToTicks( hour, minute, second );
            ticks += millisecond * TicksPerMillisecond;
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARG_DATETIMERANGE ) );
            }
            data = ( ( unsigned long long )ticks | ( ( unsigned long long )kind << KindShift ) );
        }

        DateTime::DateTime( int year, int month, int day, int hour, int minute, int second, int millisecond, const globalization::Calendar& calendar )
        {
            if ( millisecond < 0 || millisecond >= MillisPerSecond )
            {
                throw ArgumentOutOfRangeException( "millisecond", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1 ) );
            }
            long long ticks = calendar.ToDateTime( year, month, day, hour, minute, second, 0 ).Ticks( );
            ticks += millisecond * TicksPerMillisecond;
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARG_DATETIMERANGE ) );
            }
            data = ( unsigned long long )ticks;
        }

        DateTime::DateTime( int year, int month, int day, int hour, int minute, int second, int millisecond, const globalization::Calendar& calendar, DateTimeKind kind )
        {
            if ( millisecond < 0 || millisecond >= MillisPerSecond )
            {
                throw ArgumentOutOfRangeException( "millisecond", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1 ) );
            }
            if ( kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARGUMENT_INVALIDDATETIMEKIND ), "kind" );
            }
            long long ticks = calendar.ToDateTime( year, month, day, hour, minute, second, 0 ).Ticks( );
            ticks += millisecond * TicksPerMillisecond;
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARG_DATETIMERANGE ) );
            }
            data = ( ( unsigned long long )ticks | ( ( unsigned long long )kind << KindShift ) );
        }

        DateTime DateTime::Add( const TimeSpan& value ) const
        {
            return AddTicks( value.ticks );
        }

        DateTime DateTime::Add( double value, int scale ) const
        {
            long long millis = ( long long )( value * scale + ( value >= 0 ? 0.5 : -0.5 ) );
            if ( millis <= -MaxMillis || millis >= MaxMillis )
            {
                throw ArgumentOutOfRangeException( "value", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_ADDVALUE ) );
            }
            return AddTicks( millis * TicksPerMillisecond );
        }

        DateTime DateTime::AddDays( double value ) const
        {
            return Add( value, MillisPerDay );
        }

        DateTime DateTime::AddHours( double value ) const
        {
            return Add( value, MillisPerHour );
        }

        DateTime DateTime::AddMilliseconds( double value ) const
        {
            return Add( value, 1 );
        }

        DateTime DateTime::AddMinutes( double value ) const
        {
            return Add( value, MillisPerMinute );
        }

        DateTime DateTime::AddMonths( int months ) const
        {
            if ( months < -120000 || months > 120000 )
            {
                throw ArgumentOutOfRangeException( "months", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_DATETIMEBADMONTHS ) );
            }
            int y, m, d;

            GetYearMonthDay( y, m, d );

            int i = m - 1 + months;
            if ( i >= 0 )
            {
                m = i % 12 + 1;
                y = y + i / 12;
            }
            else
            {
                m = 12 + ( i + 1 ) % 12;
                y = y + ( i - 11 ) / 12;
            }
            if ( y < 1 || y > 9999 )
            {
                throw ArgumentOutOfRangeException( "months", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_DATEARITHMETIC ) );
            }
            int days = DaysInMonth( y, m );
            if ( d > days )
            {
                d = days;
            }
            return DateTime( ( unsigned long long )( DateToTicks( y, m, d ) + ( data & TicksMask ) % TicksPerDay ) | ( data & FlagsMask ) );
        }

        DateTime DateTime::AddSeconds( double value ) const
        {
            return Add( value, MillisPerSecond );
        }

        DateTime DateTime::AddTicks( long long value ) const
        {
            long long ticks = data & TicksMask;
            if ( value > MaxTicks - ticks || value < MinTicks - ticks )
            {
                throw ArgumentOutOfRangeException( "value", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_DATEARITHMETIC ) );
            }
            return DateTime( ( unsigned long long )( ticks + value ) | ( data & FlagsMask ) );
        }

        DateTime DateTime::AddYears( int value ) const
        {
            if ( value < -10000 || value > 10000 )
            {
                throw ArgumentOutOfRangeException( "years", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_DATETIMEBADYEARS ) );
            }
            return AddMonths( value * 12 );
        }

        const DateTime& DateTime::AssingTo( SYSTEMTIME& systemTime ) const
        {
            long long filetime = data & TicksMask;
            filetime -= FileTimeOffset;
            FileTimeToSystemTime( ( FILETIME* )&filetime, &systemTime );
            return *this;
        }

        AnsiString DateTime::DateToAnsiString( ) const
        {
            char buffer[128];
            SYSTEMTIME systemTime;
            AssingTo( systemTime );
            size_t length = GetDateFormatA( LOCALE_USER_DEFAULT, 0, &systemTime, nullptr, buffer, 128 );
            if ( length == 0 )
            {
                ThrowLastOSError( );
            }
            AnsiString result( buffer, length );
            return result;
        }
        WideString DateTime::DateToString( ) const
        {
            wchar_t buffer[128];
            SYSTEMTIME systemTime;
            AssingTo( systemTime );
            size_t length = GetDateFormatW( LOCALE_USER_DEFAULT, 0, &systemTime, nullptr, buffer, 128 );
            if ( length == 0 )
            {
                ThrowLastOSError( );
            }
            WideString result( buffer, length );
            return result;
        }

        AnsiString DateTime::TimeToAnsiString( ) const
        {
            char buffer[128];
            SYSTEMTIME systemTime;
            AssingTo( systemTime );
            size_t length = GetTimeFormatA( LOCALE_USER_DEFAULT, 0, &systemTime, nullptr, buffer, 128 );
            if ( length == 0 )
            {
                ThrowLastOSError( );
            }
            AnsiString result( buffer, length );
            return result;
        }
        WideString DateTime::TimeToString( ) const
        {
            wchar_t buffer[128];
            SYSTEMTIME systemTime;
            AssingTo( systemTime );
            size_t length = GetTimeFormatW( LOCALE_USER_DEFAULT, 0, &systemTime, nullptr, buffer, 128 );
            if ( length == 0 )
            {
                ThrowLastOSError( );
            }
            WideString result( buffer, length );
            return result;
        }

        AnsiString DateTime::ToAnsiString( ) const
        {
            char buffer[128];
            SYSTEMTIME systemTime;
            AssingTo( systemTime );
            int length = GetDateFormatA( LOCALE_USER_DEFAULT, 0, &systemTime, nullptr, buffer, 128 );
            if ( length == 0 )
            {
                ThrowLastOSError( );
            }
            buffer[length - 1] = '\x20';

            int length2 = GetTimeFormatA( LOCALE_USER_DEFAULT, 0, &systemTime, nullptr, &buffer[length], 128 - ( length ) );
            if ( length2 == 0 )
            {
                ThrowLastOSError( );
            }

            AnsiString result( buffer, size_t( length + length2 - 1 ) );
            return result;
        }

        WideString DateTime::ToString( ) const
        {
            wchar_t buffer[128];
            SYSTEMTIME systemTime;
            AssingTo( systemTime );
            int length = GetDateFormatW( LOCALE_USER_DEFAULT, 0, &systemTime, nullptr, buffer, 128 );
            if ( length == 0 )
            {
                ThrowLastOSError( );
            }
            buffer[length - 1] = '\x20';

            int length2 = GetTimeFormatW( LOCALE_USER_DEFAULT, 0, &systemTime, nullptr, &buffer[length], 128 - ( length ) );
            if ( length2 == 0 )
            {
                ThrowLastOSError( );
            }

            WideString result( buffer, size_t( length + length2 - 1 ) );
            return result;
        }


        int DateTime::Compare( const DateTime& t1, const DateTime& t2 )
        {
            long long ticks1 = t1.data & TicksMask;
            long long ticks2 = t2.data & TicksMask;
            if ( ticks1 > ticks2 )
            {
                return 1;
            }
            if ( ticks1 < ticks2 )
            {
                return -1;
            }
            return 0;
        }


        int DateTime::CompareTo( const DateTime& value ) const
        {
            long long valueTicks = value.data & TicksMask;
            long long ticks = data & TicksMask;
            if ( ticks > valueTicks )
            {
                return 1;
            }
            if ( ticks < valueTicks )
            {
                return -1;
            }
            return 0;
        }


        int DateTime::DaysInMonth( int year, int month )
        {
            if ( month < 1 || month > 12 )
            {
                throw ArgumentOutOfRangeException( "month", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_MONTH ) );
            }
            const int* days = IsLeapYear( year ) ? DaysToMonth366 : DaysToMonth365;
            return days[month] - days[month - 1];
        }

        long long DateTime::DoubleDateToTicks( double value )
        {
            if ( value >= OADateMaxAsDouble || value <= OADateMinAsDouble )
            {
                throw new ArgumentException( Environment::GetResourceString( ApplicationResources::ARG_OLEAUTDATEINVALID ) );
            }
            long long millis = ( long long )( value * MillisPerDay + ( value >= 0 ? 0.5 : -0.5 ) );

            // fixup for negative milliseconds
            if ( millis < 0 )
            {
                millis -= ( millis % MillisPerDay ) * 2;
            }

            millis += DoubleDateOffset / TicksPerMillisecond;

            if ( millis < 0 || millis >= MaxMillis )
            {
                throw new ArgumentException( Environment::GetResourceString( ApplicationResources::ARG_OLEAUTDATESCALE ) );
            }
            return millis * TicksPerMillisecond;
        }



        DateTime DateTime::FromBinary( long long data )
        {
            long long ticks = data & TicksMask;
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                throw ArgumentException( Environment::GetResourceString( ApplicationResources::ARGUMENT_DATETIMEBADBINARYDATA ), "data" );
            }
            return DateTime( data );
        }

        DateTime DateTime::FromFileTime( long long fileTime )
        {
            return FromFileTimeUtc( fileTime ).ToLocalTime( );
        }

        DateTime DateTime::FromFileTimeUtc( long long fileTime )
        {
            if ( fileTime < 0 || fileTime > MaxTicks - FileTimeOffset )
            {
                throw new ArgumentOutOfRangeException( "fileTime", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_FILETIMEINVALID ) );
            }

            long long universalTicks = fileTime + FileTimeOffset;
            return DateTime( universalTicks, DateTimeKind::Utc );
        }

        DateTime DateTime::FromOADate( double d )
        {
            return DateTime( DoubleDateToTicks( d ), DateTimeKind::Unspecified );
        }


        bool DateTime::IsDaylightSavingTime( ) const
        {
            if ( Kind( ) == DateTimeKind::Utc )
            {
                return false;
            }

            USHORT year = USHORT( Year( ) );
            TIME_ZONE_INFORMATION tzi;
            if ( GetTimeZoneInformationForYear( year, nullptr, &tzi ) == FALSE )
            {
                ThrowLastOSError( );
            }

            tzi.DaylightDate.wYear = year;
            tzi.StandardDate.wYear = year;

            long long daylightDateInTicks = SystemTimeToTicks( tzi.DaylightDate );
            long long standardDateInTicks = SystemTimeToTicks( tzi.StandardDate );
            long long ticks = data & TicksMask;


            if ( daylightDateInTicks > standardDateInTicks )
            {
                if ( ( ticks > standardDateInTicks ) && ( ticks < daylightDateInTicks ) )
                {
                    return true;
                }
            }
            else if ( daylightDateInTicks < standardDateInTicks )
            {
                if ( ( ticks > daylightDateInTicks ) && ( ticks < standardDateInTicks ) )
                {
                    return true;
                }
            }
            return false;
        }

        DateTime DateTime::SpecifyKind( const DateTime& value, DateTimeKind kind )
        {
            return DateTime( value.data & TicksMask, kind );
        }

        long long DateTime::ToBinary( ) const
        {
            return data;
        }

        DateTime DateTime::Date( ) const
        {
            long long ticks = data & TicksMask;
            return DateTime( ( unsigned long long )( ticks - ticks % TicksPerDay ) | ( data & FlagsMask ) );
        }

        int DateTime::GetDatePart( DatePart part ) const
        {
            long long ticks = data & TicksMask;
            int n = ( int )( ticks / TicksPerDay );
            int periodsOf400years = n / DaysPer400Years;
            n -= periodsOf400years * DaysPer400Years;
            int periodsOf100years = n / DaysPer100Years;
            if ( periodsOf100years == 4 )
            {
                periodsOf100years = 3;
            }
            n -= periodsOf100years * DaysPer100Years;
            int periodsOf4years = n / DaysPer4Years;
            n -= periodsOf4years * DaysPer4Years;
            int y1 = n / DaysPerYear;
            if ( y1 == 4 )
            {
                y1 = 3;
            }

            if ( part == DatePart::Year )
            {
                return periodsOf400years * 400 + periodsOf100years * 100 + periodsOf4years * 4 + y1 + 1;
            }
            n -= y1 * DaysPerYear;
            if ( part == DatePart::DayOfYear )
            {
                return n + 1;
            }

            bool leapYear = y1 == 3 && ( periodsOf4years != 24 || periodsOf100years == 3 );

            const int* days = leapYear ? DaysToMonth366 : DaysToMonth365;

            int m = ( n >> 5 ) + 1;

            while ( n >= days[m] )
            {
                m++;
            }
            if ( part == DatePart::Month )
            {
                return m;
            }
            return n - days[m - 1] + 1;
        }

        void DateTime::GetYearMonthDay( int& year, int& month, int& day ) const
        {
            long long ticks = data & TicksMask;
            int n = ( int )( ticks / TicksPerDay );
            int periodsOf400years = n / DaysPer400Years;
            n -= periodsOf400years * DaysPer400Years;
            int periodsOf100years = n / DaysPer100Years;
            if ( periodsOf100years == 4 )
            {
                periodsOf100years = 3;
            }
            n -= periodsOf100years * DaysPer100Years;
            int periodsOf4years = n / DaysPer4Years;
            n -= periodsOf4years * DaysPer4Years;
            int y1 = n / DaysPerYear;
            if ( y1 == 4 )
            {
                y1 = 3;
            }

            year = periodsOf400years * 400 + periodsOf100years * 100 + periodsOf4years * 4 + y1 + 1;

            n -= y1 * DaysPerYear;

            bool leapYear = y1 == 3 && ( periodsOf4years != 24 || periodsOf100years == 3 );

            const int* days = leapYear ? DaysToMonth366 : DaysToMonth365;

            int m = ( n >> 5 ) + 1;

            while ( n >= days[m] )
            {
                m++;
            }
            month = m;

            day = n - days[m - 1] + 1;
        }


        int DateTime::Day( ) const
        {
            return GetDatePart( DatePart::Day );
        }

        DayOfWeek DateTime::DayOfWeek( ) const
        {
            long long ticks = data & TicksMask;
            return ( ::harlinn::windows::DayOfWeek )( ( ticks / TicksPerDay + 1 ) % 7 );
        }

        int DateTime::DayOfYear( ) const
        {
            return GetDatePart( DatePart::DayOfYear );
        }


        int DateTime::Hour( ) const
        {
            long long ticks = data & TicksMask;
            return ( int )( ( ticks / TicksPerHour ) % 24 );
        }


        DateTimeKind DateTime::Kind( ) const
        {
            long long kind = data & FlagsMask;
            switch ( kind )
            {
                case KindUnspecified:
                return DateTimeKind::Unspecified;
                case KindUtc:
                return DateTimeKind::Utc;
                default:
                return DateTimeKind::Local;
            }
        }

        int DateTime::Millisecond( ) const
        {
            long long ticks = data & TicksMask;
            return ( int )( ( ticks / TicksPerMillisecond ) % 1000 );
        }

        int DateTime::Minute( ) const
        {
            long long ticks = data & TicksMask;
            return ( int )( ( ticks / TicksPerMinute ) % 60 );
        }

        int DateTime::Month( ) const
        {
            return GetDatePart( DatePart::Month );
        }



        DateTime DateTime::Now( )
        {
            DateTime utc = UtcNow( );
            return utc.ToLocalTime( );
        }

        DateTime DateTime::UtcNow( )
        {
            long long ticks = 0;
            GetSystemTimeAsFileTime( ( FILETIME* )&ticks );
            return DateTime( ( ( unsigned long long )( ticks + FileTimeOffset ) ) | KindUtc );
        }

        int DateTime::Second( ) const
        {
            long long ticks = data & TicksMask;
            return ( int )( ( ticks / TicksPerSecond ) % 60 );
        }


        TimeSpan DateTime::TimeOfDay( ) const
        {
            long long ticks = data & TicksMask;
            return TimeSpan( ticks % TicksPerDay );
        }

        DateTime DateTime::Today( )
        {
            return DateTime::Now( ).Date( );
        }

        int DateTime::Year( ) const
        {
            return GetDatePart( DatePart::Year );
        }

        bool DateTime::IsLeapYear( int year )
        {
            if ( year < 1 || year > 9999 )
            {
                throw ArgumentOutOfRangeException( "year", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_YEAR ) );
            }
            return year % 4 == 0 && ( year % 100 != 0 || year % 400 == 0 );
        }

        TimeSpan DateTime::Subtract( const DateTime& value ) const
        {
            long long ticks = data & TicksMask;
            long long valueTicks = value.data & TicksMask;
            return TimeSpan( ticks - valueTicks );
        }

        DateTime DateTime::Subtract( const TimeSpan& value ) const
        {
            long long ticks = data & TicksMask;
            long long valueTicks = value.ticks;
            if ( ticks - MinTicks < valueTicks || ticks - MaxTicks > valueTicks )
            {
                throw ArgumentOutOfRangeException( "value", Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_DATEARITHMETIC ) );
            }
            return DateTime( ( unsigned long long )( ticks - valueTicks ) | ( data & FlagsMask ) );
        }

        double DateTime::TicksToOADate( long long value )
        {
            if ( value == 0 )
            {
                return 0.0;
            }
            if ( value < TicksPerDay )
            {
                value += DoubleDateOffset;
            }
            if ( value < OADateMinAsTicks )
            {
                throw OverflowException( Environment::GetResourceString( ApplicationResources::ARG_OLEAUTDATEINVALID ) );
            }
            long long millis = ( value - DoubleDateOffset ) / TicksPerMillisecond;
            if ( millis < 0 )
            {
                long long frac = millis % MillisPerDay;
                if ( frac != 0 )
                {
                    millis -= ( MillisPerDay + frac ) * 2;
                }
            }
            return ( ( double )millis ) / MillisPerDay;
        }

        double DateTime::ToOADate( ) const
        {
            long long ticks = data & TicksMask;
            return TicksToOADate( ticks );
        }

        long long DateTime::ToFileTime( ) const
        {
            return ToUniversalTime( ).ToFileTimeUtc( );
        }

        long long DateTime::ToFileTimeUtc( ) const
        {
            long long ticks = data & KindLocal ? ToUniversalTime( ).data & TicksMask : data & TicksMask;
            ticks -= FileTimeOffset;
            if ( ticks < 0 )
            {
                throw ArgumentOutOfRangeException( static_cast<CharType*>( nullptr ), Environment::GetResourceString( ApplicationResources::ARGUMENTOUTOFRANGE_FILETIMEINVALID ) );
            }
            return ticks;
        }

        DateTime DateTime::ToLocalTime( ) const
        {
            if ( data & KindLocal )
            {
                return *this;
            }
            long long ticks = data & TicksMask;
            ticks -= FileTimeOffset;
            long long localTicks = 0;
            FileTimeToLocalFileTime( ( FILETIME* )&ticks, ( FILETIME* )&localTicks );
            localTicks += FileTimeOffset;
            return DateTime( localTicks, DateTimeKind::Local );
        }

        DateTime DateTime::ToUniversalTime( ) const
        {
            if ( data & KindUtc )
            {
                return *this;
            }
            long long ticks = data & TicksMask;
            ticks -= FileTimeOffset;
            long long utcTicks = 0;
            LocalFileTimeToFileTime( ( FILETIME* )&ticks, ( FILETIME* )&utcTicks );
            utcTicks += FileTimeOffset;
            return DateTime( utcTicks, DateTimeKind::Utc );
        }

        bool DateTime::TryCreate( int year, int month, int day, int hour, int minute, int second, int millisecond, DateTime& result )
        {
            result = MinValue;
            if ( year < 1 || year > 9999 || month < 1 || month > 12 )
            {
                return false;
            }
            const int* days = IsLeapYear( year ) ? DaysToMonth366 : DaysToMonth365;
            if ( day < 1 || day > days[month] - days[month - 1] )
            {
                return false;
            }

            if ( hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60 )
            {
                return false;
            }
            if ( millisecond < 0 || millisecond >= MillisPerSecond )
            {
                return false;
            }
            long long ticks = DateToTicks( year, month, day ) + TimeToTicks( hour, minute, second );

            ticks += millisecond * TicksPerMillisecond;
            if ( ticks < MinTicks || ticks > MaxTicks )
            {
                return false;
            }
            result = DateTime( ticks, DateTimeKind::Unspecified );
            return true;
        }











        // ----------------------------------------------------------------------
        // Stopwatch
        // ----------------------------------------------------------------------
        long long Stopwatch::frequency( TimeBase::TicksPerSecond );
        const bool Stopwatch::IsHighResolution = Stopwatch::InitializeStopwatch( );
        double Stopwatch::tickFrequency = 1.0;

        bool Stopwatch::InitializeStopwatch( )
        {
            long long frq = 0;
            bool result = QueryPerformanceFrequency( ( LARGE_INTEGER* )&frq ) != FALSE;
            if ( result )
            {
                frequency = frq;
                tickFrequency = double( TimeBase::TicksPerSecond ) / double( frequency );
            }
            return result;
        }

        long long Stopwatch::Frequency( )
        {
            return frequency;
        }


        Stopwatch::Stopwatch( )
            : elapsedTicks( 0 ),
            isRunning( false ),
            startedAt( 0 )
        {

        }

        void Stopwatch::Start( )
        {
            if ( !isRunning )
            {
                startedAt = GetTimestamp( );
                isRunning = true;
            }
        }

        void Stopwatch::Restart( )
        {
            elapsedTicks = 0;
            startedAt = GetTimestamp( );
            isRunning = true;
        }


        Stopwatch Stopwatch::StartNew( )
        {
            Stopwatch result;
            result.Start( );
            return result;
        }

        void Stopwatch::Stop( )
        {
            if ( isRunning )
            {
                isRunning = false;

                long long endTimeStamp = GetTimestamp( );
                long long elapsedThisPeriod = endTimeStamp - startedAt;
                elapsedTicks += elapsedThisPeriod;

                if ( elapsedTicks < 0 )
                {
                    elapsedTicks = 0;
                }
            }
        }

        void Stopwatch::Reset( )
        {
            elapsedTicks = 0;
            isRunning = false;
            startedAt = 0;
        }


        bool Stopwatch::IsRunning( ) const
        {
            return isRunning;
        }

        TimeSpan Stopwatch::Elapsed( ) const
        {
            return TimeSpan( GetElapsedDateTimeTicks( ) );
        }

        long long Stopwatch::ElapsedMilliseconds( ) const
        {
            return GetElapsedDateTimeTicks( ) / TimeBase::TicksPerMillisecond;
        }

        long long Stopwatch::ElapsedTicks( ) const
        {
            long long timeElapsed = elapsedTicks;

            if ( isRunning )
            {
                long long currentTimeStamp = GetTimestamp( );
                long long elapsedUntilNow = currentTimeStamp - startedAt;
                timeElapsed += elapsedUntilNow;
            }
            return timeElapsed;
        }

        long long Stopwatch::GetTimestamp( )
        {
            if ( IsHighResolution )
            {
                long long timestamp = 0;
                QueryPerformanceCounter( ( LARGE_INTEGER* )&timestamp );
                return timestamp;
            }
            else
            {
                return DateTime::UtcNow( ).Ticks( );
            }
        }

        double Stopwatch::GetTimestampInSeconds( )
        {
            double ts = tickFrequency * double( Stopwatch::GetTimestamp( ) )*TimeBase::SecondsPerTick;
            return ts;
        }
        double Stopwatch::GetTimestampInMilliseconds( )
        {
            double ts = tickFrequency * double( Stopwatch::GetTimestamp( ) )*TimeBase::MillisecondsPerTick;
            return ts;
        }

        long long Stopwatch::GetElapsedDateTimeTicks( ) const
        {
            long long ticks = ElapsedTicks( );
            if ( IsHighResolution )
            {
                double dticks = double( ticks );
                dticks *= tickFrequency;
                return long long( dticks );
            }
            else
            {
                return ticks;
            }
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Sea Surveillance AS
Norway Norway
Chief Architect - Sea Surveillance AS.

Specializing in integrated operations and high performance computing solutions.

I’ve been fooling around with computers since the early eighties, I’ve even done work on CP/M and MP/M.

Wrote my first “real” program on a BBC micro model B based on a series in a magazine at that time. It was fun and I got hooked on this thing called programming ...

A few Highlights:

  • High performance application server development
  • Model Driven Architecture and Code generators
  • Real-Time Distributed Solutions
  • C, C++, C#, Java, TSQL, PL/SQL, Delphi, ActionScript, Perl, Rexx
  • Microsoft SQL Server, Oracle RDBMS, IBM DB2, PostGreSQL
  • AMQP, Apache qpid, RabbitMQ, Microsoft Message Queuing, IBM WebSphereMQ, Oracle TuxidoMQ
  • Oracle WebLogic, IBM WebSphere
  • Corba, COM, DCE, WCF
  • AspenTech InfoPlus.21(IP21), OsiSoft PI


More information about what I do for a living can be found at: harlinn.com or LinkedIn

You can contact me at espen@harlinn.no

Comments and Discussions