@@ -620,14 +620,12 @@ utf16string __cdecl conversions::to_utf16string(const std::string& value) { retu
620
620
621
621
static const int64_t NtToUnixOffsetSeconds = 11644473600 ; // diff between windows and unix epochs (seconds)
622
622
623
- static bool year_is_leap_year_1601 (int year )
623
+ static bool year_is_leap_year_1601 (int yearsSince1601 )
624
624
{
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 ));
627
627
}
628
628
629
- static bool year_is_leap_year (int year) { return year_is_leap_year_1601 (year + 299 ); }
630
-
631
629
static const int SecondsInMinute = 60 ;
632
630
static const int SecondsInHour = SecondsInMinute * 60 ;
633
631
static const int SecondsInDay = SecondsInHour * 24 ;
@@ -641,9 +639,6 @@ static const int SecondsInYear = SecondsInDay * DaysInYear;
641
639
static const int SecondsIn4Years = SecondsInDay * DaysIn4Years;
642
640
static const int64_t SecondsIn100Years = static_cast <int64_t >(SecondsInDay) * DaysIn100Years;
643
641
static 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 );
647
642
648
643
static int count_leap_years_1601 (int yearsSince1601)
649
644
{
@@ -660,12 +655,6 @@ static int count_leap_years_1601(int yearsSince1601)
660
655
return result;
661
656
}
662
657
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
-
669
658
// The following table assumes no leap year; leap year is added separately
670
659
static const unsigned short cumulative_days_to_month[12 ] = {
671
660
0 , // Jan
@@ -749,23 +738,37 @@ static compute_year_result compute_year_1601(int64_t secondsSince1601)
749
738
return {year400 * 400 + year100 * 100 + year4 * 4 + year1, secondsInt};
750
739
}
751
740
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
+ // }
760
763
761
764
utility::string_t datetime::to_string (date_format format) const
762
765
{
763
- if (m_interval > INT64_C (2650467743990000000 ))
766
+ const int64_t interval = static_cast <int64_t >(m_interval);
767
+ if (interval > INT64_C (0x24C85A5ED1C018F0 ))
764
768
{
765
769
throw std::out_of_range (" The requested year exceeds the year 9999." );
766
770
}
767
771
768
- const int64_t interval = static_cast <int64_t >(m_interval);
769
772
const int64_t secondsSince1601 = interval / _secondTicks; // convert to seconds
770
773
const int fracSec = static_cast <int >(interval % _secondTicks);
771
774
@@ -899,12 +902,12 @@ static const unsigned char max_days_in_month[12] = {
899
902
31 // Dec
900
903
};
901
904
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)
903
906
{
904
907
int maxDaysThisMonth;
905
908
if (month == 1 )
906
909
{ // Feb needs leap year testing
907
- maxDaysThisMonth = 28 + year_is_leap_year (year);
910
+ maxDaysThisMonth = 28 + year_is_leap_year_1601 (year);
908
911
}
909
912
else
910
913
{
@@ -914,9 +917,9 @@ static bool validate_day_month(int day, int month, int year)
914
917
return day >= 1 && day <= maxDaysThisMonth;
915
918
}
916
919
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)
918
921
{
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 ;
920
923
}
921
924
922
925
template <class CharT >
@@ -1009,7 +1012,7 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date
1009
1012
datetime __cdecl datetime::from_string_maximum_error (const utility::string_t & dateString, date_format format)
1010
1013
{
1011
1014
datetime result = datetime::maximum ();
1012
- int64_t secondsSince1900 ;
1015
+ int64_t secondsSince1601 ;
1013
1016
uint64_t fracSec = 0 ;
1014
1017
auto str = dateString.c_str ();
1015
1018
if (format == RFC_1123)
@@ -1076,19 +1079,21 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
1076
1079
1077
1080
int year = (str[0 ] - _XPLATSTR (' 0' )) * 1000 + (str[1 ] - _XPLATSTR (' 0' )) * 100 + (str[2 ] - _XPLATSTR (' 0' )) * 10 +
1078
1081
(str[3 ] - _XPLATSTR (' 0' ));
1079
- if (year < 1900 )
1082
+ if (year < 1601 )
1080
1083
{
1081
1084
return result;
1082
1085
}
1083
1086
1087
+ year -= 1601 ;
1088
+
1084
1089
// days in month validity check
1085
- if (!validate_day_month (monthDay, month, year))
1090
+ if (!validate_day_month_1601 (monthDay, month, year))
1086
1091
{
1087
1092
return result;
1088
1093
}
1089
1094
1090
1095
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);
1092
1097
1093
1098
if (!ascii_isdigit2 (str[0 ]) || !ascii_isdigit (str[1 ]) || str[2 ] != _XPLATSTR (' :' ) || !ascii_isdigit5 (str[3 ]) ||
1094
1099
!ascii_isdigit (str[4 ]))
@@ -1132,21 +1137,20 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
1132
1137
return result;
1133
1138
}
1134
1139
1135
- year -= 1900 ;
1136
- int daysSince1900 = year * DaysInYear + count_leap_years (year) + yearDay;
1140
+ int daysSince1601 = year * DaysInYear + count_leap_years_1601 (year) + yearDay;
1137
1141
1138
1142
if (parsedWeekday != 7 )
1139
1143
{
1140
- const int actualWeekday = (daysSince1900 + 1 ) % 7 ;
1144
+ const int actualWeekday = (daysSince1601 + 1 ) % 7 ;
1141
1145
1142
1146
if (parsedWeekday != actualWeekday)
1143
1147
{
1144
1148
return result;
1145
1149
}
1146
1150
}
1147
1151
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;
1150
1154
1151
1155
if (!string_starts_with (str, " GMT" ) && !string_starts_with (str, " UT" ))
1152
1156
{
@@ -1186,8 +1190,8 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
1186
1190
return result;
1187
1191
}
1188
1192
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 )
1191
1195
{
1192
1196
return result;
1193
1197
}
@@ -1203,11 +1207,13 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
1203
1207
1204
1208
int year = (str[0 ] - _XPLATSTR (' 0' )) * 1000 + (str[1 ] - _XPLATSTR (' 0' )) * 100 + (str[2 ] - _XPLATSTR (' 0' )) * 10 +
1205
1209
(str[3 ] - _XPLATSTR (' 0' ));
1206
- if (year < 1900 )
1210
+ if (year < 1601 )
1207
1211
{
1208
1212
return result;
1209
1213
}
1210
1214
1215
+ year -= 1601 ;
1216
+
1211
1217
str += 4 ;
1212
1218
if (*str == _XPLATSTR (' -' ))
1213
1219
{
@@ -1241,24 +1247,22 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
1241
1247
}
1242
1248
1243
1249
int monthDay = atoi2 (str);
1244
- if (!validate_day_month (monthDay, month, year))
1250
+ if (!validate_day_month_1601 (monthDay, month, year))
1245
1251
{
1246
1252
return result;
1247
1253
}
1248
1254
1249
- const int yearDay = get_year_day (month, monthDay, year);
1255
+ const int yearDay = get_year_day_1601 (month, monthDay, year);
1250
1256
1251
1257
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;
1254
1259
1255
1260
if (str[0 ] != _XPLATSTR (' T' ) && str[0 ] != _XPLATSTR (' t' ))
1256
1261
{
1257
1262
// No time
1258
- secondsSince1900 = static_cast <int64_t >(daysSince1900 ) * SecondsInDay;
1263
+ secondsSince1601 = static_cast <int64_t >(daysSince1601 ) * SecondsInDay;
1259
1264
1260
- result.m_interval =
1261
- static_cast <interval_type>(secondsSince1900 * _secondTicks + fracSec + NtTo1900OffsetInterval);
1265
+ result.m_interval = static_cast <interval_type>(secondsSince1601 * _secondTicks + fracSec);
1262
1266
return result;
1263
1267
}
1264
1268
@@ -1347,8 +1351,8 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
1347
1351
}
1348
1352
}
1349
1353
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;
1352
1356
1353
1357
if (str[0 ] == _XPLATSTR (' Z' ) || str[0 ] == _XPLATSTR (' z' ))
1354
1358
{
@@ -1363,8 +1367,8 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
1363
1367
return result;
1364
1368
}
1365
1369
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 )
1368
1372
{
1369
1373
return result;
1370
1374
}
@@ -1379,7 +1383,7 @@ datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& da
1379
1383
throw std::invalid_argument (" unrecognized date format" );
1380
1384
}
1381
1385
1382
- result.m_interval = static_cast <interval_type>(secondsSince1900 * _secondTicks + fracSec + NtTo1900OffsetInterval );
1386
+ result.m_interval = static_cast <interval_type>(secondsSince1601 * _secondTicks + fracSec);
1383
1387
return result;
1384
1388
}
1385
1389
0 commit comments