#include "stdafx.h"
#include "hwindatetime.h"
#include "hwinenvironment.h"
#include "hwinexception.h"
#include "hwincalendar.h"
#include "hwinresources.h"
namespace harlinn
{
namespace windows
{
namespace
{
const long long TicksPerMillisecond = 10000;
const long long TicksPerSecond = TicksPerMillisecond * 1000;
const long long TicksPerMinute = TicksPerSecond * 60;
const long long TicksPerHour = TicksPerMinute * 60;
const long long TicksPerDay = TicksPerHour * 24;
const double MillisecondsPerTick = 1.0 / TicksPerMillisecond;
const double SecondsPerTick = 1.0 / TicksPerSecond;
const double MinutesPerTick = 1.0 / TicksPerMinute;
const double HoursPerTick = 1.0 / TicksPerHour;
const double DaysPerTick = 1.0 / TicksPerDay;
const unsigned long long KindUnspecified = 0x0000000000000000;
const unsigned long long KindUtc = 0x4000000000000000;
const unsigned long long KindLocal = 0x8000000000000000;
const unsigned long long TicksMask = 0x3FFFFFFFFFFFFFFF;
const unsigned long long FlagsMask = KindUtc | KindLocal;
const int KindShift = 62;
const int MillisPerSecond = 1000;
const int MillisPerMinute = MillisPerSecond * 60;
const int MillisPerHour = MillisPerMinute * 60;
const int MillisPerDay = MillisPerHour * 24;
const int DaysPerYear = 365;
const int DaysPer4Years = DaysPerYear * 4 + 1;
const int DaysPer100Years = DaysPer4Years * 25 - 1;
const int DaysPer400Years = DaysPer100Years * 4 + 1;
const int DaysTo1601 = DaysPer400Years * 4;
const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367;
const int DaysTo10000 = DaysPer400Years * 25 - 366;
const long long MinTicks = 0;
const long long MaxTicks = DaysTo10000 * TicksPerDay - 1;
const long long MaxMillis = (long long)DaysTo10000 * MillisPerDay;
const long long FileTimeOffset = DaysTo1601 * TicksPerDay;
const long long DoubleDateOffset = DaysTo1899 * TicksPerDay;
const long long OADateMinAsTicks = (DaysPer100Years - DaysPerYear) * TicksPerDay;
const int DaysToMonth365[13] =
{
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
};
const int DaysToMonth366[13] =
{
0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
};
const double OADateMinAsDouble = -657435.0;
const double OADateMaxAsDouble = 2958466.0;
}
// ----------------------------------------------------------------------
// TimeSpan
// ----------------------------------------------------------------------
HWIN_EXPORT const TimeSpan TimeSpan::Zero(0);
HWIN_EXPORT const TimeSpan TimeSpan::MaxValue(MAXINT64);
HWIN_EXPORT const TimeSpan TimeSpan::MinValue(MININT64);
HWIN_EXPORT 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(Resources::OVERFLOW_TIMESPANTOOLONG));
}
long long result = milliSeconds * TicksPerMillisecond;
return result;
}
HWIN_EXPORT 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(Resources::OVERFLOW_TIMESPANTOOLONG));
}
return TimeSpan(result);
}
HWIN_EXPORT TimeSpan TimeSpan::Interval(double theValue, int theScale)
{
if (_isnan(theValue))
{
throw ArgumentException(Environment::GetResourceString(Resources::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(Resources::OVERFLOW_NEGATETWOSCOMPNUM));
}
return TimeSpan((long long)milliSeconds * TicksPerMillisecond);
}
HWIN_EXPORT TimeSpan TimeSpan::Duration() const
{
if (ticks == MinValue.ticks)
{
throw OverflowException(Environment::GetResourceString(Resources::OVERFLOW_DURATION));
}
return TimeSpan(ticks >= 0? ticks: -ticks);
}
HWIN_EXPORT TimeSpan TimeSpan::Negate() const
{
if (ticks==MinValue.ticks)
{
throw OverflowException(Environment::GetResourceString(Resources::OVERFLOW_NEGATETWOSCOMPNUM));
}
return TimeSpan(-ticks);
}
HWIN_EXPORT 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(Resources::OVERFLOW_TIMESPANTOOLONG));
}
return TimeSpan(result);
}
HWIN_EXPORT String 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 String(buffer,length);
}
HWIN_EXPORT double TimeSpan::TotalDays() const
{
return ((double)ticks) * DaysPerTick;
}
HWIN_EXPORT double TimeSpan::TotalHours() const
{
return (double(ticks)) * HoursPerTick;
}
HWIN_EXPORT double TimeSpan::TotalMilliseconds() const
{
double result = ((double)ticks) * MillisecondsPerTick;
if (result > MaxMilliSeconds)
{
return (double)MaxMilliSeconds;
}
if (result < MinMilliSeconds)
{
return (double)MinMilliSeconds;
}
return result;
}
HWIN_EXPORT double TimeSpan::TotalMinutes() const
{
return (double)ticks * MinutesPerTick;
}
HWIN_EXPORT double TimeSpan::TotalSeconds() const
{
return (double)ticks * SecondsPerTick;
}
// ----------------------------------------------------------------------
// DateTime
// ----------------------------------------------------------------------
HWIN_EXPORT const DateTime DateTime::MinValue(MinTicks, DateTimeKind::Unspecified);
HWIN_EXPORT const DateTime DateTime::MaxValue(MaxTicks, DateTimeKind::Unspecified);
HWIN_EXPORT DateTime::DateTime(long long ticks)
{
if (ticks < MinTicks || ticks > MaxTicks)
{
throw ArgumentOutOfRangeException("ticks", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATETIMEBADTICKS));
}
data = (unsigned long long)ticks;
}
HWIN_EXPORT DateTime::DateTime(unsigned long long theDateData)
: data(theDateData)
{
}
HWIN_EXPORT DateTime::DateTime(long long ticks, DateTimeKind kind)
{
if (ticks < MinTicks || ticks > MaxTicks)
{
throw ArgumentOutOfRangeException("ticks", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATETIMEBADTICKS));
}
if (kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local)
{
throw ArgumentException(Environment::GetResourceString(Resources::ARGUMENT_INVALIDDATETIMEKIND), "kind");
}
data = ((unsigned long long)ticks | ((unsigned long long)kind << KindShift));
}
HWIN_EXPORT long long DateTime::ToTicks(int year, int month, int day, const globalization::Calendar& calendar)
{
return ToTicks(year, month, day,0,0,0,0,calendar);
}
HWIN_EXPORT 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(Resources::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(Resources::ARG_DATETIMERANGE));
}
return ticks;
}
HWIN_EXPORT 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(nullptr, Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_BADYEARMONTHDAY));
}
HWIN_EXPORT long long DateTime::SystemTimeToTicks(const SYSTEMTIME& systemTime)
{
if (systemTime.wMilliseconds >= MillisPerSecond)
{
throw ArgumentOutOfRangeException("systemTime.wMilliseconds", Environment::GetResourceString(Resources::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(Resources::ARG_DATETIMERANGE));
}
return ticks;
}
HWIN_EXPORT 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(nullptr, Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_BADHOURMINUTESECOND));
}
HWIN_EXPORT DateTime::DateTime(int year, int month, int day)
{
data = (unsigned long long) DateToTicks(year, month, day);
}
HWIN_EXPORT DateTime::DateTime(int year, int month, int day, const globalization::Calendar& calendar)
: data(ToTicks( year, month, day, 0, 0, 0,0, calendar))
{
}
HWIN_EXPORT DateTime::DateTime(int year, int month, int day, int hour, int minute, int second)
: data(DateToTicks(year, month, day) + TimeToTicks(hour, minute, second))
{
}
HWIN_EXPORT 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(Resources::ARGUMENT_INVALIDDATETIMEKIND), "kind");
}
long long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
data = ((long long)ticks | ((long long)kind << KindShift));
}
HWIN_EXPORT 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();
}
HWIN_EXPORT 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(Resources::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(Resources::ARG_DATETIMERANGE));
}
data = (unsigned long long)ticks;
}
HWIN_EXPORT 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(Resources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1));
}
if (kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local)
{
throw ArgumentException(Environment::GetResourceString(Resources::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(Resources::ARG_DATETIMERANGE));
}
data = ((unsigned long long)ticks | ((unsigned long long)kind << KindShift));
}
HWIN_EXPORT 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(Resources::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(Resources::ARG_DATETIMERANGE));
}
data = (unsigned long long)ticks;
}
HWIN_EXPORT 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(Resources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1));
}
if (kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local)
{
throw ArgumentException(Environment::GetResourceString(Resources::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(Resources::ARG_DATETIMERANGE));
}
data = ((unsigned long long)ticks | ((unsigned long long)kind << KindShift));
}
HWIN_EXPORT DateTime DateTime::Add(const TimeSpan& value) const
{
return AddTicks(value.ticks);
}
HWIN_EXPORT 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(Resources::ARGUMENTOUTOFRANGE_ADDVALUE));
}
return AddTicks(millis * TicksPerMillisecond);
}
HWIN_EXPORT DateTime DateTime::AddDays(double value) const
{
return Add(value, MillisPerDay);
}
HWIN_EXPORT DateTime DateTime::AddHours(double value) const
{
return Add(value, MillisPerHour);
}
HWIN_EXPORT DateTime DateTime::AddMilliseconds(double value) const
{
return Add(value, 1);
}
HWIN_EXPORT DateTime DateTime::AddMinutes(double value) const
{
return Add(value, MillisPerMinute);
}
HWIN_EXPORT DateTime DateTime::AddMonths(int months) const
{
if (months < -120000 || months > 120000)
{
throw ArgumentOutOfRangeException("months", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATETIMEBADMONTHS));
}
int y = GetDatePart(DatePart::Year);
int m = GetDatePart(DatePart::Month);
int d = GetDatePart(DatePart::Day);
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(Resources::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));
}
HWIN_EXPORT DateTime DateTime::AddSeconds(double value) const
{
return Add(value, MillisPerSecond);
}
HWIN_EXPORT DateTime DateTime::AddTicks(long long value) const
{
long long ticks = data & TicksMask;
if (value > MaxTicks - ticks || value < MinTicks - ticks)
{
throw ArgumentOutOfRangeException("value", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATEARITHMETIC));
}
return DateTime((unsigned long long)(ticks + value) | (data & FlagsMask));
}
HWIN_EXPORT DateTime DateTime::AddYears(int value) const
{
if (value < -10000 || value > 10000)
{
throw ArgumentOutOfRangeException("years", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATETIMEBADYEARS));
}
return AddMonths(value * 12);
}
HWIN_EXPORT const DateTime& DateTime::AssingTo(SYSTEMTIME& systemTime) const
{
long long filetime = data & TicksMask;
filetime -= FileTimeOffset;
FileTimeToSystemTime((FILETIME*)&filetime,&systemTime);
return *this;
}
HWIN_EXPORT std::string 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();
}
std::string result(buffer,length);
return result;
}
HWIN_EXPORT String 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();
}
String result(buffer,length);
return result;
}
HWIN_EXPORT std::string 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();
}
std::string result(buffer,length);
return result;
}
HWIN_EXPORT String 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();
}
String result(buffer,length);
return result;
}
HWIN_EXPORT std::string 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] = '\x20';
int length2 = GetTimeFormatA(LOCALE_USER_DEFAULT, 0,&systemTime,nullptr,&buffer[length+1],128-(length+1));
if(length2 == 0)
{
ThrowLastOSError();
}
std::string result(buffer,size_t(length+length2+1));
return result;
}
HWIN_EXPORT String 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] = '\x20';
int length2 = GetTimeFormatW(LOCALE_USER_DEFAULT, 0,&systemTime,nullptr,&buffer[length+1],128-(length+1));
if(length2 == 0)
{
ThrowLastOSError();
}
String result(buffer,size_t(length+length2+1));
return result;
}
HWIN_EXPORT 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;
}
HWIN_EXPORT 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;
}
HWIN_EXPORT int DateTime::DaysInMonth(int year, int month)
{
if (month < 1 || month > 12)
{
throw ArgumentOutOfRangeException("month", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_MONTH));
}
const int* days = IsLeapYear(year)? DaysToMonth366: DaysToMonth365;
return days[month] - days[month - 1];
}
HWIN_EXPORT long long DateTime::DoubleDateToTicks(double value)
{
if (value >= OADateMaxAsDouble || value <= OADateMinAsDouble)
{
throw new ArgumentException(Environment::GetResourceString(Resources::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(Resources::ARG_OLEAUTDATESCALE));
}
return millis * TicksPerMillisecond;
}
HWIN_EXPORT DateTime DateTime::FromBinary(long long data)
{
long long ticks = data & TicksMask;
if (ticks < MinTicks || ticks > MaxTicks)
{
throw ArgumentException(Environment::GetResourceString(Resources::ARGUMENT_DATETIMEBADBINARYDATA), "data");
}
return DateTime(data);
}
HWIN_EXPORT DateTime DateTime::FromFileTime(long long fileTime)
{
return FromFileTimeUtc(fileTime).ToLocalTime();
}
HWIN_EXPORT DateTime DateTime::FromFileTimeUtc(long long fileTime)
{
if (fileTime < 0 || fileTime > MaxTicks - FileTimeOffset)
{
throw new ArgumentOutOfRangeException("fileTime", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_FILETIMEINVALID));
}
long long universalTicks = fileTime + FileTimeOffset;
return DateTime(universalTicks, DateTimeKind::Utc);
}
HWIN_EXPORT DateTime DateTime::FromOADate(double d)
{
return DateTime(DoubleDateToTicks(d), DateTimeKind::Unspecified);
}
HWIN_EXPORT 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;
}
HWIN_EXPORT DateTime DateTime::SpecifyKind(const DateTime& value, DateTimeKind kind)
{
return DateTime(value.data & TicksMask, kind);
}
HWIN_EXPORT long long DateTime::ToBinary() const
{
return data;
}
HWIN_EXPORT DateTime DateTime::Date() const
{
long long ticks = data & TicksMask;
return DateTime((unsigned long long)(ticks - ticks % TicksPerDay) | (data & FlagsMask));
}
HWIN_EXPORT 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;
}
HWIN_EXPORT int DateTime::Day() const
{
return GetDatePart(DatePart::Day);
}
HWIN_EXPORT DayOfWeek DateTime::DayOfWeek() const
{
long long ticks = data & TicksMask;
return (harlinn::windows::DayOfWeek)((ticks / TicksPerDay + 1) % 7);
}
HWIN_EXPORT int DateTime::DayOfYear() const
{
return GetDatePart(DatePart::DayOfYear);
}
HWIN_EXPORT int DateTime::Hour( ) const
{
long long ticks = data & TicksMask;
return (int)((ticks / TicksPerHour) % 24);
}
HWIN_EXPORT 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;
}
}
HWIN_EXPORT int DateTime::Millisecond() const
{
long long ticks = data & TicksMask;
return (int)((ticks/ TicksPerMillisecond) % 1000);
}
HWIN_EXPORT int DateTime::Minute() const
{
long long ticks = data & TicksMask;
return (int)((ticks / TicksPerMinute) % 60);
}
HWIN_EXPORT int DateTime::Month() const
{
return GetDatePart(DatePart::Month);
}
HWIN_EXPORT DateTime DateTime::Now()
{
DateTime utc = UtcNow();
return utc.ToLocalTime();
}
HWIN_EXPORT DateTime DateTime::UtcNow()
{
long long ticks = 0;
GetSystemTimeAsFileTime((FILETIME*)&ticks);
return DateTime( ((unsigned long long)(ticks + FileTimeOffset)) | KindUtc);
}
HWIN_EXPORT int DateTime::Second() const
{
long long ticks = data & TicksMask;
return (int)((ticks / TicksPerSecond) % 60);
}
HWIN_EXPORT long long DateTime::Ticks() const
{
long long ticks = data & TicksMask;
return ticks;
}
HWIN_EXPORT TimeSpan DateTime::TimeOfDay() const
{
long long ticks = data & TicksMask;
return TimeSpan(ticks % TicksPerDay);
}
HWIN_EXPORT DateTime DateTime::Today()
{
return DateTime::Now().Date();
}
HWIN_EXPORT int DateTime::Year() const
{
return GetDatePart(DatePart::Year);
}
HWIN_EXPORT bool DateTime::IsLeapYear(int year)
{
if (year < 1 || year > 9999)
{
throw ArgumentOutOfRangeException("year", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_YEAR));
}
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
HWIN_EXPORT TimeSpan DateTime::Subtract(const DateTime& value) const
{
long long ticks = data & TicksMask;
long long valueTicks = value.data & TicksMask;
return TimeSpan(ticks - valueTicks);
}
HWIN_EXPORT 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(Resources::ARGUMENTOUTOFRANGE_DATEARITHMETIC));
}
return DateTime((unsigned long long)(ticks - valueTicks) | (data & FlagsMask));
}
HWIN_EXPORT double DateTime::TicksToOADate(long long value)
{
if (value == 0)
{
return 0.0;
}
if (value < TicksPerDay)
{
value += DoubleDateOffset;
}
if (value < OADateMinAsTicks)
{
throw OverflowException(Environment::GetResourceString(Resources::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;
}
HWIN_EXPORT double DateTime::ToOADate() const
{
long long ticks = data & TicksMask;
return TicksToOADate(ticks);
}
HWIN_EXPORT long long DateTime::ToFileTime() const
{
return ToUniversalTime().ToFileTimeUtc();
}
HWIN_EXPORT long long DateTime::ToFileTimeUtc() const
{
long long ticks = data & KindLocal ? ToUniversalTime().data & TicksMask : data & TicksMask;
ticks -= FileTimeOffset;
if (ticks < 0)
{
throw ArgumentOutOfRangeException(nullptr, Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_FILETIMEINVALID));
}
return ticks;
}
HWIN_EXPORT 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);
}
HWIN_EXPORT 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);
}
HWIN_EXPORT 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( TicksPerSecond );
HWIN_EXPORT 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(TicksPerSecond)/double(frequency);
}
return result;
}
HWIN_EXPORT long long Stopwatch::Frequency()
{
return frequency;
}
HWIN_EXPORT Stopwatch::Stopwatch()
: elapsedTicks(0),
isRunning(false),
startedAt(0)
{
}
HWIN_EXPORT void Stopwatch::Start()
{
if(!isRunning)
{
startedAt = GetTimestamp();
isRunning = true;
}
}
HWIN_EXPORT void Stopwatch::Restart()
{
elapsedTicks = 0;
startedAt = GetTimestamp();
isRunning = true;
}
HWIN_EXPORT Stopwatch Stopwatch::StartNew()
{
Stopwatch result;
result.Start();
return result;
}
HWIN_EXPORT void Stopwatch::Stop()
{
if( isRunning)
{
isRunning = false;
long long endTimeStamp = GetTimestamp();
long long elapsedThisPeriod = endTimeStamp - startedAt;
elapsedTicks += elapsedThisPeriod;
if(elapsedTicks < 0)
{
elapsedTicks = 0;
}
}
}
HWIN_EXPORT void Stopwatch::Reset()
{
elapsedTicks = 0;
isRunning = false;
startedAt = 0;
}
HWIN_EXPORT bool Stopwatch::IsRunning() const
{
return isRunning;
}
HWIN_EXPORT TimeSpan Stopwatch::Elapsed() const
{
return TimeSpan( GetElapsedDateTimeTicks());
}
HWIN_EXPORT long long Stopwatch::ElapsedMilliseconds() const
{
return GetElapsedDateTimeTicks()/TicksPerMillisecond;
}
HWIN_EXPORT long long Stopwatch::ElapsedTicks() const
{
long long timeElapsed = elapsedTicks;
if( isRunning)
{
long long currentTimeStamp = GetTimestamp();
long long elapsedUntilNow = currentTimeStamp - startedAt;
timeElapsed += elapsedUntilNow;
}
return timeElapsed;
}
HWIN_EXPORT long long Stopwatch::GetTimestamp()
{
if(IsHighResolution)
{
long long timestamp = 0;
QueryPerformanceCounter((LARGE_INTEGER*)×tamp);
return timestamp;
}
else
{
return DateTime::UtcNow().Ticks();
}
}
HWIN_EXPORT double Stopwatch::GetTimestampInSeconds()
{
double ts = tickFrequency * double(Stopwatch::GetTimestamp())*SecondsPerTick;
return ts;
}
HWIN_EXPORT double Stopwatch::GetTimestampInMilliseconds()
{
double ts = tickFrequency * double(Stopwatch::GetTimestamp())*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;
}
}
}
}