diff -rNU3 musl-old/src/time/__secs_to_tm.c musl/src/time/__secs_to_tm.c --- musl-old/src/time/__secs_to_tm.c 2013-11-25 11:57:25.138608721 +0100 +++ musl/src/time/__secs_to_tm.c 2013-11-26 10:55:00.944118059 +0100 @@ -8,6 +8,21 @@ #define DAYS_PER_100Y (365*100 + 24) #define DAYS_PER_4Y (365*4 + 1) +#ifndef NO_LEAPSECONDS +static int leapsecs_sub(long long *t) +{ + unsigned int i = 0; + int hit = 0; + for (; i < __leapsecs_num; i++) + if (*t >= __leapsecs_table[i].trans) break; + if (i < __leapsecs_num) { + if (*t == __leapsecs_table[i].trans) hit = 1; + *t -= __leapsecs_table[i].corr; + } + return hit; +} +#endif + int __secs_to_tm(long long t, struct tm *tm) { long long days, secs; @@ -21,6 +36,9 @@ if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL) return -1; +#ifndef NO_LEAPSECONDS + int hit = leapsecs_sub(&t); +#endif secs = t - LEAPOCH; days = secs / 86400; remsecs = secs % 86400; @@ -76,6 +94,9 @@ tm->tm_hour = remsecs / 3600; tm->tm_min = remsecs / 60 % 60; tm->tm_sec = remsecs % 60; +#ifndef NO_LEAPSECONDS + if (hit) tm->tm_sec++; +#endif return 0; } diff -rNU3 musl-old/src/time/time_impl.h musl/src/time/time_impl.h --- musl-old/src/time/time_impl.h 2013-11-25 11:57:25.138608721 +0100 +++ musl/src/time/time_impl.h 2013-11-26 10:48:40.712450191 +0100 @@ -7,3 +7,12 @@ int __secs_to_tm(long long, struct tm *); void __secs_to_zone(long long, int, int *, long *, long *, const char **); const unsigned char *__map_file(const char *, size_t *); + +#ifndef NO_LEAPSECONDS +struct lsinfo_s { + long long trans; + int corr; +} ; +extern struct lsinfo_s *__leapsecs_table; +extern unsigned int __leapsecs_num; +#endif diff -rNU3 musl-old/src/time/__tm_to_secs.c musl/src/time/__tm_to_secs.c --- musl-old/src/time/__tm_to_secs.c 2013-11-25 11:57:25.138608721 +0100 +++ musl/src/time/__tm_to_secs.c 2013-11-26 10:54:16.153921563 +0100 @@ -1,5 +1,16 @@ #include "time_impl.h" +#ifndef NO_LEAPSECONDS +static void leapsecs_add(long long *t, int hit) +{ + unsigned int i = 0; + for (; i < __leapsecs_num; i++) + if (*t >= __leapsecs_table[i].trans) break; + if (i < __leapsecs_num) + *t += __leapsecs_table[i].corr + (hit && (*t == __leapsecs_table[i].trans)); +} +#endif + long long __tm_to_secs(const struct tm *tm) { int is_leap; @@ -20,5 +31,8 @@ t += 3600LL * tm->tm_hour; t += 60LL * tm->tm_min; t += tm->tm_sec; +#ifndef NO_LEAPSECONDS + leapsecs_add(&t, tm->tm_sec==60); +#endif return t; } diff -rNU3 musl-old/src/time/__tz.c musl/src/time/__tz.c --- musl-old/src/time/__tz.c 2013-11-25 11:57:25.138608721 +0100 +++ musl/src/time/__tz.c 2013-11-26 12:41:31.142337204 +0100 @@ -118,6 +118,28 @@ int __munmap(void *, size_t); +#ifndef NO_LEAPSECONDS + +#define LEAPSECONDS_MAX 50 /* value in tzcode, probably too much */ +static struct lsinfo_s leapsecond_table[LEAPSECONDS_MAX<<1]; +struct lsinfo_s *__leapsecs_table = leapsecond_table; +unsigned int __leapsecs_num = 0; + +static inline uint64_t zi_read64(const unsigned char *z) +{ + return ((uint64_t)zi_read32(z) << 32) + zi_read32(z+4); +} + +static void parse_leapsecs(const unsigned char *z, unsigned int i, int lsize) +{ + __leapsecs_num = i; + for (; i; i--, z += lsize+4) { + __leapsecs_table[i-1].trans = (long long)(lsize == 8 ? zi_read64(z) : zi_read32(z)); + __leapsecs_table[i-1].corr = zi_read32(z+lsize); + } +} +#endif + static void do_tzset() { char buf[NAME_MAX+25], *pathname=buf+24; @@ -175,7 +197,7 @@ zi = map; if (map) { int scale = 2; - if (sizeof(time_t) > 4 && map[4]=='2') { + if (sizeof(time_t) > 4 && ((map[4]=='2') || (map[4]=='3'))) { size_t skip = zi_dotprod(zi+20, VEC(1,1,8,5,6,1), 6); trans = zi+skip+44+44; scale++; @@ -186,6 +208,9 @@ types = index + zi_read32(trans-12); abbrevs = types + 6*zi_read32(trans-8); abbrevs_end = abbrevs + zi_read32(trans-4); +#ifndef NO_LEAPSECONDS + parse_leapsecs(abbrevs_end, zi_read32(trans-16), 1 << scale); +#endif if (zi[map_size-1] == '\n') { for (s = (const char *)zi+map_size-2; *s!='\n'; s--); s++;