3 #include "../conversion/stringbuilder.h"
4 #include "../conversion/stringconversion.h"
14 const int DateTime::m_daysPerYear = 365;
15 const int DateTime::m_daysPer4Years = 1461;
16 const int DateTime::m_daysPer100Years = 36524;
17 const int DateTime::m_daysPer400Years = 146097;
18 const int DateTime::m_daysTo1601 = 584388;
19 const int DateTime::m_daysTo1899 = 693593;
20 const int DateTime::m_daysTo10000 = 3652059;
21 const int DateTime::m_daysToMonth365[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
22 const int DateTime::m_daysToMonth366[13] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
23 const int DateTime::m_daysInMonth365[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
24 const int DateTime::m_daysInMonth366[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
26 template <
typename num1,
typename num2,
typename num3> constexpr
bool inRangeInclMax(num1 val, num2
min, num3
max)
28 return (val) >= (
min) && (val) <= (
max);
31 template <
typename num1,
typename num2,
typename num3> constexpr
bool inRangeExclMax(num1 val, num2
min, num3
max)
33 return (val) >= (
min) && (val) < (
max);
59 DateTime DateTime::fromTimeStamp(time_t timeStamp)
62 struct tm *
const timeinfo = localtime(&timeStamp);
63 return DateTime::fromDateAndTime(timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min,
64 timeinfo->tm_sec < 60 ? timeinfo->tm_sec : 59, 0);
81 int values[6] = { 0 };
82 int *
const dayIndex = values + 2;
83 int *
const secondsIndex = values + 5;
84 int *valueIndex = values;
85 int *
const valuesEnd = values + 7;
86 double miliSecondsFact = 100.0, miliSeconds = 0.0;
87 for (
const char *strIndex = str;; ++strIndex) {
88 const char c = *strIndex;
89 if (c <= '9' && c >=
'0') {
90 if (valueIndex > secondsIndex) {
91 miliSeconds += (c -
'0') * miliSecondsFact;
92 miliSecondsFact /= 10;
95 *valueIndex += c -
'0';
97 }
else if ((c ==
'-' || c ==
':' || c ==
'/') || (c ==
'.' && (valueIndex == secondsIndex)) || (c ==
' ' && (valueIndex == dayIndex))) {
98 if (++valueIndex == valuesEnd) {
101 }
else if (c ==
'\0') {
107 return DateTime::fromDateAndTime(values[0], values[1], *dayIndex, values[3], values[4], *secondsIndex, miliSeconds);
119 std::pair<DateTime, TimeSpan> DateTime::fromIsoString(
const char *str)
121 int values[9] = { 0 };
122 int *
const dayIndex = values + 2;
123 int *
const hourIndex = values + 3;
124 int *
const secondsIndex = values + 5;
125 int *
const miliSecondsIndex = values + 6;
126 int *
const deltaHourIndex = values + 7;
127 int *valueIndex = values;
128 bool deltaNegative =
false;
129 double miliSecondsFact = 100.0, miliSeconds = 0.0;
130 for (
const char *strIndex = str;; ++strIndex) {
131 const char c = *strIndex;
132 if (c <= '9' && c >=
'0') {
133 if (valueIndex == miliSecondsIndex) {
134 miliSeconds += (c -
'0') * miliSecondsFact;
135 miliSecondsFact /= 10;
138 *valueIndex += c -
'0';
140 }
else if (c ==
'T') {
141 if (++valueIndex != hourIndex) {
144 }
else if (c ==
'-') {
145 if (valueIndex < dayIndex) {
147 }
else if (++valueIndex == deltaHourIndex) {
148 deltaNegative =
true;
152 }
else if (c ==
'.') {
153 if (valueIndex != secondsIndex) {
158 }
else if (c ==
':') {
159 if (valueIndex < hourIndex) {
161 }
else if (valueIndex == secondsIndex) {
166 }
else if ((c ==
'+') && (++valueIndex >= secondsIndex)) {
167 valueIndex = deltaHourIndex;
168 deltaNegative =
false;
169 }
else if ((c ==
'Z') && (++valueIndex >= secondsIndex)) {
170 valueIndex = deltaHourIndex + 2;
171 }
else if (c ==
'\0') {
177 auto delta(TimeSpan::fromMinutes(*deltaHourIndex * 60 + values[8]));
179 delta =
TimeSpan(-delta.totalTicks());
181 return make_pair(DateTime::fromDateAndTime(values[0], values[1], *dayIndex, *hourIndex, values[4], *secondsIndex, miliSeconds), delta);
191 stringstream s(stringstream::in | stringstream::out);
193 if (format == DateTimeOutputFormat::DateTimeAndWeekday || format == DateTimeOutputFormat::DateTimeAndShortWeekday)
194 s << printDayOfWeek(dayOfWeek(), format == DateTimeOutputFormat::DateTimeAndShortWeekday) <<
' ';
195 if (format == DateTimeOutputFormat::DateOnly || format == DateTimeOutputFormat::DateAndTime || format == DateTimeOutputFormat::DateTimeAndWeekday
196 || format == DateTimeOutputFormat::DateTimeAndShortWeekday)
197 s << setw(4) << year() <<
'-' << setw(2) << month() <<
'-' << setw(2) << day();
198 if (format == DateTimeOutputFormat::DateAndTime || format == DateTimeOutputFormat::DateTimeAndWeekday
199 || format == DateTimeOutputFormat::DateTimeAndShortWeekday)
201 if (format == DateTimeOutputFormat::TimeOnly || format == DateTimeOutputFormat::DateAndTime || format == DateTimeOutputFormat::DateTimeAndWeekday
202 || format == DateTimeOutputFormat::DateTimeAndShortWeekday) {
203 s << setw(2) << hour() <<
':' << setw(2) << minute() <<
':' << setw(2) << second();
204 int ms = millisecond();
205 if (!noMilliseconds && ms > 0) {
206 s <<
'.' << setw(3) << ms;
216 string DateTime::toIsoString(
TimeSpan timeZoneDelta)
const
218 stringstream s(stringstream::in | stringstream::out);
220 s << setw(4) << year() <<
'-' << setw(2) << month() <<
'-' << setw(2) << day() <<
'T' << setw(2) << hour() <<
':' << setw(2) << minute() <<
':'
221 << setw(2) << second();
222 const int milli(millisecond());
223 const int micro(microsecond());
224 const int nano(nanosecond());
225 if (milli || micro || nano) {
226 s <<
'.' << setw(3) << milli;
228 s << setw(3) << micro;
230 s << nano / TimeSpan::nanosecondsPerTick;
234 if (!timeZoneDelta.
isNull()) {
241 s << setw(2) << timeZoneDelta.
hours() <<
':' << setw(2) << timeZoneDelta.
minutes();
253 const char *DateTime::printDayOfWeek(
DayOfWeek dayOfWeek,
bool abbreviation)
257 case DayOfWeek::Monday:
259 case DayOfWeek::Tuesday:
261 case DayOfWeek::Wednesday:
263 case DayOfWeek::Thursday:
265 case DayOfWeek::Friday:
267 case DayOfWeek::Saturday:
269 case DayOfWeek::Sunday:
274 case DayOfWeek::Monday:
276 case DayOfWeek::Tuesday:
278 case DayOfWeek::Wednesday:
280 case DayOfWeek::Thursday:
282 case DayOfWeek::Friday:
284 case DayOfWeek::Saturday:
286 case DayOfWeek::Sunday:
293 #if defined(PLATFORM_UNIX) && !defined(PLATFORM_MAC)
301 clock_gettime(CLOCK_REALTIME, &t);
302 return DateTime(DateTime::unixEpochStart().totalTicks() +
static_cast<std::uint64_t
>(t.tv_sec) * TimeSpan::ticksPerSecond
303 +
static_cast<std::uint64_t
>(t.tv_nsec) / 100);
310 std::uint64_t DateTime::dateToTicks(
int year,
int month,
int day)
313 throw ConversionException(
"year is out of range");
316 throw ConversionException(
"month is out of range");
318 const auto *
const daysToMonth =
reinterpret_cast<const int *
>(isLeapYear(year) ? m_daysToMonth366 : m_daysToMonth365);
319 const int passedMonth = month - 1;
320 if (!
inRangeInclMax(day, 1, daysToMonth[month] - daysToMonth[passedMonth])) {
321 throw ConversionException(
"day is out of range");
323 const auto passedYears =
static_cast<unsigned int>(year - 1);
324 const auto passedDays =
static_cast<unsigned int>(day - 1);
325 return (passedYears * m_daysPerYear + passedYears / 4 - passedYears / 100 + passedYears / 400
326 +
static_cast<unsigned int>(daysToMonth[passedMonth]) + passedDays)
327 * TimeSpan::ticksPerDay;
333 std::uint64_t DateTime::timeToTicks(
int hour,
int minute,
int second,
double millisecond)
336 throw ConversionException(
"hour is out of range");
339 throw ConversionException(
"minute is out of range");
342 throw ConversionException(
"second is out of range");
345 throw ConversionException(
"millisecond is out of range");
347 return static_cast<std::uint64_t
>(hour * TimeSpan::ticksPerHour) +
static_cast<std::uint64_t
>(minute * TimeSpan::ticksPerMinute)
348 +
static_cast<std::uint64_t
>(second * TimeSpan::ticksPerSecond) +
static_cast<std::uint64_t
>(millisecond * TimeSpan::ticksPerMillisecond);
355 int DateTime::getDatePart(
DatePart part)
const
357 const int fullDays = m_ticks / TimeSpan::ticksPerDay;
358 const int full400YearBlocks = fullDays / m_daysPer400Years;
359 const int daysMinusFull400YearBlocks = fullDays - full400YearBlocks * m_daysPer400Years;
360 int full100YearBlocks = daysMinusFull400YearBlocks / m_daysPer100Years;
361 if (full100YearBlocks == 4) {
362 full100YearBlocks = 3;
364 const int daysMinusFull100YearBlocks = daysMinusFull400YearBlocks - full100YearBlocks * m_daysPer100Years;
365 const int full4YearBlocks = daysMinusFull100YearBlocks / m_daysPer4Years;
366 const int daysMinusFull4YearBlocks = daysMinusFull100YearBlocks - full4YearBlocks * m_daysPer4Years;
367 int full1YearBlocks = daysMinusFull4YearBlocks / m_daysPerYear;
368 if (full1YearBlocks == 4) {
371 if (part == DatePart::Year) {
372 return full400YearBlocks * 400 + full100YearBlocks * 100 + full4YearBlocks * 4 + full1YearBlocks + 1;
374 const int restDays = daysMinusFull4YearBlocks - full1YearBlocks * m_daysPerYear;
375 if (part == DatePart::DayOfYear) {
378 const int *
const daysToMonth = (full1YearBlocks == 3 && (full4YearBlocks != 24 || full100YearBlocks == 3)) ? m_daysToMonth366 : m_daysToMonth365;
380 while (restDays >= daysToMonth[month]) {
383 if (part == DatePart::Month) {
385 }
else if (part == DatePart::Day) {
386 return restDays - daysToMonth[month - 1] + 1;