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);
58 DateTime DateTime::fromTimeStamp(time_t timeStamp)
61 struct tm *
const timeinfo = localtime(&timeStamp);
62 return DateTime::fromDateAndTime(timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min,
63 timeinfo->tm_sec < 60 ? timeinfo->tm_sec : 59, 0);
80 int values[6] = { 0 };
81 int *
const dayIndex = values + 2;
82 int *
const secondsIndex = values + 5;
83 int *valueIndex = values;
84 int *
const valuesEnd = values + 7;
85 double miliSecondsFact = 100.0, miliSeconds = 0.0;
86 for (
const char *strIndex = str;; ++strIndex) {
87 const char c = *strIndex;
88 if (c <= '9' && c >=
'0') {
89 if (valueIndex > secondsIndex) {
90 miliSeconds += (c -
'0') * miliSecondsFact;
91 miliSecondsFact /= 10;
94 *valueIndex += c -
'0';
96 }
else if ((c ==
'-' || c ==
':' || c ==
'/') || (c ==
'.' && (valueIndex == secondsIndex)) || (c ==
' ' && (valueIndex == dayIndex))) {
97 if (++valueIndex == valuesEnd) {
100 }
else if (c ==
'\0') {
106 return DateTime::fromDateAndTime(values[0], values[1], *dayIndex, values[3], values[4], *secondsIndex, miliSeconds);
118 std::pair<DateTime, TimeSpan> DateTime::fromIsoString(
const char *str)
120 int values[9] = { 0 };
121 int *
const dayIndex = values + 2;
122 int *
const hourIndex = values + 3;
123 int *
const secondsIndex = values + 5;
124 int *
const miliSecondsIndex = values + 6;
125 int *
const deltaHourIndex = values + 7;
126 int *valueIndex = values;
127 bool deltaNegative =
false;
128 double miliSecondsFact = 100.0, miliSeconds = 0.0;
129 for (
const char *strIndex = str;; ++strIndex) {
130 const char c = *strIndex;
131 if (c <= '9' && c >=
'0') {
132 if (valueIndex == miliSecondsIndex) {
133 miliSeconds += (c -
'0') * miliSecondsFact;
134 miliSecondsFact /= 10;
137 *valueIndex += c -
'0';
139 }
else if (c ==
'T') {
140 if (++valueIndex != hourIndex) {
143 }
else if (c ==
'-') {
144 if (valueIndex < dayIndex) {
146 }
else if (++valueIndex == deltaHourIndex) {
147 deltaNegative =
true;
151 }
else if (c ==
'.') {
152 if (valueIndex != secondsIndex) {
157 }
else if (c ==
':') {
158 if (valueIndex < hourIndex) {
160 }
else if (valueIndex == secondsIndex) {
165 }
else if ((c ==
'+') && (++valueIndex >= secondsIndex)) {
166 valueIndex = deltaHourIndex;
167 deltaNegative =
false;
168 }
else if ((c ==
'Z') && (++valueIndex >= secondsIndex)) {
169 valueIndex = deltaHourIndex + 2;
170 }
else if (c ==
'\0') {
176 auto delta(TimeSpan::fromMinutes(*deltaHourIndex * 60 + values[8]));
178 delta =
TimeSpan(-delta.totalTicks());
180 return make_pair(DateTime::fromDateAndTime(values[0], values[1], *dayIndex, *hourIndex, values[4], *secondsIndex, miliSeconds), delta);
190 stringstream s(stringstream::in | stringstream::out);
192 if (format == DateTimeOutputFormat::DateTimeAndWeekday || format == DateTimeOutputFormat::DateTimeAndShortWeekday)
193 s << printDayOfWeek(dayOfWeek(), format == DateTimeOutputFormat::DateTimeAndShortWeekday) <<
' ';
194 if (format == DateTimeOutputFormat::DateOnly || format == DateTimeOutputFormat::DateAndTime || format == DateTimeOutputFormat::DateTimeAndWeekday
195 || format == DateTimeOutputFormat::DateTimeAndShortWeekday)
196 s << setw(4) << year() <<
'-' << setw(2) << month() <<
'-' << setw(2) << day();
197 if (format == DateTimeOutputFormat::DateAndTime || format == DateTimeOutputFormat::DateTimeAndWeekday
198 || format == DateTimeOutputFormat::DateTimeAndShortWeekday)
200 if (format == DateTimeOutputFormat::TimeOnly || format == DateTimeOutputFormat::DateAndTime || format == DateTimeOutputFormat::DateTimeAndWeekday
201 || format == DateTimeOutputFormat::DateTimeAndShortWeekday) {
202 s << setw(2) << hour() <<
':' << setw(2) << minute() <<
':' << setw(2) << second();
203 int ms = millisecond();
204 if (!noMilliseconds && ms > 0) {
205 s <<
'.' << setw(3) << ms;
215 string DateTime::toIsoString(
TimeSpan timeZoneDelta)
const
217 stringstream s(stringstream::in | stringstream::out);
219 s << setw(4) << year() <<
'-' << setw(2) << month() <<
'-' << setw(2) << day() <<
'T' << setw(2) << hour() <<
':' << setw(2) << minute() <<
':'
220 << setw(2) << second();
221 const int milli(millisecond());
222 const int micro(microsecond());
223 const int nano(nanosecond());
224 if (milli || micro || nano) {
225 s <<
'.' << setw(3) << milli;
227 s << setw(3) << micro;
229 s << nano / TimeSpan::nanosecondsPerTick;
233 if (!timeZoneDelta.
isNull()) {
240 s << setw(2) << timeZoneDelta.
hours() <<
':' << setw(2) << timeZoneDelta.
minutes();
252 const char *DateTime::printDayOfWeek(
DayOfWeek dayOfWeek,
bool abbreviation)
256 case DayOfWeek::Monday:
258 case DayOfWeek::Tuesday:
260 case DayOfWeek::Wednesday:
262 case DayOfWeek::Thursday:
264 case DayOfWeek::Friday:
266 case DayOfWeek::Saturday:
268 case DayOfWeek::Sunday:
273 case DayOfWeek::Monday:
275 case DayOfWeek::Tuesday:
277 case DayOfWeek::Wednesday:
279 case DayOfWeek::Thursday:
281 case DayOfWeek::Friday:
283 case DayOfWeek::Saturday:
285 case DayOfWeek::Sunday:
292 #if defined(PLATFORM_UNIX) && !defined(PLATFORM_MAC)
300 clock_gettime(CLOCK_REALTIME, &t);
301 return DateTime(DateTime::unixEpochStart().totalTicks() + static_cast<std::uint64_t>(t.tv_sec) * TimeSpan::ticksPerSecond
302 + static_cast<std::uint64_t>(t.tv_nsec) / 100);
309 std::uint64_t DateTime::dateToTicks(
int year,
int month,
int day)
312 throw ConversionException(
"year is out of range");
315 throw ConversionException(
"month is out of range");
317 const auto *
const daysToMonth = reinterpret_cast<const int *>(isLeapYear(year) ? m_daysToMonth366 : m_daysToMonth365);
318 const int passedMonth = month - 1;
319 if (!
inRangeInclMax(day, 1, daysToMonth[month] - daysToMonth[passedMonth])) {
320 throw ConversionException(
"day is out of range");
322 const auto passedYears = static_cast<unsigned int>(year - 1);
323 const auto passedDays = static_cast<unsigned int>(day - 1);
324 return (passedYears * m_daysPerYear + passedYears / 4 - passedYears / 100 + passedYears / 400
325 + static_cast<unsigned int>(daysToMonth[passedMonth]) + passedDays)
326 * TimeSpan::ticksPerDay;
332 std::uint64_t DateTime::timeToTicks(
int hour,
int minute,
int second,
double millisecond)
335 throw ConversionException(
"hour is out of range");
338 throw ConversionException(
"minute is out of range");
341 throw ConversionException(
"second is out of range");
344 throw ConversionException(
"millisecond is out of range");
346 return static_cast<std::uint64_t>(hour * TimeSpan::ticksPerHour) + static_cast<std::uint64_t>(minute * TimeSpan::ticksPerMinute)
347 + static_cast<std::uint64_t>(second * TimeSpan::ticksPerSecond) + static_cast<std::uint64_t>(millisecond * TimeSpan::ticksPerMillisecond);
354 int DateTime::getDatePart(
DatePart part)
const
356 const int fullDays = m_ticks / TimeSpan::ticksPerDay;
357 const int full400YearBlocks = fullDays / m_daysPer400Years;
358 const int daysMinusFull400YearBlocks = fullDays - full400YearBlocks * m_daysPer400Years;
359 int full100YearBlocks = daysMinusFull400YearBlocks / m_daysPer100Years;
360 if (full100YearBlocks == 4) {
361 full100YearBlocks = 3;
363 const int daysMinusFull100YearBlocks = daysMinusFull400YearBlocks - full100YearBlocks * m_daysPer100Years;
364 const int full4YearBlocks = daysMinusFull100YearBlocks / m_daysPer4Years;
365 const int daysMinusFull4YearBlocks = daysMinusFull100YearBlocks - full4YearBlocks * m_daysPer4Years;
366 int full1YearBlocks = daysMinusFull4YearBlocks / m_daysPerYear;
367 if (full1YearBlocks == 4) {
370 if (part == DatePart::Year) {
371 return full400YearBlocks * 400 + full100YearBlocks * 100 + full4YearBlocks * 4 + full1YearBlocks + 1;
373 const int restDays = daysMinusFull4YearBlocks - full1YearBlocks * m_daysPerYear;
374 if (part == DatePart::DayOfYear) {
377 const int *
const daysToMonth = (full1YearBlocks == 3 && (full4YearBlocks != 24 || full100YearBlocks == 3)) ? m_daysToMonth366 : m_daysToMonth365;
379 while (restDays >= daysToMonth[month]) {
382 if (part == DatePart::Month) {
384 }
else if (part == DatePart::Day) {
385 return restDays - daysToMonth[month - 1] + 1;