diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index d720bdc70f..5263c8d5d5 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -639,26 +639,22 @@ static const int64_t SecondsFrom1900To2001 = INT64_C(3187296000); static const int64_t NtTo1900OffsetInterval = INT64_C(0x014F373BFDE04000); -static int count_leap_years(int yearsSince1900) +static int count_leap_years(const int yearsSince1900) { - int result = 0; - if (yearsSince1900 > 101) - { - result += 25; - yearsSince1900 -= 101; - } + int tmpYears = yearsSince1900 + 299; // shift into 1601, the first 400 year cycle including 1900 - int year400 = yearsSince1900 / 400; - yearsSince1900 -= year400 * 400; - result += year400 * 97; + int year400 = tmpYears / 400; + tmpYears -= year400 * 400; + int result = year400 * 97; - int year100 = yearsSince1900 / 100; - yearsSince1900 -= year100 * 100; + int year100 = tmpYears / 100; + tmpYears -= year100 * 100; result += year100 * 24; - int year4 = yearsSince1900 / 4; - yearsSince1900 -= year4 * 4; - result += year4; + result += tmpYears / 4; + + // subtract off leap years from 1601 + result -= 72; return result; } @@ -724,16 +720,11 @@ struct compute_year_result int secondsLeftThisYear; }; +static const int64_t secondsFrom1601To1900 = INT64_C(9435484800); + static compute_year_result compute_year(int64_t secondsSince1900) { - int year = 0; - int64_t secondsLeft = secondsSince1900; - if (secondsSince1900 >= SecondsFrom1900To2001) - { - // After year 2001, shift there and start normal 400 year cycle - year += 101; - secondsLeft -= SecondsFrom1900To2001; - } + int64_t secondsLeft = secondsSince1900 + secondsFrom1601To1900; // shift to start of this 400 year cycle int year400 = static_cast(secondsLeft / SecondsIn400Years); secondsLeft -= year400 * SecondsIn400Years; @@ -747,8 +738,8 @@ static compute_year_result compute_year(int64_t secondsSince1900) int year1 = secondsInt / SecondsInYear; secondsInt -= year1 * SecondsInYear; - year += year400 * 400 + year100 * 100 + year4 * 4 + year1; - return {year, secondsInt}; + // shift back to 1900 base from 1601: + return {year400 * 400 + year100 * 100 + year4 * 4 + year1 - 299, secondsInt}; } utility::string_t datetime::to_string(date_format format) const @@ -779,7 +770,7 @@ utility::string_t datetime::to_string(date_format format) const } const auto monthDay = yearDay - monthTable[month] + 1; - const auto weekday = static_cast((secondsSince1900 / SecondsInDay + 3) % 7); + const auto weekday = static_cast((secondsSince1900 / SecondsInDay + 1) % 7); char outBuffer[38]; // Thu, 01 Jan 1970 00:00:00 GMT\0 // 1970-01-01T00:00:00.1234567Z\0 diff --git a/Release/tests/functional/utils/datetime.cpp b/Release/tests/functional/utils/datetime.cpp index 871dc3462a..33d532a098 100644 --- a/Release/tests/functional/utils/datetime.cpp +++ b/Release/tests/functional/utils/datetime.cpp @@ -10,6 +10,8 @@ ****/ #include "stdafx.h" +#include +#include using namespace utility; @@ -131,6 +133,13 @@ SUITE(datetime) TestDateTimeRoundtrip(_XPLATSTR("9999-12-31T23:59:59Z")); } + TEST(emitting_time_correct_day) { + const auto test = utility::datetime() + UINT64_C(132004507640000000); // 2019-04-22T23:52:44 is a Monday + const auto actual = test.to_string(utility::datetime::RFC_1123); + const utility::string_t expected(_XPLATSTR("Mon")); + VERIFY_ARE_EQUAL(actual.substr(0, 3), expected); + } + void TestRfc1123IsTimeT(const utility::char_t* str, uint64_t t) { datetime dt = datetime::from_string(str, utility::datetime::RFC_1123);