Skip to content

Commit 7c8f624

Browse files
authored
Fix off by one error in leap years before year 2000, and bad day names (#1120)
1 parent b7d3e8b commit 7c8f624

File tree

2 files changed

+26
-26
lines changed

2 files changed

+26
-26
lines changed

Release/src/utilities/asyncrt_utils.cpp

+17-26
Original file line numberDiff line numberDiff line change
@@ -639,26 +639,22 @@ static const int64_t SecondsFrom1900To2001 = INT64_C(3187296000);
639639

640640
static const int64_t NtTo1900OffsetInterval = INT64_C(0x014F373BFDE04000);
641641

642-
static int count_leap_years(int yearsSince1900)
642+
static int count_leap_years(const int yearsSince1900)
643643
{
644-
int result = 0;
645-
if (yearsSince1900 > 101)
646-
{
647-
result += 25;
648-
yearsSince1900 -= 101;
649-
}
644+
int tmpYears = yearsSince1900 + 299; // shift into 1601, the first 400 year cycle including 1900
650645

651-
int year400 = yearsSince1900 / 400;
652-
yearsSince1900 -= year400 * 400;
653-
result += year400 * 97;
646+
int year400 = tmpYears / 400;
647+
tmpYears -= year400 * 400;
648+
int result = year400 * 97;
654649

655-
int year100 = yearsSince1900 / 100;
656-
yearsSince1900 -= year100 * 100;
650+
int year100 = tmpYears / 100;
651+
tmpYears -= year100 * 100;
657652
result += year100 * 24;
658653

659-
int year4 = yearsSince1900 / 4;
660-
yearsSince1900 -= year4 * 4;
661-
result += year4;
654+
result += tmpYears / 4;
655+
656+
// subtract off leap years from 1601
657+
result -= 72;
662658

663659
return result;
664660
}
@@ -724,16 +720,11 @@ struct compute_year_result
724720
int secondsLeftThisYear;
725721
};
726722

723+
static const int64_t secondsFrom1601To1900 = INT64_C(9435484800);
724+
727725
static compute_year_result compute_year(int64_t secondsSince1900)
728726
{
729-
int year = 0;
730-
int64_t secondsLeft = secondsSince1900;
731-
if (secondsSince1900 >= SecondsFrom1900To2001)
732-
{
733-
// After year 2001, shift there and start normal 400 year cycle
734-
year += 101;
735-
secondsLeft -= SecondsFrom1900To2001;
736-
}
727+
int64_t secondsLeft = secondsSince1900 + secondsFrom1601To1900; // shift to start of this 400 year cycle
737728

738729
int year400 = static_cast<int>(secondsLeft / SecondsIn400Years);
739730
secondsLeft -= year400 * SecondsIn400Years;
@@ -747,8 +738,8 @@ static compute_year_result compute_year(int64_t secondsSince1900)
747738
int year1 = secondsInt / SecondsInYear;
748739
secondsInt -= year1 * SecondsInYear;
749740

750-
year += year400 * 400 + year100 * 100 + year4 * 4 + year1;
751-
return {year, secondsInt};
741+
// shift back to 1900 base from 1601:
742+
return {year400 * 400 + year100 * 100 + year4 * 4 + year1 - 299, secondsInt};
752743
}
753744

754745
utility::string_t datetime::to_string(date_format format) const
@@ -779,7 +770,7 @@ utility::string_t datetime::to_string(date_format format) const
779770
}
780771

781772
const auto monthDay = yearDay - monthTable[month] + 1;
782-
const auto weekday = static_cast<int>((secondsSince1900 / SecondsInDay + 3) % 7);
773+
const auto weekday = static_cast<int>((secondsSince1900 / SecondsInDay + 1) % 7);
783774

784775
char outBuffer[38]; // Thu, 01 Jan 1970 00:00:00 GMT\0
785776
// 1970-01-01T00:00:00.1234567Z\0

Release/tests/functional/utils/datetime.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
****/
1111

1212
#include "stdafx.h"
13+
#include <stdint.h>
14+
#include <string>
1315

1416
using namespace utility;
1517

@@ -131,6 +133,13 @@ SUITE(datetime)
131133
TestDateTimeRoundtrip(_XPLATSTR("9999-12-31T23:59:59Z"));
132134
}
133135

136+
TEST(emitting_time_correct_day) {
137+
const auto test = utility::datetime() + UINT64_C(132004507640000000); // 2019-04-22T23:52:44 is a Monday
138+
const auto actual = test.to_string(utility::datetime::RFC_1123);
139+
const utility::string_t expected(_XPLATSTR("Mon"));
140+
VERIFY_ARE_EQUAL(actual.substr(0, 3), expected);
141+
}
142+
134143
void TestRfc1123IsTimeT(const utility::char_t* str, uint64_t t)
135144
{
136145
datetime dt = datetime::from_string(str, utility::datetime::RFC_1123);

0 commit comments

Comments
 (0)