@@ -620,14 +620,12 @@ utf16string __cdecl conversions::to_utf16string(const std::string& value) { retu
620620
621621static const int64_t NtToUnixOffsetSeconds = 11644473600 ; // diff between windows and unix epochs (seconds)
622622
623- static bool year_is_leap_year_1601 (int year )
623+ static bool year_is_leap_year_1601 (int yearsSince1601 )
624624{
625- int decimal_year = year + 1601 ;
626- return (decimal_year % 4 == 0 && (decimal_year % 100 != 0 || decimal_year % 400 == 0 ));
625+ int decimalYear = yearsSince1601 + 1601 ;
626+ return (decimalYear % 4 == 0 && (decimalYear % 100 != 0 || decimalYear % 400 == 0 ));
627627}
628628
629- static bool year_is_leap_year (int year) { return year_is_leap_year_1601 (year + 299 ); }
630-
631629static const int SecondsInMinute = 60 ;
632630static const int SecondsInHour = SecondsInMinute * 60 ;
633631static const int SecondsInDay = SecondsInHour * 24 ;
@@ -641,9 +639,6 @@ static const int SecondsInYear = SecondsInDay * DaysInYear;
641639static const int SecondsIn4Years = SecondsInDay * DaysIn4Years;
642640static const int64_t SecondsIn100Years = static_cast <int64_t >(SecondsInDay) * DaysIn100Years;
643641static const int64_t SecondsIn400Years = static_cast <int64_t >(SecondsInDay) * DaysIn400Years;
644- static const int64_t SecondsFrom1900To2001 = INT64_C(3187296000 );
645-
646- static const int64_t NtTo1900OffsetInterval = INT64_C(0x014F373BFDE04000 );
647642
648643static int count_leap_years_1601 (int yearsSince1601)
649644{
@@ -660,12 +655,6 @@ static int count_leap_years_1601(int yearsSince1601)
660655 return result;
661656}
662657
663- static int count_leap_years (const int yearsSince1900)
664- {
665- // shift into 1601, the first 400 year cycle including 1900, then subtract leap years from 1601->1900
666- return count_leap_years_1601 (yearsSince1900 + 299 ) - 72 ;
667- }
668-
669658// The following table assumes no leap year; leap year is added separately
670659static const unsigned short cumulative_days_to_month[12 ] = {
671660 0 , // Jan
@@ -749,23 +738,37 @@ static compute_year_result compute_year_1601(int64_t secondsSince1601)
749738 return {year400 * 400 + year100 * 100 + year4 * 4 + year1, secondsInt};
750739}
751740
752- static const int64_t secondsFrom1601To1900 = INT64_C(9435484800 );
753- static compute_year_result compute_year (int64_t secondsSince1900)
754- {
755- // shift to start of this 400 year cycle
756- auto partialResult = compute_year_1601 (secondsSince1900 + secondsFrom1601To1900);
757- // shift back to 1900
758- return {partialResult.year - 299 , partialResult.secondsLeftThisYear };
759- }
741+ // The constant below was calculated by running the following test program on a Windows machine:
742+ // #include <windows.h>
743+ // #include <stdio.h>
744+
745+ // int main() {
746+ // SYSTEMTIME st;
747+ // st.wYear = 9999;
748+ // st.wMonth = 12;
749+ // st.wDayOfWeek = 5;
750+ // st.wDay = 31;
751+ // st.wHour = 23;
752+ // st.wMinute = 59;
753+ // st.wSecond = 59;
754+ // st.wMilliseconds = 999;
755+
756+ // unsigned long long ft;
757+ // if (SystemTimeToFileTime(&st, reinterpret_cast<FILETIME*>(&ft))) {
758+ // printf("0x%016llX\n", ft);
759+ // } else {
760+ // puts("failed!");
761+ // }
762+ // }
760763
761764utility::string_t datetime::to_string (date_format format) const
762765{
763- if (m_interval > INT64_C (2650467743990000000 ))
766+ const int64_t interval = static_cast <int64_t >(m_interval);
767+ if (interval > INT64_C (0x24C85A5ED1C018F0 ))
764768 {
765769 throw std::out_of_range (" The requested year exceeds the year 9999." );
766770 }
767771
768- const int64_t interval = static_cast <int64_t >(m_interval);
769772 const int64_t secondsSince1601 = interval / _secondTicks; // convert to seconds
770773 const int fracSec = static_cast <int >(interval % _secondTicks);
771774
@@ -899,12 +902,12 @@ static const unsigned char max_days_in_month[12] = {
899902 31 // Dec
900903};
901904
902- static bool validate_day_month (int day, int month, int year)
905+ static bool validate_day_month_1601 (int day, int month, int year)
903906{
904907 int maxDaysThisMonth;
905908 if (month == 1 )
906909 { // Feb needs leap year testing
907- maxDaysThisMonth = 28 + year_is_leap_year (year);
910+ maxDaysThisMonth = 28 + year_is_leap_year_1601 (year);
908911 }
909912 else
910913 {
@@ -914,9 +917,9 @@ static bool validate_day_month(int day, int month, int year)
914917 return day >= 1 && day <= maxDaysThisMonth;
915918}
916919
917- static int get_year_day (int month, int monthDay, int year)
920+ static int get_year_day_1601 (int month, int monthDay, int year)
918921{
919- return cumulative_days_to_month[month] + monthDay + (year_is_leap_year (year) && month > 1 ) - 1 ;
922+ return cumulative_days_to_month[month] + monthDay + (year_is_leap_year_1601 (year) && month > 1 ) - 1 ;
920923}
921924
922925template <class CharT >
@@ -1009,7 +1012,7 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date
10091012datetime __cdecl datetime::from_string_maximum_error (const utility::string_t & dateString, date_format format)
10101013{
10111014 datetime result = datetime::maximum ();
1012- int64_t secondsSince1900 ;
1015+ int64_t secondsSince1601 ;
10131016 uint64_t fracSec = 0 ;
10141017 auto str = dateString.c_str ();
10151018 if (format == RFC_1123)
@@ -1076,19 +1079,21 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
10761079
10771080 int year = (str[0 ] - _XPLATSTR (' 0' )) * 1000 + (str[1 ] - _XPLATSTR (' 0' )) * 100 + (str[2 ] - _XPLATSTR (' 0' )) * 10 +
10781081 (str[3 ] - _XPLATSTR (' 0' ));
1079- if (year < 1900 )
1082+ if (year < 1601 )
10801083 {
10811084 return result;
10821085 }
10831086
1087+ year -= 1601 ;
1088+
10841089 // days in month validity check
1085- if (!validate_day_month (monthDay, month, year))
1090+ if (!validate_day_month_1601 (monthDay, month, year))
10861091 {
10871092 return result;
10881093 }
10891094
10901095 str += 5 ; // parsed year
1091- const int yearDay = get_year_day (month, monthDay, year);
1096+ const int yearDay = get_year_day_1601 (month, monthDay, year);
10921097
10931098 if (!ascii_isdigit2 (str[0 ]) || !ascii_isdigit (str[1 ]) || str[2 ] != _XPLATSTR (' :' ) || !ascii_isdigit5 (str[3 ]) ||
10941099 !ascii_isdigit (str[4 ]))
@@ -1132,21 +1137,20 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
11321137 return result;
11331138 }
11341139
1135- year -= 1900 ;
1136- int daysSince1900 = year * DaysInYear + count_leap_years (year) + yearDay;
1140+ int daysSince1601 = year * DaysInYear + count_leap_years_1601 (year) + yearDay;
11371141
11381142 if (parsedWeekday != 7 )
11391143 {
1140- const int actualWeekday = (daysSince1900 + 1 ) % 7 ;
1144+ const int actualWeekday = (daysSince1601 + 1 ) % 7 ;
11411145
11421146 if (parsedWeekday != actualWeekday)
11431147 {
11441148 return result;
11451149 }
11461150 }
11471151
1148- secondsSince1900 =
1149- static_cast <int64_t >(daysSince1900 ) * SecondsInDay + hour * SecondsInHour + minute * SecondsInMinute + sec;
1152+ secondsSince1601 =
1153+ static_cast <int64_t >(daysSince1601 ) * SecondsInDay + hour * SecondsInHour + minute * SecondsInMinute + sec;
11501154
11511155 if (!string_starts_with (str, " GMT" ) && !string_starts_with (str, " UT" ))
11521156 {
@@ -1186,8 +1190,8 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
11861190 return result;
11871191 }
11881192
1189- secondsSince1900 = timezone_adjust (secondsSince1900 , static_cast <unsigned char >(tzCh), tzHours, tzMinutes);
1190- if (secondsSince1900 < 0 )
1193+ secondsSince1601 = timezone_adjust (secondsSince1601 , static_cast <unsigned char >(tzCh), tzHours, tzMinutes);
1194+ if (secondsSince1601 < 0 )
11911195 {
11921196 return result;
11931197 }
@@ -1203,11 +1207,13 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
12031207
12041208 int year = (str[0 ] - _XPLATSTR (' 0' )) * 1000 + (str[1 ] - _XPLATSTR (' 0' )) * 100 + (str[2 ] - _XPLATSTR (' 0' )) * 10 +
12051209 (str[3 ] - _XPLATSTR (' 0' ));
1206- if (year < 1900 )
1210+ if (year < 1601 )
12071211 {
12081212 return result;
12091213 }
12101214
1215+ year -= 1601 ;
1216+
12111217 str += 4 ;
12121218 if (*str == _XPLATSTR (' -' ))
12131219 {
@@ -1241,24 +1247,22 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
12411247 }
12421248
12431249 int monthDay = atoi2 (str);
1244- if (!validate_day_month (monthDay, month, year))
1250+ if (!validate_day_month_1601 (monthDay, month, year))
12451251 {
12461252 return result;
12471253 }
12481254
1249- const int yearDay = get_year_day (month, monthDay, year);
1255+ const int yearDay = get_year_day_1601 (month, monthDay, year);
12501256
12511257 str += 2 ;
1252- year -= 1900 ;
1253- int daysSince1900 = year * DaysInYear + count_leap_years (year) + yearDay;
1258+ int daysSince1601 = year * DaysInYear + count_leap_years_1601 (year) + yearDay;
12541259
12551260 if (str[0 ] != _XPLATSTR (' T' ) && str[0 ] != _XPLATSTR (' t' ))
12561261 {
12571262 // No time
1258- secondsSince1900 = static_cast <int64_t >(daysSince1900 ) * SecondsInDay;
1263+ secondsSince1601 = static_cast <int64_t >(daysSince1601 ) * SecondsInDay;
12591264
1260- result.m_interval =
1261- static_cast <interval_type>(secondsSince1900 * _secondTicks + fracSec + NtTo1900OffsetInterval);
1265+ result.m_interval = static_cast <interval_type>(secondsSince1601 * _secondTicks + fracSec);
12621266 return result;
12631267 }
12641268
@@ -1347,8 +1351,8 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
13471351 }
13481352 }
13491353
1350- secondsSince1900 =
1351- static_cast <int64_t >(daysSince1900 ) * SecondsInDay + hour * SecondsInHour + minute * SecondsInMinute + sec;
1354+ secondsSince1601 =
1355+ static_cast <int64_t >(daysSince1601 ) * SecondsInDay + hour * SecondsInHour + minute * SecondsInMinute + sec;
13521356
13531357 if (str[0 ] == _XPLATSTR (' Z' ) || str[0 ] == _XPLATSTR (' z' ))
13541358 {
@@ -1363,8 +1367,8 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
13631367 return result;
13641368 }
13651369
1366- secondsSince1900 = timezone_adjust (secondsSince1900 , offsetDirection, atoi2 (str + 1 ), atoi2 (str + 4 ));
1367- if (secondsSince1900 < 0 )
1370+ secondsSince1601 = timezone_adjust (secondsSince1601 , offsetDirection, atoi2 (str + 1 ), atoi2 (str + 4 ));
1371+ if (secondsSince1601 < 0 )
13681372 {
13691373 return result;
13701374 }
@@ -1379,7 +1383,7 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
13791383 throw std::invalid_argument (" unrecognized date format" );
13801384 }
13811385
1382- result.m_interval = static_cast <interval_type>(secondsSince1900 * _secondTicks + fracSec + NtTo1900OffsetInterval );
1386+ result.m_interval = static_cast <interval_type>(secondsSince1601 * _secondTicks + fracSec);
13831387 return result;
13841388}
13851389
0 commit comments