Skip to content

Commit

Permalink
Fix off by one error in leap years before year 2000, and bad day names (
Browse files Browse the repository at this point in the history
  • Loading branch information
BillyONeal authored Apr 24, 2019
1 parent b7d3e8b commit 7c8f624
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 26 deletions.
43 changes: 17 additions & 26 deletions Release/src/utilities/asyncrt_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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<int>(secondsLeft / SecondsIn400Years);
secondsLeft -= year400 * SecondsIn400Years;
Expand All @@ -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
Expand Down Expand Up @@ -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<int>((secondsSince1900 / SecondsInDay + 3) % 7);
const auto weekday = static_cast<int>((secondsSince1900 / SecondsInDay + 1) % 7);

char outBuffer[38]; // Thu, 01 Jan 1970 00:00:00 GMT\0
// 1970-01-01T00:00:00.1234567Z\0
Expand Down
9 changes: 9 additions & 0 deletions Release/tests/functional/utils/datetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
****/

#include "stdafx.h"
#include <stdint.h>
#include <string>

using namespace utility;

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 7c8f624

Please sign in to comment.