diff options
Diffstat (limited to 'src/nxt_gmtime.c')
-rw-r--r-- | src/nxt_gmtime.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/nxt_gmtime.c b/src/nxt_gmtime.c new file mode 100644 index 00000000..9c3fa190 --- /dev/null +++ b/src/nxt_gmtime.c @@ -0,0 +1,79 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +/* The function is valid for positive nxt_time_t only. */ + +void +nxt_gmtime(nxt_time_t s, struct tm *tm) +{ + nxt_int_t yday; + nxt_uint_t daytime, mday, mon, year, days, leap; + + days = (nxt_uint_t) (s / 86400); + daytime = (nxt_uint_t) (s % 86400); + + /* January 1, 1970 was Thursday. */ + tm->tm_wday = (4 + days) % 7; + + /* The algorithm based on Gauss' formula. */ + + /* Days since March 1, 1 BCE. */ + days = days - (31 + 28) + 719527; + + /* + * The "days" should be adjusted by 1 only, however some March 1st's + * go to previous year, so "days" are adjusted by 2. This also shifts + * the last February days to the next year, but this is catched by + * negative "yday". + */ + year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1); + + yday = days - (365 * year + year / 4 - year / 100 + year / 400); + + leap = (year % 4 == 0) && (year % 100 || (year % 400 == 0)); + + if (yday < 0) { + yday = 365 + leap + yday; + year--; + } + + /* + * An empirical formula that maps "yday" to month. + * There are at least 10 variants, some of them are: + * mon = (yday + 31) * 15 / 459 + * mon = (yday + 31) * 17 / 520 + * mon = (yday + 31) * 20 / 612 + */ + + mon = (yday + 31) * 10 / 306; + + /* The Gauss' formula that evaluates days before month. */ + + mday = yday - (367 * mon / 12 - 30) + 1; + + if (yday >= 306) { + year++; + mon -= 11; + yday -= 306; + + } else { + mon++; + yday += 31 + 28 + leap; + } + + tm->tm_mday = mday; + tm->tm_mon = mon; + tm->tm_year = year - 1900; + tm->tm_yday = yday; + + tm->tm_hour = daytime / 3600; + daytime %= 3600; + tm->tm_min = daytime / 60; + tm->tm_sec = daytime % 60; +} |