#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* )×tamp );
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;
}
}
}
}