Mercurial > dovecot > core-2.2
changeset 21661:c4584d7dc07e
lib: Accept leap second in utc_mktime
Accept leap second at any time in utc_mktime since utc_mktime is being
used before applying the timezone offset everywhere.
author | Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi> |
---|---|
date | Tue, 21 Feb 2017 16:25:25 +0200 |
parents | ed928407244b |
children | 4f63ef17d9dc |
files | src/lib/test-utc-mktime.c src/lib/utc-mktime.c src/lib/utc-mktime.h |
diffstat | 3 files changed, 50 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/test-utc-mktime.c Tue Feb 21 14:42:01 2017 +0200 +++ b/src/lib/test-utc-mktime.c Tue Feb 21 16:25:25 2017 +0200 @@ -19,7 +19,21 @@ #endif { 2007, 11, 7, 1, 7, 20 }, { 1970, 1, 1, 0, 0, 0 }, - { 2038, 1, 19, 3, 14, 7 } + { 2038, 1, 19, 3, 14, 7 }, + { INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX }, + { 2038, 1, 19, 3, 14, 8 }, + { 2106, 2, 7, 6, 28, 15 }, + { 2106, 2, 7, 6, 28, 16 }, + /* June leap second */ + { 2015, 6, 30, 23, 59, 59 }, + { 2015, 6, 30, 23, 59, 60 }, + { 2015, 7, 1, 0, 0, 0 }, + /* Invalid leap second */ + { 2017, 1, 24, 16, 40, 60 }, + /* Dec leap second */ + { 2016, 12, 31, 23, 59, 59 }, + { 2016, 12, 31, 23, 59, 60 }, + { 2017, 1, 1, 0, 0, 0 }, }; static time_t output[] = { #ifdef TIME_T_SIGNED @@ -31,8 +45,23 @@ #endif 1194397640, 0, - 2147483647 + 2147483647, + -1, + 2147483648, + 4294967295, + 4294967296, + /* June leap second */ + 1435708799, + 1435708799, + 1435708800, + /* Invalid leap second - utc_mktime() doesn't mind */ + 1485276059, + /* Dec leap second */ + 1483228799, + 1483228799, + 1483228800, }; + i_assert(N_ELEMENTS(input) == N_ELEMENTS(output)); struct tm tm; unsigned int i; time_t t;
--- a/src/lib/utc-mktime.c Tue Feb 21 14:42:01 2017 +0200 +++ b/src/lib/utc-mktime.c Tue Feb 21 16:25:25 2017 +0200 @@ -20,20 +20,33 @@ return tm1->tm_sec - tm2->tm_sec; } +static inline void adjust_leap_second(struct tm *tm) +{ + if (tm->tm_sec == 60) + tm->tm_sec = 59; +} + #ifdef HAVE_TIMEGM +/* Normalization done by timegm is considered a failure here, since it means + * the timestamp is not valid as-is. Leap second 60 is adjusted to 59 before + * this though. */ time_t utc_mktime(const struct tm *tm) { - struct tm mod_tm = *tm; + struct tm leap_adj_tm = *tm; + adjust_leap_second(&leap_adj_tm); + struct tm tmp = leap_adj_tm; time_t t; - t = timegm(&mod_tm); - if (tm_cmp(tm, &mod_tm) != 0) + t = timegm(&tmp); + if (tm_cmp(&leap_adj_tm, &tmp) != 0) return (time_t)-1; return t; } #else time_t utc_mktime(const struct tm *tm) { + struct tm leap_adj_tm = *tm; + adjust_leap_second(&leap_adj_tm); const struct tm *try_tm; time_t t; int bits, dir; @@ -49,7 +62,7 @@ #endif for (bits = TIME_T_MAX_BITS - 2;; bits--) { try_tm = gmtime(&t); - dir = tm_cmp(tm, try_tm); + dir = tm_cmp(&leap_adj_tm, try_tm); if (dir == 0) return t; if (bits < 0)
--- a/src/lib/utc-mktime.h Tue Feb 21 14:42:01 2017 +0200 +++ b/src/lib/utc-mktime.h Tue Feb 21 16:25:25 2017 +0200 @@ -4,7 +4,8 @@ #include <time.h> /* Like mktime(), but assume that tm is in UTC. Unlike mktime(), values in - tm fields must be in valid range. */ + tm fields must be in valid range. Leap second is accepted any time though + since utc_mktime is often used before applying the time zone offset. */ time_t utc_mktime(const struct tm *tm); #endif