#include #include #include #include #include #include #include #include #include #define SECONDS_PER_DAY 86400 static int isleap(int year) { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } static int make_yday(int year, int month) { static const short int upto[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; int yd; yd = upto[month - 1]; if (month > 2 && isleap(year)) yd++; return yd; } static int day_of_week(int year, int mon, int day) { static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 }; year -= mon < 3; return (year + year / 4 - year / 100 + year / 400 + t[mon - 1] + day) % 7; } // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16 static constexpr u64 broken_down_to_unix(u64 year, u64 yday, u64 hour, u64 min, u64 sec) { return sec + min * 60 + hour * 3600 + yday * 86400 + (year - 70) * 31536000 + ((year - 69) / 4) * 86400 - ((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400; } static void time_to_struct_tm(time_t time, struct tm* result) { result->tm_isdst = 0; // No DST/timezone support for now. int year = 1970; while (time > 0) { time_t seconds_in_year = (isleap(year) ? 366 : 365) * SECONDS_PER_DAY; if (seconds_in_year <= time) { year++; time -= seconds_in_year; continue; } break; } int month_days[] = { 31, isleap(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int month = 0; while (1) { time_t seconds_in_month = month_days[month] * SECONDS_PER_DAY; if (seconds_in_month <= time) { month++; time -= seconds_in_month; continue; } break; } int day = (int)(time / SECONDS_PER_DAY); time %= SECONDS_PER_DAY; check(day < month_days[month]); int hour = (int)(time / 3600); time %= 3600; int min = (int)(time / 60); time %= 60; result->tm_year = year - 1900; result->tm_mon = month; result->tm_yday = make_yday(year, month + 1) + day; result->tm_wday = day_of_week(year, month + 1, day + 1); result->tm_mday = day + 1; result->tm_hour = hour; result->tm_min = min; result->tm_sec = (int)time; } extern "C" { int clock_gettime(clockid_t id, struct timespec* ts) { long rc = syscall(SYS_clock_gettime, id, ts); __errno_return(rc, int); } time_t time(time_t* tp) { struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) < 0) return (time_t)-1; if (tp) *tp = ts.tv_sec; return ts.tv_sec; } struct tm* localtime_r(const time_t* tp, struct tm* out) { time_to_struct_tm(*tp, out); return out; } struct tm* gmtime_r(const time_t* tp, struct tm* out) { time_to_struct_tm(*tp, out); return out; } struct tm* localtime(const time_t* tp) { static struct tm out; return localtime_r(tp, &out); } struct tm* gmtime(const time_t* tp) { static struct tm out; return gmtime_r(tp, &out); } char* asctime_r(const struct tm* tm, char buf[26]) { strftime(buf, 26, "%a %b %d %H:%M:%S %Y\n", tm); return buf; } char* asctime(const struct tm* tm) { static char buf[26]; return asctime_r(tm, buf); } char* ctime_r(const time_t* tp, char buf[26]) { struct tm out; return asctime_r(localtime_r(tp, &out), buf); } char* ctime(const time_t* tp) { return asctime(localtime(tp)); } int gettimeofday(struct timeval* tp, void* timezone) { if (timezone) { fputs("gettimeofday: timezone was not NULL, abort\n", stderr); abort(); } struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) < 0) return -1; tp->tv_sec = ts.tv_sec; tp->tv_usec = ts.tv_nsec / 1000; return 0; } time_t mktime(struct tm* tm) { // FIXME: Check if the tm structure is valid. time_t result = broken_down_to_unix(tm->tm_year, make_yday(tm->tm_year, tm->tm_mon + 1) + (tm->tm_mday - 1), tm->tm_hour, tm->tm_min, tm->tm_sec); tm->tm_yday = make_yday(tm->tm_year + 1900, tm->tm_mon + 1) + (tm->tm_mday - 1); tm->tm_wday = day_of_week(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); return result; } double difftime(time_t a, time_t b) { return (double)(a - b); } clock_t clock(void) { struct rusage ru; if (getrusage(RUSAGE_SELF, &ru) < 0) return (clock_t)-1; return ru.ru_utime.tv_sec * CLOCKS_PER_SEC + ru.ru_utime.tv_usec; } }