// Copyright (c) 2019, Peter Ohler, All rights reserved. #include "util.h" #include #include #include #include #include #define SECS_PER_DAY 86400LL #define SECS_PER_YEAR 31536000LL #define SECS_PER_LEAP 31622400LL #define SECS_PER_QUAD_YEAR (SECS_PER_YEAR * 3 + SECS_PER_LEAP) #define SECS_PER_CENT (SECS_PER_QUAD_YEAR * 24 + SECS_PER_YEAR * 4) #define SECS_PER_LEAP_CENT (SECS_PER_CENT + SECS_PER_DAY) #define SECS_PER_QUAD_CENT (SECS_PER_CENT * 4 + SECS_PER_DAY) static int64_t eom_secs[] = { 2678400, // January (31) 5097600, // February (28) 2419200 2505600 7776000, // March (31) 10368000, // April (30 2592000 13046400, // May (31) 15638400, // June (30) 18316800, // July (31) 20995200, // August (31) 23587200, // September (30) 26265600, // October (31) 28857600, // November (30) 31536000, // December (31) }; static int64_t eom_leap_secs[] = { 2678400, // January (31) 5184000, // February (28) 2419200 2505600 7862400, // March (31) 10454400, // April (30 2592000 13132800, // May (31) 15724800, // June (30) 18403200, // July (31) 21081600, // August (31) 23673600, // September (30) 26352000, // October (31) 28944000, // November (30) 31622400, // December (31) }; void sec_as_time(int64_t secs, TimeInfo ti) { int64_t qc = 0; int64_t c = 0; int64_t qy = 0; int64_t y = 0; bool leap = false; int64_t *ms; int m; int shift = 0; secs += 62167219200LL; // normalize to first day of the year 0 if (secs < 0) { shift = -secs / SECS_PER_QUAD_CENT; shift++; secs += shift * SECS_PER_QUAD_CENT; } qc = secs / SECS_PER_QUAD_CENT; secs = secs - qc * SECS_PER_QUAD_CENT; if (secs < SECS_PER_LEAP) { leap = true; } else if (secs < SECS_PER_QUAD_YEAR) { if (SECS_PER_LEAP <= secs) { secs -= SECS_PER_LEAP; y = secs / SECS_PER_YEAR; secs = secs - y * SECS_PER_YEAR; y++; leap = false; } } else if (secs < SECS_PER_LEAP_CENT) { // first century in 400 years is a leap century (one extra day) qy = secs / SECS_PER_QUAD_YEAR; secs = secs - qy * SECS_PER_QUAD_YEAR; if (secs < SECS_PER_LEAP) { leap = true; } else { secs -= SECS_PER_LEAP; y = secs / SECS_PER_YEAR; secs = secs - y * SECS_PER_YEAR; y++; } } else { secs -= SECS_PER_LEAP_CENT; c = secs / SECS_PER_CENT; secs = secs - c * SECS_PER_CENT; c++; if (secs < SECS_PER_YEAR * 4) { y = secs / SECS_PER_YEAR; secs = secs - y * SECS_PER_YEAR; } else { secs -= SECS_PER_YEAR * 4; qy = secs / SECS_PER_QUAD_YEAR; secs = secs - qy * SECS_PER_QUAD_YEAR; qy++; if (secs < SECS_PER_LEAP) { leap = true; } else { secs -= SECS_PER_LEAP; y = secs / SECS_PER_YEAR; secs = secs - y * SECS_PER_YEAR; y++; } } } ti->year = (int)((qc - (int64_t)shift) * 400 + c * 100 + qy * 4 + y); if (leap) { ms = eom_leap_secs; } else { ms = eom_secs; } for (m = 1; m <= 12; m++, ms++) { if (secs < *ms) { if (1 < m) { secs -= *(ms - 1); } ti->mon = m; break; } } ti->day = (int)(secs / 86400LL); secs = secs - (int64_t)ti->day * 86400LL; ti->day++; ti->hour = (int)(secs / 3600LL); secs = secs - (int64_t)ti->hour * 3600LL; ti->min = (int)(secs / 60LL); secs = secs - (int64_t)ti->min * 60LL; ti->sec = (int)secs; }