libc/stdtime: Sync with tzcode2013h from ftp://ftp.iana.org/tz/releases
authorSascha Wildner <saw@online.de>
Sun, 1 Dec 2013 20:39:23 +0000 (21:39 +0100)
committerSascha Wildner <saw@online.de>
Mon, 2 Dec 2013 14:32:14 +0000 (15:32 +0100)
This also reverts most of the changes from the "locale megapatch".
While well-meant, this threw us back to being in sync with upstream's
tzcode2010m, while before we were in sync with tzcode2012c.

Leave those FreeBSD changes which make sense.

12 files changed:
lib/libc/gen/tzset.3
lib/libc/stdtime/asctime.c
lib/libc/stdtime/ctime.3
lib/libc/stdtime/difftime.c
lib/libc/stdtime/localtime.c
lib/libc/stdtime/private.h
lib/libc/stdtime/strftime.3
lib/libc/stdtime/strftime.c
lib/libc/stdtime/time2posix.3
lib/libc/stdtime/time32.c
lib/libc/stdtime/tzfile.5
lib/libc/stdtime/tzfile.h

index 34fe325..2ae7e92 100644 (file)
@@ -30,7 +30,7 @@
 .\"
 .\" $FreeBSD: src/lib/libc/gen/tzset.3,v 1.6.2.5 2001/12/14 18:33:51 ru Exp $
 .\"
-.Dd October 19, 2008
+.Dd December 1, 2013
 .Dt TZSET 3
 .Os
 .Sh NAME
@@ -66,10 +66,14 @@ is used.
 .Pp
 If
 .Ev TZ
-appears in the environment but its value is a null string, Coordinated
+appears in the environment but its value is a null string
 Universal Time
-.Pq Tn UTC
-is used (without leap second correction).
+.Pq UT
+is used, with the abbreviation
+.Dq UTC
+and without leap second correction; please see
+.Xr ctime 3
+for more about UT, UTC, and leap seconds.
 .Pp
 If
 .Ev TZ
@@ -197,6 +201,10 @@ describes when the change back happens.  Each
 .Em time
 field describes when, in current local time, the change to the other
 time is made.
+As an extension to POSIX, daylight saving is assumed to be in effect
+all year if it begins January 1 at 00:00 and ends December 31 at
+24:00 plus the difference between daylight saving and standard time,
+leaving no room for standard time in the calendar.
 .Pp
 The format of
 .Em date
@@ -245,21 +253,63 @@ which may occur in either the fourth or the fifth week).  Week 1 is the
 first week in which the
 .Em d Ns 'th
 day occurs.  Day zero is Sunday.
+.El
 .Pp
 The
 .Em time
 has the same format as
 .Em offset
-except that no leading sign
+except that POSIX does not allow a leading sign
 .Pq Ql \-
 or
-.Pq Ql +
-is allowed.  The default, if
+.Pq Ql + .
+As an extension to POSIX, the hours part of
+.Em time
+can range from -167 through 167; this allows for unusual rules such
+as
+.Dq the Saturday before the first Sunday of March .
+The default, if
 .Em time
 is not given, is
 .Sy 02:00:00 .
 .El
 .Pp
+Here are some examples of
+.Ev TZ
+values that directly specify the time zone rules; they use some of the
+extensions to POSIX.
+.Bl -tag -width ".Sy EST5X"
+.It Sy EST5
+stands for US Eastern Standard
+Time (EST), 5 hours behind UTC, without daylight saving.
+.It Sy FJT-12FJST,M10.3.1/146,M1.3.4/75
+stands for Fiji Time (FJT) and Fiji Summer Time (FJST), 12 hours ahead
+of UTC, springing forward on October's third Monday at
+146:00 (i.e., 02:00 on the first Sunday on or after October 21), and
+falling back on January's third Thursday at 75:00 (i.e., 03:00 on the
+first Sunday on or after January 18).
+.It Sy IST-2IDT,M3.4.4/26,M10.5.0
+stands for Israel Standard Time (IST) and Israel Daylight Time (IDT),
+2 hours ahead of UTC, springing forward on March's fourth
+Tuesday at 26:00 (i.e., 02:00 on the first Friday on or after March
+23), and falling back on October's last Sunday at 02:00.
+.It Sy WART4WARST,J1/0,J365/25
+stands for Western Argentina Summer Time (WARST), 3 hours behind UTC.
+There is a dummy fall-back transition on December 31 at 25:00 daylight
+saving time (i.e., 24:00 standard time, equivalent to January 1 at
+00:00 standard time), and a simultaneous spring-forward transition on
+January 1 at 00:00 standard time, so daylight saving time is in effect
+all year and the initial
+.Sy WART
+is a placeholder.
+.It Sy WGT3WGST,M3.5.0/-2,M10.5.0/-1
+stands for Western Greenland Time (WGT) and Western Greenland Summer
+Time (WGST), 3 hours behind UTC, where clocks follow the EU rules of
+springing forward on March's last Sunday at 01:00 UTC (\(mi02:00 local
+time) and falling back on October's last Sunday at 01:00 UTC
+(-01:00 local time).
+.El
+.Pp
 If no
 .Em rule
 is present in the
@@ -277,7 +327,6 @@ the
 .Em offset
 values in
 .Ev TZ .
-.El
 .Pp
 For compatibility with System V Release 3.1, a semicolon
 .Pq Ql \&;
index e1a49d3..973ec81 100644 (file)
@@ -81,10 +81,10 @@ asctime_r(const struct tm *timeptr, char *buf)
                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
        };
+       char            year[INT_STRLEN_MAXIMUM(int) + 2];
+       char            result[MAX_ASCTIME_BUF_SIZE];
        const char *    wn;
        const char *    mn;
