Skip to content

Instantly share code, notes, and snippets.

@qrealka
Last active November 11, 2019 12:26
Show Gist options
  • Save qrealka/af6c765e07a8522c35717854377a292a to your computer and use it in GitHub Desktop.
Save qrealka/af6c765e07a8522c35717854377a292a to your computer and use it in GitHub Desktop.
test converters for days before 1582 (gergorian calendar)
#include <cstdio>
#include <chrono>
#include <cinttypes>
#include <ctime>
struct YMD
{
int y{};
unsigned m{};
unsigned d{};
};
using days = std::chrono::duration
<int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>::type>;
YMD civi_from_days(days dd) noexcept
{
auto z = dd.count() + 719468;
const int era = (z >= 0 ? z : z - 146096) / 146097;
const unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096]
const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399]
const int y = static_cast<int>(yoe) + era * 400;
const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365]
const unsigned mp = (5*doy + 2)/153; // [0, 11]
const unsigned d = doy - (153*mp+2)/5 + 1; // [1, 31]
const unsigned m = mp + (mp < 10 ? 3 : -9); // [1, 12]
return { y + static_cast<int>(m <= 2), m, d};
}
int main()
{
auto input_sec = std::chrono::seconds(-61999999999);
// MIDNIGHT NORMALIZATION is very risky and didn't found any documentations about it
// probably a good discussion is here https://stackoverflow.com/a/23978037
//const std::time_t t = input_sec.count();
//auto* utcTime = std::gmtime(&t);
//utcTime->tm_sec = utcTime->tm_min = utcTime->tm_hour = 0;
//input_sec = std::chrono::seconds(std::mktime(utcTime));
// I think to safe conversion date before 1582 we have to create our own calendar in ICU
// Tests for other systems:
// linux: "Tue Apr 19 09:21:41 LMT 0005"
// Javascript "Tue Apr 19 0005 09:21:41 GMT-0025"
// Python same
// Postgres : "0005-04-17T09:46:41Z"
// MySQL: just return NULL
// MSSQL: crash sometimes
const auto ymd = civi_from_days(std::chrono::duration_cast<days>(input_sec));
printf("%d / %d / %d for %" PRId64 " seconds", ymd.y, ymd.m, ymd.d, input_sec.count());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment