diff options
Diffstat (limited to 'src/timezone/localtime.c')
-rw-r--r-- | src/timezone/localtime.c | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c index 0fc0a824ae4..f9b39195fad 100644 --- a/src/timezone/localtime.c +++ b/src/timezone/localtime.c @@ -36,7 +36,7 @@ * in which Daylight Saving Time is never observed. * 4. They might reference tzname[0] after setting to a time zone * in which Standard Time is never observed. - * 5. They might reference tm.TM_ZONE after calling offtime. + * 5. They might reference tm.tm_zone after calling offtime. * What's best to do in the above cases is open to debate; * for now, we just set things up so that in any of the five cases * WILDABBR is used. Another possibility: initialize tzname[0] to the @@ -92,8 +92,9 @@ struct rule static struct pg_tm *gmtsub(pg_time_t const *, int32, struct pg_tm *); static bool increment_overflow(int *, int); static bool increment_overflow_time(pg_time_t *, int32); +static int64 leapcorr(struct state const *, pg_time_t); static struct pg_tm *timesub(pg_time_t const *, int32, struct state const *, - struct pg_tm *); + struct pg_tm *); static bool typesequiv(struct state const *, int, int); @@ -138,7 +139,7 @@ detzcode(const char *const codep) * Do two's-complement negation even on non-two's-complement machines. * If the result would be minval - 1, return minval. */ - result -= !TWOS_COMPLEMENT(int32) &&result != 0; + result -= !TWOS_COMPLEMENT(int32) && result != 0; result += minval; } return result; @@ -152,7 +153,7 @@ detzcode64(const char *const codep) int64 one = 1; int64 halfmaxval = one << (64 - 2); int64 maxval = halfmaxval - 1 + halfmaxval; - int64 minval = -TWOS_COMPLEMENT(int64) -maxval; + int64 minval = -TWOS_COMPLEMENT(int64) - maxval; result = codep[0] & 0x7f; for (i = 1; i < 8; ++i) @@ -164,7 +165,7 @@ detzcode64(const char *const codep) * Do two's-complement negation even on non-two's-complement machines. * If the result would be minval - 1, return minval. */ - result -= !TWOS_COMPLEMENT(int64) &&result != 0; + result -= !TWOS_COMPLEMENT(int64) && result != 0; result += minval; } return result; @@ -173,7 +174,7 @@ detzcode64(const char *const codep) static bool differ_by_repeat(const pg_time_t t1, const pg_time_t t0) { - if (TYPE_BIT(pg_time_t) -TYPE_SIGNED(pg_time_t) <SECSPERREPEAT_BITS) + if (TYPE_BIT(pg_time_t) - TYPE_SIGNED(pg_time_t) < SECSPERREPEAT_BITS) return 0; return t1 - t0 == SECSPERREPEAT; } @@ -477,12 +478,14 @@ tzloadbody(char const *name, char *canonname, struct state *sp, bool doextend, for (i = 0; i < ts->timecnt; i++) if (sp->timecnt == 0 - || sp->ats[sp->timecnt - 1] < ts->ats[i]) + || (sp->ats[sp->timecnt - 1] + < ts->ats[i] + leapcorr(sp, ts->ats[i]))) break; while (i < ts->timecnt && sp->timecnt < TZ_MAX_TIMES) { - sp->ats[sp->timecnt] = ts->ats[i]; + sp->ats[sp->timecnt] + = ts->ats[i] + leapcorr(sp, ts->ats[i]); sp->types[sp->timecnt] = (sp->typecnt + ts->types[i]); sp->timecnt++; @@ -1480,7 +1483,7 @@ timesub(const pg_time_t *timep, int32 offset, int leapdays; tdelta = tdays / DAYSPERLYEAR; - if (!((!TYPE_SIGNED(pg_time_t) ||INT_MIN <= tdelta) + if (!((!TYPE_SIGNED(pg_time_t) || INT_MIN <= tdelta) && tdelta <= INT_MAX)) goto out_of_range; idelta = tdelta; @@ -1601,6 +1604,22 @@ increment_overflow_time(pg_time_t *tp, int32 j) return false; } +static int64 +leapcorr(struct state const *sp, pg_time_t t) +{ + struct lsinfo const *lp; + int i; + + i = sp->leapcnt; + while (--i >= 0) + { + lp = &sp->lsis[i]; + if (t >= lp->ls_trans) + return lp->ls_corr; + } + return 0; +} + /* * Find the next DST transition time in the given zone after the given time * |