-       char                    year[INT_STRLEN_MAXIMUM(int) + 2];
-       char                    result[MAX_ASCTIME_BUF_SIZE];
 
        if (timeptr == NULL) {
                errno = EINVAL;
@@ -102,19 +102,16 @@ asctime_r(const struct tm *timeptr, char *buf)
        ** Assume that strftime is unaffected by other out-of-range members
        ** (e.g., timeptr->tm_mday) when processing "%Y".
        */
-       (void) strftime(year, sizeof year, "%Y", timeptr);
-       /*
-       ** We avoid using snprintf since it's not available on all systems.
-       */
-       (void) sprintf(result,
+       strftime(year, sizeof year, "%Y", timeptr);
+       snprintf(result, sizeof result,
                ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
                wn, mn,
                timeptr->tm_mday, timeptr->tm_hour,
                timeptr->tm_min, timeptr->tm_sec,
                year);
-       if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime)
+       if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime) {
                return strcpy(buf, result);
-       else {
+       else {
                errno = EOVERFLOW;
                return NULL;
        }
index d84ab4a..e30f2dc 100644 (file)
@@ -11,7 +11,7 @@
 .\" 2. Redistributions in binary form must reproduce the above copyright
 .\"    notice, this list of conditions and the following disclaimer in the
 .\"    documentation and/or other materials provided with the distribution.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 3. Neither the name of the University nor the names of its contributors
 .\"    may be used to endorse or promote products derived from this software
 .\"    without specific prior written permission.
 .\"
@@ -30,7 +30,7 @@
 .\"     From: @(#)ctime.3      8.1 (Berkeley) 6/4/93
 .\" $FreeBSD: head/contrib/tzcode/stdtime/ctime.3 165903 2007-01-09 00:28:16Z imp $
 .\"
-.Dd January 2, 1999
+.Dd November 19, 2013
 .Dt CTIME 3
 .Os
 .Sh NAME
@@ -129,12 +129,21 @@ The
 function
 adjusts the time value for the current time zone in the same manner as
 .Fn localtime ,
-and returns a pointer to a 26-character string of the form:
+and returns a pointer to a string of the form:
 .Bd -literal -offset indent
 Thu Nov 24 18:22:48 1986\en\e0
 .Ed
 .Pp
-All the fields have constant width.
+Years requiring fewer than four characters are padded with leading zeroes.
+For years longer than four characters, the string is of the form
+.Bd -literal -offset indent
+Thu Nov 24 18:22:48     81986\en\e0
+.Ed
+.Pp
+with five spaces before the year.
+These unusual formats are designed to make it less likely that older
+software that expects exactly 26 bytes of output will mistakenly output
+misleading values for out-of-range years.
 .Pp
 The
 .Fn ctime_r
@@ -225,7 +234,9 @@ A negative value for
 causes the
 .Fn mktime
 function to attempt to divine whether summer time is in effect for the
-specified time.
+specified time; in this case it does not use a consistent
+rule and may give a different answer when later
+presented with the same argument.
 The
 .Fa tm_isdst
 and
@@ -276,7 +287,7 @@ int tm_wday;        /\(** day of week (Sunday = 0) \(**/
 int tm_yday;   /\(** day of year (0 - 365) \(**/
 int tm_isdst;  /\(** is summer time in effect? \(**/
 char \(**tm_zone;      /\(** abbreviation of timezone name \(**/
-long tm_gmtoff;        /\(** offset from UTC in seconds \(**/
+long tm_gmtoff;        /\(** offset from UT in seconds \(**/
 .Ed
 .Pp
 The
@@ -287,13 +298,31 @@ is non-zero if summer time is in effect.
 The field
 .Fa tm_gmtoff
 is the offset (in seconds) of the time represented from
-.Tn UTC ,
+.Tn UT ,
 with positive
 values indicating east of the Prime Meridian.
+The field's name is derived from Greenwich Mean Time, a precursor of UT.
+.Sh COMPATIBILITY
+The
+.Fn asctime
+and
+.Fn ctime
+functions
+behave strangely for years before 1000 or after 9999.
+The 1989 and 1999 editions of the C Standard say
+that years from -99 through 999 are converted without
+extra spaces, but this conflicts with longstanding
+tradition and with this implementation.
+Traditional implementations of these two functions are
+restricted to years in the range 1900 through 2099.
+To avoid this portability mess, new programs should use
+.Xr strftime 3
+instead.
 .Sh SEE ALSO
 .Xr date 1 ,
 .Xr gettimeofday 2 ,
 .Xr getenv 3 ,
+.Xr strftime 3 ,
 .Xr time 3 ,
 .Xr tzset 3 ,
 .Xr tzfile 5
index 6100a0a..db5a839 100644 (file)
@@ -7,37 +7,28 @@
 /*LINTLIBRARY*/
 
 #include "namespace.h"
-#include "private.h"   /* for time_t, TYPE_INTEGRAL, and TYPE_SIGNED */
+#include "private.h"   /* for time_t and TYPE_SIGNED */
 #include "un-namespace.h"
 
 double
-difftime(const time_t time1, const time_t time0)
+difftime(time_t time1, time_t time0)
 {
        /*
        ** If (sizeof (double) > sizeof (time_t)) simply convert and subtract
        ** (assuming that the larger type has more precision).
-       ** This is the common real-world case circa 2004.
        */
        if (sizeof (double) > sizeof (time_t))
                return (double) time1 - (double) time0;
-       if (!TYPE_INTEGRAL(time_t)) {
-               /*
-               ** time_t is floating.
-               */
-               return time1 - time0;
-       }
        if (!TYPE_SIGNED(time_t)) {
                /*
-               ** time_t is integral and unsigned.
                ** The difference of two unsigned values can't overflow
                ** if the minuend is greater than or equal to the subtrahend.
                */
                if (time1 >= time0)
-                       return time1 - time0;
-               else    return -((double) (time0 - time1));
+                       return            time1 - time0;
+               else    return -(double) (time0 - time1);
        }
        /*
-       ** time_t is integral and signed.
        ** Handle cases where both time1 and time0 have the same sign
        ** (meaning that their difference cannot overflow).
        */
@@ -45,16 +36,16 @@ difftime(const time_t time1, const time_t time0)
                return time1 - time0;
        /*
        ** time1 and time0 have opposite signs.
-       ** Punt if unsigned long is too narrow.
+       ** Punt if uintmax_t is too narrow.
+       ** This suffers from double rounding; attempt to lessen that
+       ** by using long double temporaries.
        */
-       if (sizeof (unsigned long) < sizeof (time_t))
-               return (double) time1 - (double) time0;
+       if (sizeof (uintmax_t) < sizeof (time_t))
+               return (long double) time1 - (long double) time0;
        /*
        ** Stay calm...decent optimizers will eliminate the complexity below.
        */
        if (time1 >= 0 /* && time0 < 0 */)
-               return (unsigned long) time1 +
-                       (unsigned long) (-(time0 + 1)) + 1;
-       return -(double) ((unsigned long) time0 +
-               (unsigned long) (-(time1 + 1)) + 1);
+               return    (uintmax_t) time1 + (uintmax_t) (-1 - time0) + 1;
+       return -(double) ((uintmax_t) time0 + (uintmax_t) (-1 - time1) + 1);
 }
index 4cac820..85c9a72 100644 (file)
 #include "namespace.h"
 #include <sys/types.h>
 #include <sys/stat.h>
+
 #include <errno.h>
 #include <fcntl.h>
+#include <time.h>
 #include <pthread.h>
 #include "private.h"
 #include "libc_private.h"
-#include "un-namespace.h"
+#include <un-namespace.h>
 
 #include "tzfile.h"
-#include "float.h"     /* for FLT_MAX and DBL_MAX */
 
 #ifndef TZ_ABBR_MAX_LEN
 #define TZ_ABBR_MAX_LEN        16
@@ -38,8 +39,6 @@
 #define TZ_ABBR_ERR_CHAR       '_'
 #endif /* !defined TZ_ABBR_ERR_CHAR */
 
-#include "libc_private.h"
-
 #define        _MUTEX_LOCK(x)          if (__isthreaded) _pthread_mutex_lock(x)
 #define        _MUTEX_UNLOCK(x)        if (__isthreaded) _pthread_mutex_unlock(x)
 
@@ -58,7 +57,6 @@
                        if (__isthreaded) _pthread_rwlock_unlock(x);    \
                } while (0)
 
-#ifndef WILDABBR
 /*
 ** Someone might make incorrect use of a time zone abbreviation:
 **     1.      They might reference tzname[0] before calling tzset (explicitly
@@ -79,7 +77,6 @@
 ** that tzname[0] has the "normal" length of three characters).
 */
 #define WILDABBR       "   "
-#endif /* !defined WILDABBR */
 
 static char            wildabbr[] = WILDABBR;
 
@@ -97,16 +94,16 @@ static const char   gmt[] = "UTC";
 #endif /* !defined TZDEFDST */
 
 struct ttinfo {                                /* time type information */
-       long            tt_gmtoff;      /* UTC offset in seconds */
+       int_fast32_t    tt_gmtoff;      /* UT offset in seconds */
        int             tt_isdst;       /* used to set tm_isdst */
        int             tt_abbrind;     /* abbreviation list index */
        int             tt_ttisstd;     /* TRUE if transition is std time */
-       int             tt_ttisgmt;     /* TRUE if transition is UTC */
+       int             tt_ttisgmt;     /* TRUE if transition is UT */
 };
 
 struct lsinfo {                                /* leap second information */
        time_t          ls_trans;       /* transition time */
-       long            ls_corr;        /* correction to apply */
+       int_fast64_t    ls_corr;        /* correction to apply */
 };
 
 #define BIGGEST(a, b)  (((a) > (b)) ? (a) : (b))
@@ -131,6 +128,7 @@ struct state {
        char            chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
                                (2 * (MY_TZNAME_MAX + 1)))];
        struct lsinfo   lsis[TZ_MAX_LEAPS];
+       int             defaulttype; /* for early times or if no transitions */
 };
 
 struct rule {
@@ -138,7 +136,7 @@ struct rule {
        int             r_day;          /* day number of rule */
        int             r_week;         /* week number of rule */
        int             r_mon;          /* month number of rule */
-       long            r_time;         /* transition time of rule */
+       int_fast32_t    r_time;         /* transition time of rule */
 };
 
 #define JULIAN_DAY             0       /* Jn - Julian day */
@@ -149,47 +147,48 @@ struct rule {
 ** Prototypes for static functions.
 */
 
-static long            detzcode(const char * codep);
-static time_t          detzcode64(const char * codep);
+static int_fast32_t    detzcode(const char * codep);
+static int_fast64_t    detzcode64(const char * codep);
 static int             differ_by_repeat(time_t t1, time_t t0);
-static const char *    getzname(const char * strp);
-static const char *    getqzname(const char * strp, const int delim);
+static const char *    getzname(const char * strp) __pure;
+static const char *    getqzname(const char * strp, const int delim) __pure;
 static const char *    getnum(const char * strp, int * nump, int min,
                                int max);
-static const char *    getsecs(const char * strp, long * secsp);
-static const char *    getoffset(const char * strp, long * offsetp);
+static const char *    getsecs(const char * strp, int_fast32_t * secsp);
+static const char *    getoffset(const char * strp, int_fast32_t * offsetp);
 static const char *    getrule(const char * strp, struct rule * rulep);
 static void            gmtload(struct state * sp);
-static struct tm *     gmtsub(const time_t * timep, long offset,
+static struct tm *     gmtsub(const time_t * timep, int_fast32_t offset,
                                struct tm * tmp);
-static struct tm *     localsub(const time_t * timep, long offset,
+static struct tm *     localsub(const time_t * timep, int_fast32_t offset,
                                struct tm * tmp);
 static int             increment_overflow(int * number, int delta);
-static int             leaps_thru_end_of(int y);
-static int             long_increment_overflow(long * number, int delta);
-static int             long_normalize_overflow(long * tensptr,
+static int             leaps_thru_end_of(int y) __pure;
+static int             increment_overflow32(int_fast32_t * number, int delta);
+static int             increment_overflow_time(time_t *t, int_fast32_t delta);
+static int             normalize_overflow32(int_fast32_t * tensptr,
                                int * unitsptr, int base);
 static int             normalize_overflow(int * tensptr, int * unitsptr,
                                int base);
 static void            settzname(void);
 static time_t          time1(struct tm * tmp,
                                struct tm * (*funcp)(const time_t *,
-                               long, struct tm *),
-                               long offset);
+                               int_fast32_t, struct tm *),
+                               int_fast32_t offset);
 static time_t          time2(struct tm *tmp,
                                struct tm * (*funcp)(const time_t *,
-                               long, struct tm*),
-                               long offset, int * okayp);
+                               int_fast32_t, struct tm*),
+                               int_fast32_t offset, int * okayp);
 static time_t          time2sub(struct tm *tmp,
                                struct tm * (*funcp)(const time_t *,
-                               long, struct tm*),
-                               long offset, int * okayp, int do_norm_secs);
-static struct tm *     timesub(const time_t * timep, long offset,
+                               int_fast32_t, struct tm*),
+                               int_fast32_t offset, int * okayp, int do_norm_secs);
+static struct tm *     timesub(const time_t * timep, int_fast32_t offset,
                                const struct state * sp, struct tm * tmp);
 static int             tmcomp(const struct tm * atmp,
                                const struct tm * btmp);
-static time_t          transtime(time_t janfirst, int year,
-                               const struct rule * rulep, long offset);
+static int_fast32_t    transtime(int year, const struct rule * rulep,
+                                 int_fast32_t offset) __pure;
 static int             typesequiv(const struct state * sp, int a, int b);
 static int             tzload(const char * name, struct state * sp,
                                int doextend);
@@ -231,47 +230,53 @@ char *                    tzname[2] = {
 
 static struct tm       tm;
 
-time_t                 timezone = 0;
+long                   timezone = 0;
 int                    daylight = 0;
 
-static long
+static int_fast32_t
 detzcode(const char * const codep)
 {
-       long    result;
-       int     i;
+       int_fast32_t    result;
+       int             i;
 
-       result = (codep[0] & 0x80) ? ~0L : 0;
+       result = (codep[0] & 0x80) ? -1 : 0;
        for (i = 0; i < 4; ++i)
                result = (result << 8) | (codep[i] & 0xff);
        return result;
 }
 
-static time_t
+static int_fast64_t
 detzcode64(const char * const codep)
 {
-       time_t  result;
+       int_fast64_t result;
        int     i;
 
-       result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
+       result = (codep[0] & 0x80) ? -1 : 0;
        for (i = 0; i < 8; ++i)
-               result = result * 256 + (codep[i] & 0xff);
+               result = (result << 8) | (codep[i] & 0xff);
        return result;
 }
 
 static void
 settzname(void)
 {
-       struct state *  sp = lclptr;
+       struct state * const    sp = lclptr;
        int                     i;
 
        tzname[0] = wildabbr;
        tzname[1] = wildabbr;
        daylight = 0;
        timezone = 0;
+
        /*
        ** And to get the latest zone names into tzname. . .
        */
        for (i = 0; i < sp->typecnt; ++i) {
+               const struct ttinfo * const ttisp = &sp->ttis[i];
+
+               tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind];
+       }
+       for (i = 0; i < sp->timecnt; ++i) {
                const struct ttinfo * const ttisp = &sp->ttis[sp->types[i]];
 
                tzname[ttisp->tt_isdst] =
@@ -304,14 +309,9 @@ settzname(void)
 static int
 differ_by_repeat(const time_t t1, const time_t t0)
 {
-       int_fast64_t _t0 = t0;
-       int_fast64_t _t1 = t1;
-
-       if (TYPE_INTEGRAL(time_t) &&
-               TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
-                       return 0;
-       //turn ((int_fast64_t)(t1 - t0) == SECSPERREPEAT);
-       return _t1 - _t0 == SECSPERREPEAT;
+       if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
+               return 0;
+       return t1 - t0 == SECSPERREPEAT;
 }
 
 static int
@@ -323,12 +323,13 @@ tzload(const char *name, struct state * const sp, const int doextend)
        int             stored;
        int             nread;
        int             res;
-       union {
+       typedef union {
                struct tzhead   tzhead;
                char            buf[2 * sizeof(struct tzhead) +
                                        2 * sizeof *sp +
                                        4 * TZ_MAX_TIMES];
-       } *u;
+       } u_t;
+       u_t             *u;
 
        u = NULL;
        res = -1;
@@ -369,9 +370,9 @@ tzload(const char *name, struct state * const sp, const int doextend)
                                free(fullname);
                                return -1;
                        }
-                       (void) strcpy(fullname, p);
-                       (void) strcat(fullname, "/");
-                       (void) strcat(fullname, name);
+                       strcpy(fullname, p);
+                       strcat(fullname, "/");
+                       strcat(fullname, name);
                        /*
                        ** Set doaccess if '.' (as in "../") shows up in name.
                        */
@@ -381,7 +382,7 @@ tzload(const char *name, struct state * const sp, const int doextend)
                }
                if (doaccess && access(name, R_OK) != 0) {
                        free(fullname);
-                       return -1;
+                       return -1;
                }
                if ((fid = _open(name, O_RDONLY)) == -1) {
                        free(fullname);
@@ -403,6 +404,7 @@ tzload(const char *name, struct state * const sp, const int doextend)
        for (stored = 4; stored <= 8; stored *= 2) {
                int             ttisstdcnt;
                int             ttisgmtcnt;
+               int             timecnt;
 
                ttisstdcnt = (int) detzcode(u->tzhead.tzh_ttisstdcnt);
                ttisgmtcnt = (int) detzcode(u->tzhead.tzh_ttisgmtcnt);
@@ -427,16 +429,37 @@ tzload(const char *name, struct state * const sp, const int doextend)
                        ttisstdcnt +                    /* ttisstds */
                        ttisgmtcnt)                     /* ttisgmts */
                                goto out;
+               timecnt = 0;
                for (i = 0; i < sp->timecnt; ++i) {
-                       sp->ats[i] = (stored == 4) ?
-                               detzcode(p) : detzcode64(p);
+                       int_fast64_t at
+                         = stored == 4 ? detzcode(p) : detzcode64(p);
+                       sp->types[i] = ((TYPE_SIGNED(time_t)
+                                        ? time_t_min <= at
+                                        : 0 <= at)
+                                       && at <= time_t_max);
+                       if (sp->types[i]) {
+                               if (i && !timecnt && at != time_t_min) {
+                                       /*
+                                       ** Keep the earlier record, but tweak
+                                       ** it so that it starts with the
+                                       ** minimum time_t value.
+                                       */
+                                       sp->types[i - 1] = 1;
+                                       sp->ats[timecnt++] = time_t_min;
+                               }
+                               sp->ats[timecnt++] = at;
+                       }
                        p += stored;
                }
+               timecnt = 0;
                for (i = 0; i < sp->timecnt; ++i) {
-                       sp->types[i] = (unsigned char) *p++;
-                       if (sp->types[i] >= sp->typecnt)
+                       unsigned char typ = *p++;
+                       if (sp->typecnt <= typ)
                                goto out;
+                       if (sp->types[i])
+                               sp->types[timecnt++] = typ;
                }
+               sp->timecnt = timecnt;
                for (i = 0; i < sp->typecnt; ++i) {
                        struct ttinfo * ttisp;
 
@@ -491,33 +514,6 @@ tzload(const char *name, struct state * const sp, const int doextend)
                        }
                }
                /*
-               ** Out-of-sort ats should mean we're running on a
-               ** signed time_t system but using a data file with
-               ** unsigned values (or vice versa).
-               */
-               for (i = 0; i < sp->timecnt - 2; ++i)
-                       if (sp->ats[i] > sp->ats[i + 1]) {
-                               ++i;
-                               if (TYPE_SIGNED(time_t)) {
-                                       /*
-                                       ** Ignore the end (easy).
-                                       */
-                                       sp->timecnt = i;
-                               } else {
-                                       /*
-                                       ** Ignore the beginning (harder).
-                                       */
-                                       int     j;
-
-                                       for (j = 0; j + i < sp->timecnt; ++j) {
-                                               sp->ats[j] = sp->ats[j + i];
-                                               sp->types[j] = sp->types[j + i];
-                                       }
-                                       sp->timecnt = j;
-                               }
-                               break;
-                       }
-               /*
                ** If this is an old file, we're done.
                */
                if (u->tzhead.tzh_version[0] == '\0')
@@ -526,16 +522,16 @@ tzload(const char *name, struct state * const sp, const int doextend)
                for (i = 0; i < nread; ++i)
                        u->buf[i] = p[i];
                /*
-               ** If this is a narrow integer time_t system, we're done.
+               ** If this is a signed narrow time_t system, we're done.
                */
-               if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
+               if (TYPE_SIGNED(time_t) && stored >= (int) sizeof(time_t))
                        break;
        }
        if (doextend && nread > 2 &&
                u->buf[0] == '\n' && u->buf[nread - 1] == '\n' &&
                sp->typecnt + 2 <= TZ_MAX_TYPES) {
                        struct state    *ts;
-                       int     result;
+                       int             result;
 
                        ts = malloc(sizeof(*ts));
                        if (ts == NULL)
@@ -586,6 +582,40 @@ tzload(const char *name, struct state * const sp, const int doextend)
                                        break;
                }
        }
+       /*
+       ** If type 0 is is unused in transitions,
+       ** it's the type to use for early times.
+       */
+       for (i = 0; i < sp->typecnt; ++i)
+               if (sp->types[i] == 0)
+                       break;
+       i = (i >= sp->typecnt) ? 0 : -1;
+       /*
+       ** Absent the above,
+       ** if there are transition times
+       ** and the first transition is to a daylight time
+       ** find the standard type less than and closest to
+       ** the type of the first transition.
+       */
+       if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
+               i = sp->types[0];
+               while (--i >= 0)
+                       if (!sp->ttis[i].tt_isdst)
+                               break;
+       }
+       /*
+       ** If no result yet, find the first standard type.
+       ** If there is none, punt to type zero.
+       */
+       if (i < 0) {
+               i = 0;
+               while (sp->ttis[i].tt_isdst)
+                       if (++i >= sp->typecnt) {
+                               i = 0;
+                               break;
+                       }
+       }
+       sp->defaulttype = i;
        res = 0;
 out:
        free(u);
@@ -696,7 +726,7 @@ getnum(const char *strp, int * const nump, const int min, const int max)
 */
 
 static const char *
-getsecs(const char *strp, long * const secsp)
+getsecs(const char *strp, int_fast32_t * const secsp)
 {
        int     num;
 
@@ -709,7 +739,7 @@ getsecs(const char *strp, long * const secsp)
        strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
        if (strp == NULL)
                return NULL;
-       *secsp = num * (long) SECSPERHOUR;
+       *secsp = num * (int_fast32_t) SECSPERHOUR;
        if (*strp == ':') {
                ++strp;
                strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
@@ -736,7 +766,7 @@ getsecs(const char *strp, long * const secsp)
 */
 
 static const char *
-getoffset(const char *strp, long * const offsetp)
+getoffset(const char *strp, int_fast32_t * const offsetp)
 {
        int     neg = 0;
 
@@ -801,23 +831,22 @@ getrule(const char *strp, struct rule * const rulep)
                ** Time specified.
                */
                ++strp;
-               strp = getsecs(strp, &rulep->r_time);
+               strp = getoffset(strp, &rulep->r_time);
        } else  rulep->r_time = 2 * SECSPERHOUR;        /* default = 2:00:00 */
        return strp;
 }
 
 /*
-** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
-** year, a rule, and the offset from UTC at the time that rule takes effect,
-** calculate the Epoch-relative time that rule takes effect.
+** Given a year, a rule, and the offset from UT at the time that rule takes
+** effect, calculate the year-relative time that rule takes effect.
 */
 
-static time_t
-transtime(const time_t janfirst, const int year,
-    const struct rule * const rulep, const long offset)
+static int_fast32_t
+transtime(const int year, const struct rule * const rulep,
+         const int_fast32_t offset)
 {
        int     leapyear;
-       time_t  value;
+       int_fast32_t value;
        int     i;
        int             d, m1, yy0, yy1, yy2, dow;
 
@@ -833,7 +862,7 @@ transtime(const time_t janfirst, const int year,
                ** add SECSPERDAY times the day number-1 to the time of
                ** January 1, midnight, to get the day.
                */
-               value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
+               value = (rulep->r_day - 1) * SECSPERDAY;
                if (leapyear && rulep->r_day >= 60)
                        value += SECSPERDAY;
                break;
@@ -844,16 +873,13 @@ transtime(const time_t janfirst, const int year,
                ** Just add SECSPERDAY times the day number to the time of
                ** January 1, midnight, to get the day.
                */
-               value = janfirst + rulep->r_day * SECSPERDAY;
+               value = rulep->r_day * SECSPERDAY;
                break;
 
        case MONTH_NTH_DAY_OF_WEEK:
                /*
                ** Mm.n.d - nth "dth day" of month m.
                */
-               value = janfirst;
-               for (i = 0; i < rulep->r_mon - 1; ++i)
-                       value += mon_lengths[leapyear][i] * SECSPERDAY;
 
                /*
                ** Use Zeller's Congruence to get day-of-week of first day of
@@ -886,15 +912,17 @@ transtime(const time_t janfirst, const int year,
                /*
                ** "d" is the day-of-month (zero-origin) of the day we want.
                */
-               value += d * SECSPERDAY;
+               value = d * SECSPERDAY;
+               for (i = 0; i < rulep->r_mon - 1; ++i)
+                       value += mon_lengths[leapyear][i] * SECSPERDAY;
                break;
        }
 
        /*
-       ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
-       ** question. To get the Epoch-relative time of the specified local
+       ** "value" is the year-relative time of 00:00:00 UT on the day in
+       ** question. To get the year-relative time of the specified local
        ** time on that day, add the transition time and the current offset
-       ** from UTC.
+       ** from UT.
        */
        return value + rulep->r_time + offset;
 }
@@ -911,12 +939,11 @@ tzparse(const char *name, struct state * const sp, const int lastditch)
        const char *                    dstname;
        size_t                          stdlen;
        size_t                          dstlen;
-       long                            stdoffset;
-       long                            dstoffset;
-       time_t *                atp;
-       unsigned char * typep;
-       char *                  cp;
-       int                     load_result;
+       int_fast32_t                    stdoffset;
+       int_fast32_t                    dstoffset;
+       char *                          cp;
+       int                             load_result;
+       static struct ttinfo            zttinfo;
 
        INITIALIZE(dstname);
        stdname = name;
@@ -940,12 +967,10 @@ tzparse(const char *name, struct state * const sp, const int lastditch)
                        stdlen = name - stdname;
                }
                if (*name == '\0')
-                       return -1;      /* was "stdoffset = 0;" */
-               else {
-                       name = getoffset(name, &stdoffset);
-                       if (name == NULL)
-                               return -1;
-               }
+                       return -1;
+               name = getoffset(name, &stdoffset);
+               if (name == NULL)
+                       return -1;
        }
        load_result = tzload(TZDEFRULES, sp, FALSE);
        if (load_result != 0)
@@ -973,10 +998,10 @@ tzparse(const char *name, struct state * const sp, const int lastditch)
                if (*name == ',' || *name == ';') {
                        struct rule     start;
                        struct rule     end;
-                       int     year;
-                       time_t  janfirst;
-                       time_t          starttime;
-                       time_t          endtime;
+                       int             year;
+                       int             yearlim;
+                       int             timecnt;
+                       time_t          janfirst;
 
                        ++name;
                        if ((name = getrule(name, &start)) == NULL)
@@ -991,51 +1016,61 @@ tzparse(const char *name, struct state * const sp, const int lastditch)
                        /*
                        ** Two transitions per year, from EPOCH_YEAR forward.
                        */
+                       sp->ttis[0] = sp->ttis[1] = zttinfo;
                        sp->ttis[0].tt_gmtoff = -dstoffset;
                        sp->ttis[0].tt_isdst = 1;
                        sp->ttis[0].tt_abbrind = stdlen + 1;
                        sp->ttis[1].tt_gmtoff = -stdoffset;
                        sp->ttis[1].tt_isdst = 0;
                        sp->ttis[1].tt_abbrind = 0;
-                       atp = sp->ats;
-                       typep = sp->types;
+                       timecnt = 0;
                        janfirst = 0;
-                       sp->timecnt = 0;
-                       for (year = EPOCH_YEAR;
-                           sp->timecnt + 2 <= TZ_MAX_TIMES;
-                           ++year) {
-                               time_t  newfirst;
-
-                               starttime = transtime(janfirst, year, &start,
-                                       stdoffset);
-                               endtime = transtime(janfirst, year, &end,
-                                       dstoffset);
-                               if (starttime > endtime) {
-                                       *atp++ = endtime;
-                                       *typep++ = 1;   /* DST ends */
-                                       *atp++ = starttime;
-                                       *typep++ = 0;   /* DST begins */
-                               } else {
-                                       *atp++ = starttime;
-                                       *typep++ = 0;   /* DST begins */
-                                       *atp++ = endtime;
-                                       *typep++ = 1;   /* DST ends */
+                       yearlim = EPOCH_YEAR + YEARSPERREPEAT;
+                       for (year = EPOCH_YEAR; year < yearlim; year++) {
+                               int_fast32_t
+                                 starttime = transtime(year, &start, stdoffset),
+                                 endtime = transtime(year, &end, dstoffset);
+                               int_fast32_t
+                                 yearsecs = (year_lengths[isleap(year)]
+                                             * SECSPERDAY);
+                               int reversed = endtime < starttime;
+                               if (reversed) {
+                                       int_fast32_t swap = starttime;
+                                       starttime = endtime;
+                                       endtime = swap;
+                               }
+                               if (reversed
+                                   || (starttime < endtime
+                                       && (endtime - starttime
+                                           < (yearsecs
+                                              + (stdoffset - dstoffset))))) {
+                                       if (TZ_MAX_TIMES - 2 < timecnt)
+                                               break;
+                                       yearlim = year + YEARSPERREPEAT + 1;
+                                       sp->ats[timecnt] = janfirst;
+                                       if (increment_overflow_time
+                                           (&sp->ats[timecnt], starttime))
+                                               break;
+                                       sp->types[timecnt++] = reversed;
+                                       sp->ats[timecnt] = janfirst;
+                                       if (increment_overflow_time
+                                           (&sp->ats[timecnt], endtime))
+                                               break;
+                                       sp->types[timecnt++] = !reversed;
                                }
-                               sp->timecnt += 2;
-                               newfirst = janfirst;
-                               newfirst += year_lengths[isleap(year)] *
-                                       SECSPERDAY;
-                               if (newfirst <= janfirst)
+                               if (increment_overflow_time(&janfirst, yearsecs))
                                        break;
-                               janfirst = newfirst;
                        }
+                       sp->timecnt = timecnt;
+                       if (!timecnt)
+                               sp->typecnt = 1;        /* Perpetual DST.  */
                } else {
-                       long    theirstdoffset;
-                       long    theirdstoffset;
-                       long    theiroffset;
-                       int     isdst;
-                       int     i;
-                       int     j;
+                       int_fast32_t    theirstdoffset;
+                       int_fast32_t    theirdstoffset;
+                       int_fast32_t    theiroffset;
+                       int             isdst;
+                       int             i;
+                       int             j;
 
                        if (*name != '\0')
                                return -1;
@@ -1104,8 +1139,8 @@ tzparse(const char *name, struct state * const sp, const int lastditch)
                        }
                        /*
                        ** Finally, fill in ttis.
-                       ** ttisstd and ttisgmt need not be handled.
                        */
+                       sp->ttis[0] = sp->ttis[1] = zttinfo;
                        sp->ttis[0].tt_gmtoff = -stdoffset;
                        sp->ttis[0].tt_isdst = FALSE;
                        sp->ttis[0].tt_abbrind = 0;
@@ -1118,6 +1153,7 @@ tzparse(const char *name, struct state * const sp, const int lastditch)
                dstlen = 0;
                sp->typecnt = 1;                /* only standard time */
                sp->timecnt = 0;
+               sp->ttis[0] = zttinfo;
                sp->ttis[0].tt_gmtoff = -stdoffset;
                sp->ttis[0].tt_isdst = 0;
                sp->ttis[0].tt_abbrind = 0;
@@ -1128,11 +1164,11 @@ tzparse(const char *name, struct state * const sp, const int lastditch)
        if ((size_t) sp->charcnt > sizeof sp->chars)
                return -1;
        cp = sp->chars;
-       (void) strncpy(cp, stdname, stdlen);
+       strncpy(cp, stdname, stdlen);
        cp += stdlen;
        *cp++ = '\0';
        if (dstlen != 0) {
-               (void) strncpy(cp, dstname, dstlen);
+               strncpy(cp, dstname, dstlen);
                *(cp + dstlen) = '\0';
        }
        return 0;
@@ -1142,7 +1178,7 @@ static void
 gmtload(struct state * const sp)
 {
        if (tzload(gmt, sp, TRUE) != 0)
-               (void) tzparse(gmt, sp, TRUE);
+               tzparse(gmt, sp, TRUE);
 }
 
 static void
@@ -1160,7 +1196,7 @@ tzsetwall_basic(int rdlocked)
        _RWLOCK_WRLOCK(&lcl_rwlock);
        lcl_is_set = -1;
 
-       if (tzload((char *) NULL, lclptr, TRUE) != 0)
+       if (tzload(NULL, lclptr, TRUE) != 0)
                gmtload(lclptr);
        settzname();
        _RWLOCK_UNLOCK(&lcl_rwlock);
@@ -1198,7 +1234,7 @@ tzset_basic(int rdlocked)
        _RWLOCK_WRLOCK(&lcl_rwlock);
        lcl_is_set = strlen(name) < sizeof lcl_TZname;
        if (lcl_is_set)
-               (void) strcpy(lcl_TZname, name);
+               strcpy(lcl_TZname, name);
 
        if (*name == '\0') {
                /*
@@ -1210,10 +1246,10 @@ tzset_basic(int rdlocked)
                lclptr->ttis[0].tt_isdst = 0;
                lclptr->ttis[0].tt_gmtoff = 0;
                lclptr->ttis[0].tt_abbrind = 0;
-               (void) strcpy(lclptr->chars, gmt);
+               strcpy(lclptr->chars, gmt);
        } else if (tzload(name, lclptr, TRUE) != 0)
                if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
-                       (void) gmtload(lclptr);
+                       gmtload(lclptr);
        settzname();
        _RWLOCK_UNLOCK(&lcl_rwlock);
 
@@ -1238,7 +1274,8 @@ tzset(void)
 
 /*ARGSUSED*/
 static struct tm *
-localsub(const time_t * const timep, const long offset, struct tm * const tmp)
+localsub(const time_t * const timep, const int_fast32_t offset __unused,
+        struct tm * const tmp)
 {
        struct state *          sp;
        const struct ttinfo *   ttisp;
@@ -1247,25 +1284,19 @@ localsub(const time_t * const timep, const long offset, struct tm * const tmp)
        const time_t            t = *timep;
 
        sp = lclptr;
+
        if ((sp->goback && t < sp->ats[0]) ||
                (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
-                       time_t                  newt = t;
+                       time_t          newt = t;
                        time_t          seconds;
-                       time_t          tcycles;
-                       int_fast64_t    icycles;
+                       time_t          years;
 
                        if (t < sp->ats[0])
                                seconds = sp->ats[0] - t;
                        else    seconds = t - sp->ats[sp->timecnt - 1];
                        --seconds;
-                       tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
-                       ++tcycles;
-                       icycles = tcycles;
-                       if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
-                               return NULL;
-                       seconds = icycles;
-                       seconds *= YEARSPERREPEAT;
-                       seconds *= AVGSECSPERYEAR;
+                       years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
+                       seconds = years * AVGSECSPERYEAR;
                        if (t < sp->ats[0])
                                newt += seconds;
                        else    newt -= seconds;
@@ -1278,8 +1309,8 @@ localsub(const time_t * const timep, const long offset, struct tm * const tmp)
 
                                newy = tmp->tm_year;
                                if (t < sp->ats[0])
-                                       newy -= icycles * YEARSPERREPEAT;
-                               else    newy += icycles * YEARSPERREPEAT;
+                                       newy -= years;
+                               else    newy += years;
                                tmp->tm_year = newy;
                                if (tmp->tm_year != newy)
                                        return NULL;
@@ -1287,12 +1318,7 @@ localsub(const time_t * const timep, const long offset, struct tm * const tmp)
                        return result;
        }
        if (sp->timecnt == 0 || t < sp->ats[0]) {
-               i = 0;
-               while (sp->ttis[i].tt_isdst)
-                       if (++i >= sp->typecnt) {
-                               i = 0;
-                               break;
-                       }
+               i = sp->defaulttype;
        } else {
                int     lo = 1;
                int     hi = sp->timecnt;
@@ -1335,7 +1361,7 @@ localtime(const time_t * const timep)
        struct tm *p_tm;
 
        if (__isthreaded != 0) {
-               _once(&localtime_once, localtime_key_init);
+               _pthread_once(&localtime_once, localtime_key_init);
                if (localtime_key_error != 0) {
                        errno = localtime_key_error;
                        return(NULL);
@@ -1376,7 +1402,7 @@ localtime_r(const time_t * const timep, struct tm *tmp)
 static void
 gmt_init(void)
 {
-               gmtload(gmtptr);
+       gmtload(gmtptr);
 }
 
 /*
@@ -1384,7 +1410,8 @@ gmt_init(void)
 */
 
 static struct tm *
-gmtsub(const time_t * const timep, const long offset, struct tm * const tmp)
+gmtsub(const time_t * const timep, const int_fast32_t offset,
+       struct tm * const tmp)
 {
        struct tm *     result;
 
@@ -1393,14 +1420,13 @@ gmtsub(const time_t * const timep, const long offset, struct tm * const tmp)
 #ifdef TM_ZONE
        /*
        ** Could get fancy here and deliver something such as
-       ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
+       ** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
        ** but this is no time for a treasure hunt.
        */
        if (offset != 0)
                tmp->TM_ZONE = wildabbr;
-       else {
+       else
                tmp->TM_ZONE = gmtptr->chars;
-       }
 #endif /* defined TM_ZONE */
        return result;
 }
@@ -1408,7 +1434,6 @@ gmtsub(const time_t * const timep, const long offset, struct tm * const tmp)
 static void
 gmtime_key_init(void)
 {
-
        gmtime_key_error = _pthread_key_create(&gmtime_key, free);
 }
 
@@ -1418,7 +1443,7 @@ gmtime(const time_t * const timep)
        struct tm *p_tm;
 
        if (__isthreaded != 0) {
-               _once(&gmtime_once, gmtime_key_init);
+               _pthread_once(&gmtime_once, gmtime_key_init);
                if (gmtime_key_error != 0) {
                        errno = gmtime_key_error;
                        return(NULL);
@@ -1434,35 +1459,28 @@ gmtime(const time_t * const timep)
                        }
                        _pthread_setspecific(gmtime_key, p_tm);
                }
-               gmtsub(timep, 0L, p_tm);
-               return(p_tm);
-       }
-       else {
-               gmtsub(timep, 0L, &tm);
-               return(&tm);
+               return gmtsub(timep, 0L, p_tm);
+       } else {
+               return gmtsub(timep, 0L, &tm);
        }
 }
 
 /*
-* Re-entrant version of gmtime.
-*/
+ * Re-entrant version of gmtime.
+ */
 
 struct tm *
-gmtime_r(const time_t * const timep, struct tm *tmp)
+gmtime_r(const time_t * timep, struct tm * tmp)
 {
        return gmtsub(timep, 0L, tmp);
 }
 
-#ifdef STD_INSPIRED
-
 struct tm *
 offtime(const time_t * const timep, const long offset)
 {
        return gmtsub(timep, offset, &tm);
 }
 
-#endif /* defined STD_INSPIRED */
-
 /*
 ** Return the number of leap years through the end of the given year
 ** where, to make the math easy, the answer for year zero is defined as zero.
@@ -1476,22 +1494,23 @@ leaps_thru_end_of(const int y)
 }
 
 static struct tm *
-timesub(const time_t * const timep, const long offset,
-    const struct state * const sp, struct tm * const tmp)
+timesub(const time_t * const timep, const int_fast32_t offset,
+       const struct state * const sp, struct tm * const tmp)
 {
        const struct lsinfo *   lp;
        time_t                  tdays;
        int                     idays;  /* unsigned would be so 2003 */
-       long                    rem;
+       int_fast64_t            rem;
        int                     y;
        const int *             ip;
-       long                    corr;
+       int_fast64_t            corr;
        int                     hit;
        int                     i;
 
        corr = 0;
        hit = 0;
        i = sp->leapcnt;
+
        while (--i >= 0) {
                lp = &sp->lsis[i];
                if (*timep >= lp->ls_trans) {
@@ -1516,15 +1535,16 @@ timesub(const time_t * const timep, const long offset,
        tdays = *timep / SECSPERDAY;
        rem = *timep - tdays * SECSPERDAY;
        while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
-               int             newy;
+               int     newy;
                time_t  tdelta;
                int     idelta;
                int     leapdays;
 
                tdelta = tdays / DAYSPERLYEAR;
-               idelta = tdelta;
-               if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
+               if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
+                      && tdelta <= INT_MAX))
                        return NULL;
+               idelta = tdelta;
                if (idelta == 0)
                        idelta = (tdays < 0) ? -1 : 1;
                newy = y;
@@ -1537,9 +1557,9 @@ timesub(const time_t * const timep, const long offset,
                y = newy;
        }
        {
-               long    seconds;
+               int_fast32_t    seconds;
 
-               seconds = tdays * SECSPERDAY + 0.5;
+               seconds = tdays * SECSPERDAY;
                tdays = seconds / SECSPERDAY;
                rem += seconds - tdays * SECSPERDAY;
        }
@@ -1635,27 +1655,51 @@ ctime_r(const time_t * const timep, char *buf)
 #endif /* !defined WRONG */
 
 /*
-** Simplified normalize logic courtesy Paul Eggert.
+** Normalize logic courtesy Paul Eggert.
 */
 
 static int
-increment_overflow(int *number, int delta)
+increment_overflow(int * const ip, int j)
 {
-       int     number0;
+       int const       i = *ip;
 
-       number0 = *number;
-       *number += delta;
-       return (*number < number0) != (delta < 0);
+       /*
+       ** If i >= 0 there can only be overflow if i + j > INT_MAX
+       ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
+       ** If i < 0 there can only be overflow if i + j < INT_MIN
+       ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
+       */
+       if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
+               return TRUE;
+       *ip += j;
+       return FALSE;
 }
 
 static int
-long_increment_overflow(long *number, int delta)
+increment_overflow32(int_fast32_t * const lp, int const m)
 {
-       long    number0;
+       int_fast32_t const      l = *lp;
 
-       number0 = *number;
-       *number += delta;
-       return (*number < number0) != (delta < 0);
+       if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
+               return TRUE;
+       *lp += m;
+       return FALSE;
+}
+
+static int
+increment_overflow_time(time_t *tp, int_fast32_t j)
+{
+       /*
+       ** This is like
+       ** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...',
+       ** except that it does the right thing even if *tp + j would overflow.
+       */
+       if (! (j < 0
+              ? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
+              : *tp <= time_t_max - j))
+               return TRUE;
+       *tp += j;
+       return FALSE;
 }
 
 static int
@@ -1671,8 +1715,8 @@ normalize_overflow(int * const tensptr, int * const unitsptr, const int base)
 }
 
 static int
-long_normalize_overflow(long * const tensptr, int * const unitsptr,
-    const int base)
+normalize_overflow32(int_fast32_t * const tensptr, int * const unitsptr,
+                    const int base)
 {
        int     tensdelta;
 
@@ -1680,7 +1724,7 @@ long_normalize_overflow(long * const tensptr, int * const unitsptr,
                (*unitsptr / base) :
                (-1 - (-1 - *unitsptr) / base);
        *unitsptr -= tensdelta * base;
-       return long_increment_overflow(tensptr, tensdelta);
+       return increment_overflow32(tensptr, tensdelta);
 }
 
 static int
@@ -1688,8 +1732,9 @@ tmcomp(const struct tm * const atmp, const struct tm * const btmp)
 {
        int     result;
 
-       if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
-               (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+       if (atmp->tm_year != btmp->tm_year)
+               return atmp->tm_year < btmp->tm_year ? -1 : 1;
+       if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
                (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
                (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
                (result = (atmp->tm_min - btmp->tm_min)) == 0)
@@ -1699,17 +1744,17 @@ tmcomp(const struct tm * const atmp, const struct tm * const btmp)
 
 static time_t
 time2sub(struct tm * const tmp,
-    struct tm * (* const funcp)(const time_t *, long, struct tm *),
-    const long offset, int * const okayp, const int do_norm_secs)
+      struct tm * (* const funcp)(const time_t *, int_fast32_t, struct tm *),
+      const int_fast32_t offset, int * const okayp, const int do_norm_secs)
 {
        const struct state *    sp;
        int                     dir;
        int                     i, j;
        int                     saved_seconds;
-       long                    li;
+       int_fast32_t            li;
        time_t                  lo;
        time_t                  hi;
-       long                    y;
+       int_fast32_t            y;
        time_t                  newt;
        time_t                  t;
        struct tm               yourtm, mytm;
@@ -1726,16 +1771,16 @@ time2sub(struct tm * const tmp,
        if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
                return WRONG;
        y = yourtm.tm_year;
-       if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
+       if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
                return WRONG;
        /*
        ** Turn y into an actual year number for now.
        ** It is converted back to an offset from TM_YEAR_BASE later.
        */
-       if (long_increment_overflow(&y, TM_YEAR_BASE))
+       if (increment_overflow32(&y, TM_YEAR_BASE))
                return WRONG;
        while (yourtm.tm_mday <= 0) {
-               if (long_increment_overflow(&y, -1))
+               if (increment_overflow32(&y, -1))
                        return WRONG;
                li = y + (1 < yourtm.tm_mon);
                yourtm.tm_mday += year_lengths[isleap(li)];
@@ -1743,7 +1788,7 @@ time2sub(struct tm * const tmp,
        while (yourtm.tm_mday > DAYSPERLYEAR) {
                li = y + (1 < yourtm.tm_mon);
                yourtm.tm_mday -= year_lengths[isleap(li)];
-               if (long_increment_overflow(&y, 1))
+               if (increment_overflow32(&y, 1))
                        return WRONG;
        }
        for ( ; ; ) {
@@ -1753,18 +1798,15 @@ time2sub(struct tm * const tmp,
                yourtm.tm_mday -= i;
                if (++yourtm.tm_mon >= MONSPERYEAR) {
                        yourtm.tm_mon = 0;
-                       if (long_increment_overflow(&y, 1))
+                       if (increment_overflow32(&y, 1))
                                return WRONG;
                }
        }
-       if (long_increment_overflow(&y, -TM_YEAR_BASE))
+       if (increment_overflow32(&y, -TM_YEAR_BASE))
                return WRONG;
        yourtm.tm_year = y;
        if (yourtm.tm_year != y)
                return WRONG;
-       /* Don't go below 1900 for POLA */
-       if (yourtm.tm_year < 0)
-               return WRONG;
        if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
                saved_seconds = 0;
        else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
@@ -1790,11 +1832,6 @@ time2sub(struct tm * const tmp,
        if (!TYPE_SIGNED(time_t)) {
                lo = 0;
                hi = lo - 1;
-       } else if (!TYPE_INTEGRAL(time_t)) {
-               if (sizeof(time_t) > sizeof(float))
-                       hi = (time_t) DBL_MAX;
-               else    hi = (time_t) FLT_MAX;
-               lo = -hi;
        } else {
                lo = 1;
                for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
@@ -1817,14 +1854,14 @@ time2sub(struct tm * const tmp,
                } else  dir = tmcomp(&mytm, &yourtm);
                if (dir != 0) {
                        if (t == lo) {
-                               ++t;
-                               if (t <= lo)
+                               if (t == time_t_max)
                                        return WRONG;
+                               ++t;
                                ++lo;
                        } else if (t == hi) {
-                               --t;
-                               if (t >= hi)
+                               if (t == time_t_min)
                                        return WRONG;
+                               --t;
                                --hi;
                        }
                        if (lo > hi)
@@ -1844,6 +1881,7 @@ time2sub(struct tm * const tmp,
                */
                sp = (const struct state *)
                        ((funcp == localsub) ? lclptr : gmtptr);
+
                for (i = sp->typecnt - 1; i >= 0; --i) {
                        if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
                                continue;
@@ -1879,8 +1917,8 @@ label:
 
 static time_t
 time2(struct tm * const tmp,
-    struct tm * (* const funcp)(const time_t *, long, struct tm *),
-    const long offset, int * const okayp)
+      struct tm * (* const funcp)(const time_t *, int_fast32_t, struct tm *),
+      const int_fast32_t offset, int * const okayp)
 {
        time_t  t;
 
@@ -1894,9 +1932,9 @@ time2(struct tm * const tmp,
 }
 
 static time_t
-time1(struct tm *tmp,
-    struct tm * (* const funcp)(const time_t *, long, struct tm *),
-    const long offset)
+time1(struct tm * const tmp,
+      struct tm * (* const funcp)(const time_t *, int_fast32_t, struct tm *),
+      const int_fast32_t offset)
 {
        time_t                  t;
        const struct state *    sp;
@@ -1904,18 +1942,18 @@ time1(struct tm *tmp,
        int                     sameind, otherind;
        int                     i;
        int                     nseen;
-       int                             seen[TZ_MAX_TYPES];
-       int                             types[TZ_MAX_TYPES];
-       int                             okay;
+       int                     seen[TZ_MAX_TYPES];
+       int                     types[TZ_MAX_TYPES];
+       int                     okay;
 
        if (tmp == NULL) {
                errno = EINVAL;
                return WRONG;
        }
-
        if (tmp->tm_isdst > 1)
                tmp->tm_isdst = 1;
        t = time2(tmp, funcp, offset, &okay);
+
        /*
        ** PCTS code courtesy Grant Sullivan.
        */
@@ -1923,13 +1961,15 @@ time1(struct tm *tmp,
                return t;
        if (tmp->tm_isdst < 0)
                tmp->tm_isdst = 0;      /* reset to std and try again */
+
        /*
        ** We're supposed to assume that somebody took a time of one type
        ** and did some math on it that yielded a "struct tm" that's bad.
        ** We try to divine the type they started from and adjust to the
        ** type they need.
        */
-       sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
+       sp = (const struct state *) ((funcp == localsub) ?  lclptr : gmtptr);
+
        for (i = 0; i < sp->typecnt; ++i)
                seen[i] = FALSE;
        nseen = 0;
@@ -1971,8 +2011,6 @@ mktime(struct tm * const tmp)
        return(mktime_return_value);
 }
 
-#ifdef STD_INSPIRED
-
 time_t
 timelocal(struct tm * const tmp)
 {
@@ -1997,14 +2035,10 @@ timeoff(struct tm * const tmp, const long offset)
        return time1(tmp, gmtsub, offset);
 }
 
-#endif /* defined STD_INSPIRED */
-
 /*
 ** XXX--is the below the right way to conditionalize??
 */
 
-#ifdef STD_INSPIRED
-
 /*
 ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
 ** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
@@ -2013,7 +2047,7 @@ timeoff(struct tm * const tmp, const long offset)
 ** when exchanging timestamps with POSIX conforming systems.
 */
 
-static long
+static int_fast64_t
 leapcorr(time_t *timep)
 {
        struct state *          sp;
@@ -2069,5 +2103,3 @@ posix2time(time_t t)
        }
        return x;
 }
-
-#endif /* defined STD_INSPIRED */
index 544dd80..fe65848 100644 (file)
@@ -1,24 +1,19 @@
+/*
+ * $FreeBSD: head/contrib/tzcode/stdtime/private.h 192625 2009-05-23 06:31:50Z edwin $
+ */
+
 #ifndef PRIVATE_H
 
 #define PRIVATE_H
-
 /*
 ** This file is in the public domain, so clarified as of
 ** 1996-06-05 by Arthur David Olson.
-**
-** $FreeBSD: head/contrib/tzcode/stdtime/private.h 192625 2009-05-23 06:31:50Z edwin $
 */
 
 /* Stuff moved from Makefile.inc to reduce clutter */
 #ifndef TM_GMTOFF
 #define TM_GMTOFF      tm_gmtoff
 #define TM_ZONE                tm_zone
-#define STD_INSPIRED   1
-#define PCTS           1
-#define HAVE_LONG_DOUBLE 1
-#define HAVE_STRERROR  1
-#define        HAVE_UNISTD_H   1
-#define        LOCALE_HOME     _PATH_LOCALE
 #define TZDIR          "/usr/share/zoneinfo"
 #endif /* ndef TM_GMTOFF */
 
 ** Thank you!
 */
 
-/*
-** ID
-*/
-
-#ifndef lint
-#ifndef NOID
-/*
-static char    privatehid[] = "@(#)private.h   8.6";
-*/
-#endif /* !defined NOID */
-#endif /* !defined lint */
-
 #define GRANDPARENTED  "Local time zone must be set--see zic manual page"
 
 /*
@@ -49,51 +32,10 @@ static char privatehid[] = "@(#)private.h   8.6";
 ** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
 */
 
-#ifndef HAVE_ADJTIME
-#define HAVE_ADJTIME           1
-#endif /* !defined HAVE_ADJTIME */
-
 #ifndef HAVE_GETTEXT
 #define HAVE_GETTEXT           0
 #endif /* !defined HAVE_GETTEXT */
 
-#ifndef HAVE_INCOMPATIBLE_CTIME_R
-#define HAVE_INCOMPATIBLE_CTIME_R      0
-#endif /* !defined INCOMPATIBLE_CTIME_R */
-
-#ifndef HAVE_SETTIMEOFDAY
-#define HAVE_SETTIMEOFDAY      3
-#endif /* !defined HAVE_SETTIMEOFDAY */
-
-#ifndef HAVE_SYMLINK
-#define HAVE_SYMLINK           1
-#endif /* !defined HAVE_SYMLINK */
-
-#ifndef HAVE_SYS_STAT_H
-#define HAVE_SYS_STAT_H                1
-#endif /* !defined HAVE_SYS_STAT_H */
-
-#ifndef HAVE_SYS_WAIT_H
-#define HAVE_SYS_WAIT_H                1
-#endif /* !defined HAVE_SYS_WAIT_H */
-
-#ifndef HAVE_UNISTD_H
-#define HAVE_UNISTD_H          1
-#endif /* !defined HAVE_UNISTD_H */
-
-#ifndef HAVE_UTMPX_H
-#define HAVE_UTMPX_H           0
-#endif /* !defined HAVE_UTMPX_H */
-
-#ifndef LOCALE_HOME
-#define LOCALE_HOME            "/usr/lib/locale"
-#endif /* !defined LOCALE_HOME */
-
-#if HAVE_INCOMPATIBLE_CTIME_R
-#define asctime_r _incompatible_asctime_r
-#define ctime_r _incompatible_ctime_r
-#endif /* HAVE_INCOMPATIBLE_CTIME_R */
-
 /*
 ** Nested includes
 */
@@ -110,94 +52,22 @@ static char        privatehid[] = "@(#)private.h   8.6";
 #include "libintl.h"
 #endif /* HAVE_GETTEXT */
 
-#if HAVE_SYS_WAIT_H
 #include <sys/wait.h>  /* for WIFEXITED and WEXITSTATUS */
-#endif /* HAVE_SYS_WAIT_H */
-
-#ifndef WIFEXITED
-#define WIFEXITED(status)      (((status) & 0xff) == 0)
-#endif /* !defined WIFEXITED */
-#ifndef WEXITSTATUS
-#define WEXITSTATUS(status)    (((status) >> 8) & 0xff)
-#endif /* !defined WEXITSTATUS */
 
-#if HAVE_UNISTD_H
 #include "unistd.h"    /* for F_OK, R_OK, and other POSIX goodness */
-#endif /* HAVE_UNISTD_H */
-
-#if !(HAVE_UNISTD_H)
-#ifndef F_OK
-#define F_OK   0
-#endif /* !defined F_OK */
-#ifndef R_OK
-#define R_OK   4
-#endif /* !defined R_OK */
-#endif /* !(HAVE_UNISTD_H) */
 
 /* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
 #define is_digit(c) ((unsigned)(c) - '0' <= 9)
 
-/*
-** Define HAVE_STDINT_H's default value here, rather than at the
-** start, since __GLIBC__'s value depends on previously-included
-** files.
-** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.)
-*/
-#ifndef HAVE_STDINT_H
-#define HAVE_STDINT_H \
-       (199901 <= __STDC_VERSION__ || \
-       2 < (__GLIBC__ + (0 < __GLIBC_MINOR__)))
-#endif /* !defined HAVE_STDINT_H */
-
-#if HAVE_STDINT_H
 #include "stdint.h"
-#endif /* !HAVE_STDINT_H */
-
-#ifndef INT_FAST64_MAX
-/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX.  */
-#if defined LLONG_MAX || defined __LONG_LONG_MAX__
-typedef long long      int_fast64_t;
-#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
-#if (LONG_MAX >> 31) < 0xffffffff
-Please use a compiler that supports a 64-bit integer type (or wider);
-you may need to compile with "-DHAVE_STDINT_H".
-#endif /* (LONG_MAX >> 31) < 0xffffffff */
-typedef long           int_fast64_t;
-#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
-#endif /* !defined INT_FAST64_MAX */
-
-#ifndef INT32_MAX
-#define INT32_MAX 0x7fffffff
-#endif /* !defined INT32_MAX */
-#ifndef INT32_MIN
-#define INT32_MIN (-1 - INT32_MAX)
-#endif /* !defined INT32_MIN */
-
-/*
-** Workarounds for compilers/systems.
-*/
-
-/*
-** Some time.h implementations don't declare asctime_r.
-** Others might define it as a macro.
-** Fix the former without affecting the latter.
-*/
-
-#ifndef asctime_r
-extern char *  asctime_r(struct tm const *, char *);
-#endif
+#include <inttypes.h>
 
 /*
 ** Private function declarations.
 */
 
-char *         icalloc(int nelem, int elsize);
 char *         icatalloc(char * old, const char * new);
 char *         icpyalloc(const char * string);
-char *         imalloc(int n);
-void *         irealloc(void * pointer, int size);
-void           icfree(char * pointer);
-void           ifree(char * pointer);
 const char *   scheck(const char * string, const char * format);
 
 /*
@@ -220,14 +90,15 @@ const char *       scheck(const char * string, const char * format);
 #define TYPE_SIGNED(type) (((type) -1) < 0)
 #endif /* !defined TYPE_SIGNED */
 
-/*
-** Since the definition of TYPE_INTEGRAL contains floating point numbers,
-** it cannot be used in preprocessor directives.
-*/
-
-#ifndef TYPE_INTEGRAL
-#define        TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
-#endif /* !defined TYPE_INTEGRAL */
+/* The minimum and maximum finite time values.  */
+static time_t const time_t_min =
+  (TYPE_SIGNED(time_t)
+   ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
+   : 0);
+static time_t const time_t_max =
+  (TYPE_SIGNED(time_t)
+   ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
+   : -1);
 
 /*
 ** Since the definition of TYPE_INTEGRAL contains floating point numbers,
@@ -292,13 +163,6 @@ const char *       scheck(const char * string, const char * format);
 #define TZ_DOMAIN "tz"
 #endif /* !defined TZ_DOMAIN */
 
-#if HAVE_INCOMPATIBLE_CTIME_R
-#undef asctime_r
-#undef ctime_r
-char *asctime_r(struct tm const *, char *);
-char *ctime_r(time_t const *, char *);
-#endif /* HAVE_INCOMPATIBLE_CTIME_R */
-  
 #ifndef YEARSPERREPEAT
 #define YEARSPERREPEAT         400     /* years before a Gregorian repeat */
 #endif /* !defined YEARSPERREPEAT */
index 472e17e..56022e6 100644 (file)
@@ -13,7 +13,7 @@
 .\" 2. Redistributions in binary form must reproduce the above copyright
 .\"    notice, this list of conditions and the following disclaimer in the
 .\"    documentation and/or other materials provided with the distribution.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 3. Neither the name of the University nor the names of its contributors
 .\"    may be used to endorse or promote products derived from this software
 .\"    without specific prior written permission.
 .\"
@@ -174,8 +174,8 @@ is equivalent to
 .It Cm \&%S
 is replaced by the second as a decimal number (00-60).
 .It Cm %s
-is replaced by the number of seconds since the Epoch, UTC (see
-.Xr mktime 3 ) .
+is replaced by the number of seconds since the Epoch (see
+.Xr ctime 3 ) .
 .It Cm \&%T
 is equivalent to
 .Dq Li %H:%M:%S .
@@ -213,8 +213,10 @@ is replaced by the year without century as a decimal number (00-99).
 .It Cm \&%Z
 is replaced by the time zone name.
 .It Cm %z
-is replaced by the time zone offset from UTC; a leading plus sign stands for
-east of UTC, a minus sign for west of UTC, hours and minutes follow
+is replaced by the offset from the Prime Meridian;
+a leading plus sign stands for
+east of Greenwich, a minus sign for west of Greenwich,
+hours and minutes follow
 with two digits each and no delimiter between them (common form for
 RFC 822 date headers).
 .It Cm %+
index afdd4ee..7da1e69 100644 (file)
@@ -87,18 +87,18 @@ strftime_l(char * __restrict s, size_t maxsize, const char * __restrict format,
        p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, loc);
 #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
        if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
-               (void) fprintf_l(stderr, loc, "\n");
+               fprintf_l(stderr, loc, "\n");
                if (format == NULL)
-                       (void) fprintf_l(stderr, loc, "NULL strftime format ");
-               else    (void) fprintf_l(stderr, loc, "strftime format \"%s\" ",
+                       fprintf_l(stderr, loc, "NULL strftime format ");
+               else    fprintf_l(stderr, loc, "strftime format \"%s\" ",
                                format);
-               (void) fprintf_l(stderr, loc, "yields only two digits of years in ");
+               fprintf_l(stderr, loc, "yields only two digits of years in ");
                if (warn == IN_SOME)
-                       (void) fprintf_l(stderr, loc, "some locales");
+                       fprintf_l(stderr, loc, "some locales");
                else if (warn == IN_THIS)
-                       (void) fprintf_l(stderr, loc, "the current locale");
-               else    (void) fprintf_l(stderr, loc, "all locales");
-               (void) fprintf_l(stderr, loc, "\n");
+                       fprintf_l(stderr, loc, "the current locale");
+               else    fprintf_l(stderr, loc, "all locales");
+               fprintf_l(stderr, loc, "\n");
        }
 #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
        if (p == s + maxsize)
@@ -302,10 +302,12 @@ label:
                                        tm = *t;
                                        mkt = mktime(&tm);
                                        if (TYPE_SIGNED(time_t))
-                                               (void) sprintf(buf, "%ld",
-                                                       (long) mkt);
-                                       else    (void) sprintf(buf, "%lu",
-                                                       (unsigned long) mkt);
+                                               snprintf(buf, sizeof(buf),
+                                                   "%"PRIdMAX,
+                                                   (intmax_t) mkt);
+                                       else    snprintf(buf, sizeof(buf),
+                                                   "%"PRIuMAX,
+                                                   (uintmax_t) mkt);
                                        pt = _add(buf, pt, ptlim);
                                }
                                continue;
@@ -477,7 +479,7 @@ label:
                                continue;
                        case 'z':
                                {
-                               int             diff;
+                               long            diff;
                                char const *    sign;
 
                                if (t->tm_isdst < 0)
@@ -486,7 +488,7 @@ label:
                                diff = t->TM_GMTOFF;
 #else /* !defined TM_GMTOFF */
                                /*
-                               ** C99 says that the UTC offset must
+                               ** C99 says that the UT offset must
                                ** be computed by looking only at
                                ** tm_isdst. This requirement is
                                ** incorrect, since it means the code
@@ -563,7 +565,7 @@ _conv(const int n, const char * const format, char * const pt,
 {
        char    buf[INT_STRLEN_MAXIMUM(int) + 1];
 
-       (void) sprintf(buf, format, n);
+       snprintf(buf, sizeof(buf), format, n);
        return _add(buf, pt, ptlim);
 }
 
index 189848e..4d34423 100644 (file)
@@ -1,6 +1,6 @@
 .\" $FreeBSD: head/contrib/tzcode/stdtime/time2posix.3 192890 2009-05-27 12:18:39Z edwin $
 .\"
-.Dd September 11, 2005
+.Dd October 19, 2008
 .Dt TIME2POSIX 3
 .Os
 .Sh NAME
@@ -18,7 +18,7 @@
 .Sh DESCRIPTION
 .St -p1003.1-88
 legislates that a time_t value of
-536457599 shall correspond to "Wed Dec 31 23:59:59 GMT 1986."
+536457599 shall correspond to "Wed Dec 31 23:59:59 UTC 1986."
 This effectively implies that POSIX time_t's cannot include leap
 seconds and,
 therefore,
@@ -118,6 +118,5 @@ degenerate to the identity function.
 .Xr localtime 3 ,
 .Xr mktime 3 ,
 .Xr time 3
-.\" @(#)time2posix.3  8.2
 .\" This file is in the public domain, so clarified as of
 .\" 1996-06-05 by Arthur David Olson.
index f11caa2..d6ee06f 100644 (file)
 time_t
 _time32_to_time(__int32_t t32)
 {
-    return((time_t)t32);
+       return((time_t)t32);
 }
 
 /*
  * Convert time_t to a 32 bit representation.  If time_t is 64 bits we can
- * simply chop it down.   The resulting 32 bit representation can be 
+ * simply chop it down.   The resulting 32 bit representation can be
  * converted back to a temporally local 64 bit time_t using time32_to_time.
  */
 __int32_t
 _time_to_time32(time_t t)
 {
-    return((__int32_t)t);
+       return((__int32_t)t);
 }
 
 /*
@@ -45,7 +45,7 @@ _time_to_time32(time_t t)
 time_t
 _time64_to_time(__int64_t t64)
 {
-    return((time_t)t64);
+       return((time_t)t64);
 }
 
 /*
@@ -55,45 +55,45 @@ _time64_to_time(__int64_t t64)
 __int64_t
 _time_to_time64(time_t t)
 {
-    return((__int64_t)t);
+       return((__int64_t)t);
 }
 
 /*
- * Convert to/from 'long'.  Depending on the sizeof(long) this may or 
+ * Convert to/from 'long'.  Depending on the sizeof(long) this may or
  * may not require using the 50-year rule.
  */
 long
 _time_to_long(time_t t)
 {
-    if (sizeof(long) == sizeof(__int64_t))
-       return(_time_to_time64(t));
-    return((long)t);
+       if (sizeof(long) == sizeof(__int64_t))
+               return(_time_to_time64(t));
+       return((long)t);
 }
 
 time_t
 _long_to_time(long tlong)
 {
-    if (sizeof(long) == sizeof(__int32_t))
-       return(_time32_to_time(tlong));
-    return((time_t)tlong);
+       if (sizeof(long) == sizeof(__int32_t))
+               return(_time32_to_time(tlong));
+       return((time_t)tlong);
 }
 
 /*
- * Convert to/from 'int'.  Depending on the sizeof(int) this may or 
+ * Convert to/from 'int'.  Depending on the sizeof(int) this may or
  * may not require using the 50-year rule.
  */
 int
 _time_to_int(time_t t)
 {
-    if (sizeof(int) == sizeof(__int64_t))
-       return(_time_to_time64(t));
-    return((int)t);
+       if (sizeof(int) == sizeof(__int64_t))
+               return(_time_to_time64(t));
+       return((int)t);
 }
 
 time_t
 _int_to_time(int tint)
 {
-    if (sizeof(int) == sizeof(__int32_t))
-       return(_time32_to_time(tint));
-    return((time_t)tint);
+       if (sizeof(int) == sizeof(__int32_t))
+               return(_time32_to_time(tint));
+       return((time_t)tint);
 }
index 1fe62f5..c5cf8d7 100644 (file)
@@ -1,5 +1,5 @@
 .\" $FreeBSD: head/contrib/tzcode/stdtime/tzfile.5 200832 2009-12-22 11:17:10Z edwin $
-.Dd October 19, 2008
+.Dd December 1, 2013
 .Dt TZFILE 5
 .Os
 .Sh NAME
@@ -15,13 +15,14 @@ begin with the magic characters
 to identify them as
 time zone information files,
 followed by a character identifying the version of the file's format
-(as of 2005, either an ASCII
+(as of 2013, either an ASCII
 .Dv NUL
 or a
-.Sq Li 2 )
+.Sq Li 2 ,
+or
+.Sq Li 3 )
 followed by fifteen bytes containing zeroes reserved for future use,
-followed by six four-byte values of type
-.Vt long ,
+followed by six four-byte integer values
 written in a
 .Dq standard
 byte order
@@ -31,7 +32,7 @@ in order:
 .Pp
 .Bl -tag -compact -width tzh_ttisstdcnt
 .It Va tzh_ttisgmtcnt
-The number of UTC/local indicators stored in the file.
+The number of UT/local indicators stored in the file.
 .It Va tzh_ttisstdcnt
 The number of standard/wall indicators stored in the file.
 .It Va tzh_leapcnt
@@ -54,9 +55,7 @@ stored in the file.
 .Pp
 The above header is followed by
 .Va tzh_timecnt
-four-byte values of type
-.Fa long ,
-sorted in ascending order.
+four-byte signed integer values sorted in ascending order.
 These values are written in
 .Dq standard
 byte order.
@@ -65,8 +64,7 @@ Each is used as a transition time (as returned by
 at which the rules for computing local time change.
 Next come
 .Va tzh_timecnt
-one-byte values of type
-.Fa "unsigned char" ;
+one-byte unsigned integer values;
 each one tells which of the different types of
 .Dq local time
 types
@@ -79,23 +77,21 @@ entries) that appears next in the file;
 these structures are defined as follows:
 .Bd -literal -offset indent
 struct ttinfo {
-       long    tt_gmtoff;
-       int     tt_isdst;
-       unsigned int    tt_abbrind;
+       int32_t         tt_gmtoff;
+       unsigned char   tt_isdst;
+       unsigned char   tt_abbrind;
 };
 .Ed
 .Pp
-Each structure is written as a four-byte value for
-.Va tt_gmtoff
-of type
-.Fa long ,
+Each structure is written as a four-byte signed integer value for
+.Fa tt_gmtoff ,
 in a standard byte order, followed by a one-byte value for
 .Va tt_isdst
 and a one-byte value for
 .Va tt_abbrind .
 In each structure,
 .Va tt_gmtoff
-gives the number of seconds to be added to UTC,
+gives the number of seconds to be added to UT,
 .Li tt_isdst
 tells whether
 .Li tm_isdst
@@ -130,13 +126,13 @@ time zone environment variables.
 .Pp
 Finally there are
 .Va tzh_ttisgmtcnt
-UTC/local indicators, each stored as a one-byte value;
+UT/local indicators, each stored as a one-byte value;
 they tell whether the transition times associated with local time types
-were specified as UTC or local time,
+were specified as UT or local time,
 and are used when a time zone file is used in handling POSIX-style
 time zone environment variables.
 .Pp
-.Nm localtime
+.Xr localtime 3
 uses the first standard-time
 .Li ttinfo
 structure in the file
@@ -149,7 +145,7 @@ is zero or the time argument is less than the first transition time recorded
 in the file.
 .Pp
 For version-2-format time zone files,
-the above header and data is followed by a second header and data,
+the above header and data are followed by a second header and data,
 identical in format except that eight bytes are used for each
 transition time or leap second time.
 After the second header and data comes a newline-enclosed,
@@ -157,10 +153,23 @@ POSIX-TZ-environment-variable-style string for use in handling instants
 after the last transition time stored in the file
 (with nothing between the newlines if there is no POSIX representation for
 such instants).
+.Pp
+For version-3-format time zone files, the POSIX-TZ-style string may
+use two minor extensions to the POSIX TZ format, as described in
+.Xr tzset 3 .
+First, the hours part of its transition times may be signed and range from
+-167 through 167 instead of the POSIX-required unsigned values
+from 0 through 24.
+Second, DST is in effect all year if it starts
+January 1 at 00:00 and ends December 31 at 24:00 plus the difference
+between daylight saving and standard time.
+.Pp
+Future changes to the format may append more data.
 .Sh SEE ALSO
 .Xr ctime 3 ,
 .Xr time2posix 3 ,
+.Xr tzset 3 ,
+.Xr zdump 8 ,
 .Xr zic 8
-.\" @(#)tzfile.5       8.3
 .\" This file is in the public domain, so clarified as of
 .\" 1996-06-05 by Arthur David Olson.
index 3078e15..7dba000 100644 (file)
 ** Thank you!
 */
 
-/*
-** ID
-*/
-
-#ifndef lint
-#ifndef NOID
-/*
-static char    tzfilehid[] = "@(#)tzfile.h     8.1";
-*/
-#endif /* !defined NOID */
-#endif /* !defined lint */
-
 /*
 ** Information about time zone files.
 */
@@ -53,7 +41,7 @@ static char   tzfilehid[] = "@(#)tzfile.h     8.1";
 
 struct tzhead {
        char    tzh_magic[4];           /* TZ_MAGIC */
-       char    tzh_version[1];         /* '\0' or '2' as of 2005 */
+       char    tzh_version[1];         /* '\0' or '2' or '3' as of 2013 */
        char    tzh_reserved[15];       /* reserved--must be zero */
        char    tzh_ttisgmtcnt[4];      /* coded number of trans. time flags */
        char    tzh_ttisstdcnt[4];      /* coded number of trans. time flags */
@@ -69,7 +57,7 @@ struct tzhead {
 **     tzh_timecnt (char [4])s         coded transition times a la time(2)
 **     tzh_timecnt (unsigned char)s    types of local time starting at above
 **     tzh_typecnt repetitions of
-**             one (char [4])          coded UTC offset in seconds
+**             one (char [4])          coded UT offset in seconds
 **             one (unsigned char)     used to set tm_isdst
 **             one (unsigned char)     that's an abbreviation list index
 **     tzh_charcnt (char)s             '\0'-terminated zone abbreviations
@@ -82,7 +70,7 @@ struct tzhead {
 **                                     if absent, transition times are
 **                                     assumed to be wall clock time
 **     tzh_ttisgmtcnt (char)s          indexed by type; if TRUE, transition
-**                                     time is UTC, if FALSE,
+**                                     time is UT, if FALSE,
 **                                     transition time is local time
 **                                     if absent, transition times are
 **                                     assumed to be local time
@@ -96,6 +84,13 @@ struct tzhead {
 ** instants after the last transition time stored in the file
 ** (with nothing between the newlines if there is no POSIX representation for
 ** such instants).
+**
+** If tz_version is '3' or greater, the above is extended as follows.
+** First, the POSIX TZ string's hour offset may range from -167
+** through 167 as compared to the POSIX-required 0 through 24.
+** Second, its DST start time may be January 1 at 00:00 and its stop
+** time December 31 at 24:00 plus the difference between DST and
+** standard time, indicating DST all year.
 */
 
 /*
@@ -136,7 +131,7 @@ struct tzhead {
 #define DAYSPERNYEAR   365
 #define DAYSPERLYEAR   366
 #define SECSPERHOUR    (SECSPERMIN * MINSPERHOUR)
-#define SECSPERDAY     ((long) SECSPERHOUR * HOURSPERDAY)
+#define SECSPERDAY     ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
 #define MONSPERYEAR    12
 
 #define TM_SUNDAY      0