Skip to content

Instantly share code, notes, and snippets.

@dwilliamson
Created March 1, 2021 15:20
Show Gist options
  • Save dwilliamson/18fd198bb79bcfb17daab448a66b76ee to your computer and use it in GitHub Desktop.
Save dwilliamson/18fd198bb79bcfb17daab448a66b76ee to your computer and use it in GitHub Desktop.
#include <TinyCRT/TinyCRT.h>
#include <TinyCRT/TinyWindows.h>
namespace
{
constexpr uint64_t time100NSecsPerSec = 10000000;
uint64_t FileTimeToU64(FILETIME ft)
{
// Assume little-endian
uint64_t time;
memcpy(&time, &ft, sizeof(time));
return time / time100NSecsPerSec;
}
}
extern "C" uint64_t time(uint64_t* timer)
{
// Time now as a single integer
SYSTEMTIME st_now;
GetSystemTime(&st_now);
FILETIME ft_now;
SystemTimeToFileTime(&st_now, &ft_now);
// Reference time in 1970 as a single integer
SYSTEMTIME st_then;
st_then.wYear = 1970;
st_then.wMonth = 1;
st_then.wDayOfWeek = 0;
st_then.wDay = 1;
st_then.wHour = 0;
st_then.wMinute = 0;
st_then.wSecond = 0;
st_then.wMilliseconds = 0;
FILETIME ft_then;
SystemTimeToFileTime(&st_then, &ft_then);
// Calculate difference assuming 100-nanosecond interval resolution
uint64_t t_now = FileTimeToU64(ft_now);
uint64_t t_then = FileTimeToU64(ft_then);
uint64_t t_since = t_now - t_then;
if (timer != nullptr)
{
*timer = t_since;
}
return t_since;
}
extern "C" uint64_t _time64(uint64_t* timer)
{
return time(timer);
}
namespace
{
uint32_t CountLeapYears(uint32_t days_since_1601)
{
// (365 * 1601 / 365.0 - 1) * 0.2425
constexpr uint64_t Base = 388;
double nb_leap_years = ((days_since_1601 + 365 * 1601) / 365.0 - 1) * 0.2425;
return uint32_t(nb_leap_years) - Base;
}
int GetEndOfMonth(uint32_t month, bool is_leap_year)
{
constexpr int EndOfMonthDays[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
uint32_t end_of_month = EndOfMonthDays[month];
return is_leap_year && month > 1 ? end_of_month + 1 : end_of_month;
}
tm MakeTime64(uint64_t time)
{
// Get number of days and seconds left over
constexpr uint32_t NbSecondsPerHour = 60 * 60;
constexpr uint32_t NbSecondsPerDay = NbSecondsPerHour * 24;
auto nb_days_since_1970 = uint32_t(time / NbSecondsPerDay);
uint32_t second_this_day = time % NbSecondsPerDay;
// Make day count relative to 1601
constexpr uint32_t NbDaysIn4Years = 4 * 365 + 1;
constexpr uint32_t NbDaysInCentury = 25 * NbDaysIn4Years - 1;
uint32_t nb_days_since_1601 = nb_days_since_1970 + (3 * NbDaysInCentury + 17 * NbDaysIn4Years + 365);
// Count number of leap years/days so far
uint32_t nb_leap_days = CountLeapYears(nb_days_since_1601 + 307);
uint32_t nb_leap_years = CountLeapYears(nb_days_since_1601);
bool is_leap_year = nb_leap_days > nb_leap_years;
// Get year relative to 1900
tm t;
uint32_t year_since_1601 = (nb_days_since_1601 - nb_leap_days) / 365;
t.tm_year = year_since_1601 - 299;
// Get number of days since the start of the year
t.tm_yday = nb_days_since_1601 - (year_since_1601 * 365 + nb_leap_years);
// Search for the current month
uint32_t month = 0;
while (t.tm_yday >= GetEndOfMonth(month + 1, is_leap_year))
{
month++;
}
// Populate output time struct
uint32_t second_this_hour = second_this_day % NbSecondsPerHour;
t.tm_mon = month;
t.tm_mday = 1 + t.tm_yday - GetEndOfMonth(month, is_leap_year);
t.tm_wday = (nb_days_since_1601 + 1) % 7;
t.tm_hour = second_this_day / NbSecondsPerHour;
t.tm_min = second_this_hour / 60;
t.tm_sec = second_this_hour % 60;
t.tm_isdst = 0;
return t;
}
}
extern "C" tm* gmtime(const time_t* source_time)
{
assert(source_time != nullptr);
static tm t;
t = MakeTime64(*source_time);
return &t;
}
extern "C" tm* _gmtime64(const uint64_t* source_time)
{
assert(source_time != nullptr);
static tm t;
t = MakeTime64(*source_time);
return &t;
}
extern "C" int _gmtime64_s(struct tm* dest, const uint64_t* source_time)
{
if (dest == nullptr)
{
return EINVAL;
}
*dest = {-1, -1, -1, -1, -1, -1, -1, -1, -1};
if (source_time == nullptr)
{
return EINVAL;
}
*dest = MakeTime64(*source_time);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment