diff -rNU3 src-old/src/time/__secs_to_tm.c src/src/time/__secs_to_tm.c --- src-old/src/time/__secs_to_tm.c 2013-12-04 15:50:13.000000000 +0100 +++ src/src/time/__secs_to_tm.c 2013-12-05 01:34:35.000000000 +0100 @@ -8,6 +8,23 @@ #define DAYS_PER_100Y (365*100 + 24) #define DAYS_PER_4Y (365*4 + 1) +static int leapsecs_sub(long long *t) +{ + long long trans; + int corr; + unsigned int i = __leapsecs_num; + int hit = 0; + for (; i; i--) { + __leapsecs_read(i-1, &trans, &corr); + if (*t >= trans) break; + } + if (i) { + if (*t == trans) hit = 1; + *t -= corr; + } + return hit; +} + int __secs_to_tm(long long t, struct tm *tm) { long long days, secs; @@ -21,6 +38,7 @@ if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL) return -1; + int hit = leapsecs_sub(&t); secs = t - LEAPOCH; days = secs / 86400; remsecs = secs % 86400; @@ -76,6 +94,7 @@ tm->tm_hour = remsecs / 3600; tm->tm_min = remsecs / 60 % 60; tm->tm_sec = remsecs % 60; + if (hit) tm->tm_sec++; return 0; } diff -rNU3 src-old/src/time/__tm_to_secs.c src/src/time/__tm_to_secs.c --- src-old/src/time/__tm_to_secs.c 2013-12-04 15:50:13.000000000 +0100 +++ src/src/time/__tm_to_secs.c 2013-12-05 01:38:39.000000000 +0100 @@ -1,5 +1,21 @@ #include "time_impl.h" +static void leapsecs_add(long long *t, int hit) +{ + int oldcorr = 0; + unsigned int i = 0; + for (; i < __leapsecs_num; i++) { + long long trans; + int newcorr; + __leapsecs_read(i, &trans, &newcorr); + if (*t < trans) break; + if (!hit || (*t > trans)) { + *t += newcorr - oldcorr; + } + oldcorr = newcorr; + } +} + long long __tm_to_secs(const struct tm *tm) { int is_leap; @@ -20,5 +36,6 @@ t += 3600LL * tm->tm_hour; t += 60LL * tm->tm_min; t += tm->tm_sec; + leapsecs_add(&t, tm->tm_sec==60); return t; } diff -rNU3 src-old/src/time/__tz.c src/src/time/__tz.c --- src-old/src/time/__tz.c 2013-12-04 15:50:13.000000000 +0100 +++ src/src/time/__tz.c 2013-12-05 01:42:19.000000000 +0100 @@ -17,6 +17,8 @@ static char dst_name[TZNAME_MAX+1]; const char __gmt[] = "GMT"; +unsigned int __leapsecs_num; + static int dst_off; static int r0[5], r1[5]; @@ -105,6 +107,22 @@ return (unsigned)z[0]<<24 | z[1]<<16 | z[2]<<8 | z[3]; } +static uint64_t zi_read64(const unsigned char *z) +{ + return ((uint64_t)zi_read32(z) << 32) | (uint64_t)zi_read32(z+4); +} + +void __leapsecs_read(unsigned int i, long long *tt, int *corr) +{ + if (trans > zi+44) { + *tt = (long long)zi_read64(abbrevs_end + 12*i); + *corr = (int)zi_read32(abbrevs_end + 12*i + 8); + } else { + *tt = (long long)zi_read32(abbrevs_end + 8*i); + *corr = (int)zi_read32(abbrevs_end + 8*i + 4); + } +} + static size_t zi_dotprod(const unsigned char *z, const unsigned char *v, size_t n) { size_t y; @@ -175,7 +193,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 +204,7 @@ types = index + zi_read32(trans-12); abbrevs = types + 6*zi_read32(trans-8); abbrevs_end = abbrevs + zi_read32(trans-4); + __leapsecs_num = zi_read32(trans-16); if (zi[map_size-1] == '\n') { for (s = (const char *)zi+map_size-2; *s!='\n'; s--); s++; diff -rNU3 src-old/src/time/time_impl.h src/src/time/time_impl.h --- src-old/src/time/time_impl.h 2013-12-04 15:50:13.000000000 +0100 +++ src/src/time/time_impl.h 2013-12-04 16:50:21.000000000 +0100 @@ -7,3 +7,5 @@ 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 *); +extern unsigned int __leapsecs_num; +void __leapsecs_read(unsigned int, long long *, int *);