diff options
author | Christian Neukirchen <chneukirchen@gmail.com> | 2016-08-08 16:28:25 +0200 |
---|---|---|
committer | Christian Neukirchen <chneukirchen@gmail.com> | 2016-08-08 16:28:25 +0200 |
commit | d458439970caffc3bdebc3c139f29e02b285db55 (patch) | |
tree | a0bde4845187c09f37321e66e0aaec27351423ea /mytimegm.c | |
parent | 20dae518c4abaac33226b5e8ae85d0de1a1b226e (diff) | |
download | mblaze-d458439970caffc3bdebc3c139f29e02b285db55.tar.gz mblaze-d458439970caffc3bdebc3c139f29e02b285db55.tar.xz mblaze-d458439970caffc3bdebc3c139f29e02b285db55.zip |
import and use timegm from musl
It's ridiculous this function is not in the standards.
Diffstat (limited to 'mytimegm.c')
-rw-r--r-- | mytimegm.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/mytimegm.c b/mytimegm.c new file mode 100644 index 0000000..3d3fccd --- /dev/null +++ b/mytimegm.c @@ -0,0 +1,86 @@ +#include <time.h> + +// from musl@1cc81f5cb, slightly tweaked + +static long long +__year_to_secs(long long year, int *is_leap) +{ + if (year-2ULL <= 136) { + int y = year; + int leaps = (y-68)>>2; + if (!((y-68)&3)) { + leaps--; + if (is_leap) *is_leap = 1; + } else if (is_leap) *is_leap = 0; + return 31536000*(y-70) + 86400*leaps; + } + + int cycles, centuries, leaps, rem; + + cycles = (year-100) / 400; + rem = (year-100) % 400; + if (rem < 0) { + cycles--; + rem += 400; + } + if (!rem) { + *is_leap = 1; + centuries = 0; + leaps = 0; + } else { + if (rem >= 200) { + if (rem >= 300) centuries = 3, rem -= 300; + else centuries = 2, rem -= 200; + } else { + if (rem >= 100) centuries = 1, rem -= 100; + else centuries = 0; + } + if (!rem) { + *is_leap = 0; + leaps = 0; + } else { + leaps = rem / 4U; + rem %= 4U; + *is_leap = !rem; + } + } + + leaps += 97*cycles + 24*centuries - *is_leap; + + return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; +} + +static int +__month_to_secs(int month, int is_leap) +{ + static const int secs_through_month[] = { + 0, 31*86400, 59*86400, 90*86400, + 120*86400, 151*86400, 181*86400, 212*86400, + 243*86400, 273*86400, 304*86400, 334*86400 }; + int t = secs_through_month[month]; + if (is_leap && month >= 2) t+=86400; + return t; +} + +time_t tm_to_secs(const struct tm *tm) +{ + int is_leap; + long long year = tm->tm_year; + int month = tm->tm_mon; + if (month >= 12 || month < 0) { + int adj = month / 12; + month %= 12; + if (month < 0) { + adj--; + month += 12; + } + year += adj; + } + long long t = __year_to_secs(year, &is_leap); + t += __month_to_secs(month, is_leap); + t += 86400LL * (tm->tm_mday-1); + t += 3600LL * tm->tm_hour; + t += 60LL * tm->tm_min; + t += tm->tm_sec; + return t; +} |