diff --git a/inc/locale.h b/inc/locale.h index a21b81c..8241c0e 100644 --- a/inc/locale.h +++ b/inc/locale.h @@ -4,35 +4,6 @@ #define _COL_IGNORE_SPACE 0x1 #define _COL_IGNORE_SYMBOL 0x2 -struct lconv { - // LC_NUMERIC - char *decimal_point; // "." - char *thousands_sep; // "" - char *grouping; // "" - // LC_MONETARY - char *mon_decimal_point; // "" - char *mon_thousands_sep; // "" - char *mon_grouping; // "" - char *positive_sign; // "" - char *negative_sign; // "" - char *currency_symbol; // "" - char frac_digits; // CHAR_MAX - char p_cs_precedes; // CHAR_MAX - char n_cs_precedes; // CHAR_MAX - char p_sep_by_space; // CHAR_MAX - char n_sep_by_space; // CHAR_MAX - char p_sign_posn; // CHAR_MAX - char n_sign_posn; // CHAR_MAX - char *int_curr_symbol; // "" - char int_frac_digits; // CHAR_MAX - char int_p_cs_precedes; // CHAR_MAX - char int_n_cs_precedes; // CHAR_MAX - char int_p_sep_by_space; // CHAR_MAX - char int_n_sep_by_space; // CHAR_MAX - char int_p_sign_posn; // CHAR_MAX - char int_n_sign_posn; // CHAR_MAX -}; - // Locale categories #define LC_ALL 0 #define LC_COLLATE 1 @@ -41,5 +12,34 @@ struct lconv { #define LC_NUMERIC 4 #define LC_TIME 5 +struct lconv { + // LC_NUMERIC + char *decimal_point; // "." + char *thousands_sep; // "" + char *grouping; // "" + // LC_MONETARY + char *mon_decimal_point; // "" + char *mon_thousands_sep; // "" + char *mon_grouping; // "" + char *positive_sign; // "" + char *negative_sign; // "" + char *currency_symbol; // "" + char frac_digits; // CHAR_MAX + char p_cs_precedes; // CHAR_MAX + char n_cs_precedes; // CHAR_MAX + char p_sep_by_space; // CHAR_MAX + char n_sep_by_space; // CHAR_MAX + char p_sign_posn; // CHAR_MAX + char n_sign_posn; // CHAR_MAX + char *int_curr_symbol; // "" + char int_frac_digits; // CHAR_MAX + char int_p_cs_precedes; // CHAR_MAX + char int_n_cs_precedes; // CHAR_MAX + char int_p_sep_by_space; // CHAR_MAX + char int_n_sep_by_space; // CHAR_MAX + char int_p_sign_posn; // CHAR_MAX + char int_n_sign_posn; // CHAR_MAX +}; + char *setlocale(int category, const char *locale); struct lconv *localeconv(void); diff --git a/inc/time.h b/inc/time.h index fbd4968..a210a5f 100644 --- a/inc/time.h +++ b/inc/time.h @@ -1,45 +1,51 @@ #pragma once -#include + +#include #if !defined(NULL) #define NULL ((void *)0) #endif -// The number of clock ticks per second -#define CLOCKS_PER_SEC ((clock_t)1000) - #define TIME_UTC 1 -typedef size_t clock_t; -typedef size_t time_t; +#define CLOCKS_PER_SEC ((clock_t)1000000) + +typedef uint64_t clock_t; +typedef uint64_t time_t; struct timespec { - time_t tv_sec; // Seconds - >= 0 - long tv_nsec; // Nanoseconds - [0, 999999999] + time_t tv_sec; + long tv_nsec; }; struct tm { - int tm_sec; // seconds after the minute - [0, 60] including leap second - int tm_min; // minutes after the hour - [0, 59] - int tm_hour; // hours since midnight - [0, 23] - int tm_mday; // day of the month - [1, 31] - int tm_mon; // months since January - [0, 11] - int tm_year; // years since 1900 - int tm_wday; // days since Sunday - [0, 6] - int tm_yday; // days since January 1 - [0, 365] - int tm_isdst; // daylight savings time flag + int tm_sec; + int tm_min; + int tm_hour; + int tm_mon; + int tm_mday; // Days passed within 1st of current month + int tm_year; // Years since year 1900 + int tm_wday; // Days passed since sunday + int tm_yday; // Days passed since Jan 1 + int tm_isdst; }; -clock_t clock(void); -double difftime(time_t time1, time_t time0); -time_t mktime(struct tm *timeptr); -time_t time(time_t *timer); -int timespec_get(struct timespec *ts, int base); -char *asctime(const struct tm *timeptr); -char *ctime(const time_t *timer); -struct tm *gmtime(const time_t *timer); -struct tm *localtime(const time_t *timer); -size_t strftime(char * restrict s, size_t maxsize, const char * restrict format, const struct tm * restrict timeptr); +clock_t clock (void); +time_t time (time_t *timer); +time_t mktime (struct tm *timeptr); +double difftime (time_t time1, time_t time0); +int timespec_get(struct timespec *ts, int base); +char *asctime (const struct tm *timeptr); +char *ctime (const time_t *timer); +struct tm *gmtime (const time_t *timer); +struct tm *localtime (const time_t *timer); + +size_t strftime( + char *restrict s, + size_t maxsize, + const char *restrict format, + const struct tm *restrict timeptr +); #ifdef __STDC_WANT_LIB_EXT1__ errno_t asctime_s(char *s, rsize_t maxsize, const struct tm *timeptr); diff --git a/src/win/win_time.c b/src/win/win_time.c index 5fd1abb..a88a9ec 100644 --- a/src/win/win_time.c +++ b/src/win/win_time.c @@ -3,6 +3,15 @@ #include #include +#define TIME_TICKS_PER_SEC 1000 +#define FILE_TICKS_PER_SEC 10000000 +#define FILE_TICKS_UNTIL_UNIX_EPOCH 116444736000000000ULL + +#define NANOS_PER_SEC 1000000000 +#define NANOS_PER_FILE_TICK (NANOS_PER_SEC / FILE_TICKS_PER_SEC) +#define NANOS_PER_TIME_TICK (NANOS_PER_SEC / TIME_TICKS_PER_SEC) + + // Store the time since we started running the process static uint64_t timer_freq; static uint64_t timer_start; @@ -15,21 +24,17 @@ void _setup_timer(void) { timer_freq = freq.QuadPart; } -int timespec_get(struct timespec *ts, int base) { - if (base != TIME_UTC) return 0; - +static ULONGLONG win32_get_unix_nanos() { FILETIME ft; GetSystemTimeAsFileTime(&ft); - - ULARGE_INTEGER s = { - .LowPart = ft.dwLowDateTime, - .HighPart = ft.dwHighDateTime + ULARGE_INTEGER ft64 = { + .LowPart = ft.dwLowDateTime, + .HighPart = ft.dwHighDateTime, }; - - ULONGLONG t = s.QuadPart - 116444736000000000ULL; - ts->tv_sec = t / 10000000; - ts->tv_nsec = ((int) (t % 10000000)) * 100; - return base; + ULONGLONG fticks = ft64.QuadPart; + ULONGLONG unix_fticks = fticks - FILE_TICKS_UNTIL_UNIX_EPOCH; + ULONGLONG unix_nanos = unix_fticks * NANOS_PER_FILE_TICK; + return unix_nanos; } clock_t clock(void) { @@ -37,17 +42,34 @@ clock_t clock(void) { if (!QueryPerformanceCounter(&curr)) { return -1; } - - // time travel? if (curr.QuadPart < timer_start) { return -1; } - - uint64_t time_from_start = curr.QuadPart - timer_start; - - uint64_t scaled_millis = (time_from_start / timer_freq) * CLOCKS_PER_SEC; - // helps reduce error when doing integer division - scaled_millis += ((time_from_start % timer_freq) * CLOCKS_PER_SEC) / timer_freq; - - return scaled_millis; + clock_t ticks = curr.QuadPart - timer_start; + // Basically millis / timer_freq * CLOCKS_PER_SEC but more precise + return ticks / timer_freq * CLOCKS_PER_SEC + + ticks % timer_freq * CLOCKS_PER_SEC / timer_freq; +} + +time_t time(time_t *timer) { + ULONGLONG unix_nanos = win32_get_unix_nanos(); + time_t timer_ticks = unix_nanos / NANOS_PER_TIME_TICK; + if(timer != NULL) { + *timer = timer_ticks; + } + return timer_ticks; +} + +double difftime(time_t time1, time_t time0) { + double resolution = (double)TIME_TICKS_PER_SEC; + if(time1 >= time0) return (double)(time1 - time0) / resolution; + else return -(double)(time0 - time1) / resolution; +} + +int timespec_get(struct timespec *ts, int base) { + if (base != TIME_UTC) return 0; + ULONGLONG unix_nanos = win32_get_unix_nanos(); + ts->tv_sec = unix_nanos / NANOS_PER_SEC; + ts->tv_nsec = unix_nanos; + return base; } diff --git a/test/test_time.c b/test/test_time.c new file mode 100644 index 0000000..e759891 --- /dev/null +++ b/test/test_time.c @@ -0,0 +1,10 @@ + +#include +#include + +int main() { + time_t t1 = time(NULL); + time_t t2 = time(NULL); + double s = difftime(t2, t1); + return 0; +}