Sync back-branch copies of the timezone code with IANA release tzcode2016c.

Back-patch commit 1c1a7cbd6a, along with subsequent portability
fixes, into all active branches.  Also, back-patch commits 696027727 and
596857043 (addition of zic -P option) into 9.1 and 9.2, just to reduce
differences between the branches.  src/timezone/ is now largely identical
in all active branches, except that in 9.1, pgtz.c retains the
initial-timezone-selection code that was moved over to initdb in 9.2.

Ordinarily we wouldn't risk this much code churn in back branches, but it
seems necessary in this case, because among the changes are two feature
additions in the "zic" zone data file compiler (a larger limit on the
number of allowed DST transitions, and addition of a "%z" escape in zone
abbreviations).  IANA have not yet started to use those features in their
tzdata files, but presumably they will before too long.  If we don't update
then we'll be unable to adopt new timezone data.  Also, installations built
with --with-system-tzdata (which includes most distro-supplied builds, I
believe) might fail even if we don't update our copies of the data files.
There are assorted bug fixes too, mostly affecting obscure timezones or
post-2037 dates.

Discussion: <13601.1468868947@sss.pgh.pa.us>
This commit is contained in:
Tom Lane 2016-07-19 15:59:36 -04:00
parent bdeed0944f
commit 19d477aa68
12 changed files with 2138 additions and 1400 deletions

View File

@ -99,15 +99,15 @@ pg_load_tz(const char *name)
*/
if (strcmp(name, "GMT") == 0)
{
if (tzparse(name, &tz.state, TRUE) != 0)
if (!tzparse(name, &tz.state, true))
{
/* This really, really should not happen ... */
return NULL;
}
}
else if (tzload(name, NULL, &tz.state, TRUE) != 0)
else if (tzload(name, NULL, &tz.state, true) != 0)
{
if (name[0] == ':' || tzparse(name, &tz.state, FALSE) != 0)
if (name[0] == ':' || !tzparse(name, &tz.state, false))
{
return NULL; /* unknown timezone */
}

View File

@ -19,7 +19,7 @@ include $(top_builddir)/src/Makefile.global
OBJS= localtime.o strftime.o pgtz.o
# files needed to build zic utility program
ZICOBJS= zic.o ialloc.o scheck.o localtime.o $(WIN32RES)
ZICOBJS= zic.o $(WIN32RES)
# timezone data files
TZDATA = africa antarctica asia australasia europe northamerica southamerica \

View File

@ -1,26 +1,24 @@
src/timezone/README
Timezone
========
This is a PostgreSQL adapted version of the IANA timezone library from
This is a PostgreSQL adapted version of the timezone library from
http://www.iana.org/time-zones
http://www.iana.org/time-zones
The source code can be found at:
ftp://ftp.iana.org/tz/releases/tzcode*.tar.gz
The code is currently synced with release 2010c. There are many cosmetic
(and not so cosmetic) differences from the original tzcode library, but
diffs in the upstream version should usually be propagated to our version.
The data files under data/ are an exact copy of the latest data set from:
ftp://ftp.iana.org/tz/releases/tzdata*.tar.gz
The latest versions of both the tzdata and tzcode tarballs are normally
available right from that page. Historical versions can be found
elsewhere on the site.
Since time zone rules change frequently in some parts of the world,
we should endeavor to update the data files before each PostgreSQL
release.
release. The code need not be updated as often, but we must track
changes that might affect interpretation of the data files.
Time Zone data
==============
The data files under data/ are an exact copy of the latest tzdata set,
except that we omit some files that are not of interest for our purposes.
While the files under data/ can just be duplicated when updating, manual
effort is needed to update the time zone abbreviation lists under tznames/.
@ -32,7 +30,9 @@ which will produce a file showing all abbreviations that are in current
use according to the data/ files. Compare this to known_abbrevs.txt,
which is the list that existed last time the tznames/ files were updated.
Update tznames/ as seems appropriate, then replace known_abbrevs.txt
in the same commit.
in the same commit. Usually, if a known abbreviation has changed meaning,
the appropriate fix is to make it refer to a long-form zone name instead
of a fixed GMT offset.
When there has been a new release of Windows (probably including Service
Packs), the list of matching timezones need to be updated. Run the
@ -40,3 +40,64 @@ script in src/tools/win32tzlist.pl on a Windows machine running this new
release and apply any new timezones that it detects. Never remove any
mappings in case they are removed in Windows, since we still need to
match properly on the old version.
Time Zone code
==============
The code in this directory is currently synced with tzcode release 2016c.
There are many cosmetic (and not so cosmetic) differences from the
original tzcode library, but diffs in the upstream version should usually
be propagated to our version. Here are some notes about that.
For the most part we want to use the upstream code as-is, but there are
several considerations preventing an exact match:
* For readability/maintainability we reformat the code to match our own
conventions; this includes pgindent'ing it and getting rid of upstream's
overuse of "register" declarations. (It used to include conversion of
old-style function declarations to C89 style, but thank goodness they
fixed that.)
* We need the code to follow Postgres' portability conventions; this
includes relying on configure's results rather than hand-hacked #defines,
and not relying on <stdint.h> features that may not exist on old systems.
(In particular this means using Postgres' definitions of the int32 and
int64 typedefs, not int_fast32_t/int_fast64_t.)
* Since Postgres is typically built on a system that has its own copy
of the <time.h> functions, we must avoid conflicting with those. This
mandates renaming typedef time_t to pg_time_t, and similarly for most
other exposed names.
* We have exposed the tzload() and tzparse() internal functions, and
slightly modified the API of the former, in part because it now relies
on our own pg_open_tzfile() rather than opening files for itself.
* There's a fair amount of code we don't need and have removed,
including all the nonstandard optional APIs. We have also added
a few functions of our own at the bottom of localtime.c.
* In zic.c, we have added support for a -P (print_abbrevs) switch, which
is used to create the "abbrevs.txt" summary of currently-in-use zone
abbreviations that was described above.
The most convenient way to compare a new tzcode release to our code is
to first run the tzcode source files through a sed filter like this:
sed -r \
-e 's/^([ \t]*)\*\*([ \t])/\1 *\2/' \
-e 's/^([ \t]*)\*\*$/\1 */' \
-e 's|^\*/| */|' \
-e 's/\bregister[ \t]//g' \
-e 's/int_fast32_t/int32/g' \
-e 's/int_fast64_t/int64/g' \
-e 's/struct[ \t]+tm\b/struct pg_tm/g' \
-e 's/\btime_t\b/pg_time_t/g' \
and then run them through pgindent. (The first three sed patterns deal
with conversion of their block comment style to something pgindent
won't make a hash of; the remainder address other points noted above.)
After that, the files can be diff'd directly against our corresponding
files.

View File

@ -1,76 +0,0 @@
/*
* This file is in the public domain, so clarified as of
* 2006-07-17 by Arthur David Olson.
*
* IDENTIFICATION
* src/timezone/ialloc.c
*/
#include "postgres_fe.h"
#include "private.h"
#define nonzero(n) (((n) == 0) ? 1 : (n))
char *
imalloc(int n)
{
return malloc((size_t) nonzero(n));
}
char *
icalloc(int nelem, int elsize)
{
if (nelem == 0 || elsize == 0)
nelem = elsize = 1;
return calloc((size_t) nelem, (size_t) elsize);
}
void *
irealloc(void *pointer, int size)
{
if (pointer == NULL)
return imalloc(size);
return realloc((void *) pointer, (size_t) nonzero(size));
}
char *
icatalloc(char *old, const char *new)
{
char *result;
int oldsize,
newsize;
newsize = (new == NULL) ? 0 : strlen(new);
if (old == NULL)
oldsize = 0;
else if (newsize == 0)
return old;
else
oldsize = strlen(old);
if ((result = irealloc(old, oldsize + newsize + 1)) != NULL)
if (new != NULL)
(void) strcpy(result + oldsize, new);
return result;
}
char *
icpyalloc(const char *string)
{
return icatalloc((char *) NULL, string);
}
void
ifree(char *p)
{
if (p != NULL)
(void) free(p);
}
void
icfree(char *p)
{
if (p != NULL)
(void) free(p);
}

File diff suppressed because it is too large Load Diff

View File

@ -256,7 +256,7 @@ pg_tzset(const char *name)
*/
if (strcmp(uppername, "GMT") == 0)
{
if (tzparse(uppername, &tzstate, TRUE) != 0)
if (!tzparse(uppername, &tzstate, true))
{
/* This really, really should not happen ... */
elog(ERROR, "could not initialize GMT time zone");
@ -264,9 +264,9 @@ pg_tzset(const char *name)
/* Use uppercase name as canonical */
strcpy(canonname, uppername);
}
else if (tzload(uppername, canonname, &tzstate, TRUE) != 0)
else if (tzload(uppername, canonname, &tzstate, true) != 0)
{
if (uppername[0] == ':' || tzparse(uppername, &tzstate, FALSE) != 0)
if (uppername[0] == ':' || !tzparse(uppername, &tzstate, false))
{
/* Unknown timezone. Fail our call instead of loading GMT! */
return NULL;
@ -460,7 +460,7 @@ pg_tzenumerate_next(pg_tzenum *dir)
* the cache
*/
if (tzload(fullname + dir->baselen, dir->tz.TZname, &dir->tz.state,
TRUE) != 0)
true) != 0)
{
/* Zone could not be loaded, ignore it */
continue;

View File

@ -16,25 +16,26 @@
#ifndef _PGTZ_H
#define _PGTZ_H
#include "tzfile.h"
#include "pgtime.h"
#include "tzfile.h"
#define SMALLEST(a, b) (((a) < (b)) ? (a) : (b))
#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
struct ttinfo
{ /* time type information */
long tt_gmtoff; /* UTC offset in seconds */
int tt_isdst; /* used to set tm_isdst */
int32 tt_gmtoff; /* UT offset in seconds */
bool 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 */
bool tt_ttisstd; /* transition is std time */
bool tt_ttisgmt; /* transition is UT */
};
struct lsinfo
{ /* leap second information */
pg_time_t ls_trans; /* transition time */
long ls_corr; /* correction to apply */
int64 ls_corr; /* correction to apply */
};
struct state
@ -43,14 +44,15 @@ struct state
int timecnt;
int typecnt;
int charcnt;
int goback;
int goahead;
bool goback;
bool goahead;
pg_time_t ats[TZ_MAX_TIMES];
unsigned char types[TZ_MAX_TIMES];
struct ttinfo ttis[TZ_MAX_TYPES];
char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, 3 /* sizeof gmt */ ),
(2 * (TZ_STRLEN_MAX + 1)))];
struct lsinfo lsis[TZ_MAX_LEAPS];
int defaulttype; /* for early times or if no transitions */
};
@ -67,7 +69,7 @@ extern int pg_open_tzfile(const char *name, char *canonname);
/* in localtime.c */
extern int tzload(const char *name, char *canonname, struct state * sp,
int doextend);
extern int tzparse(const char *name, struct state * sp, int lastditch);
bool doextend);
extern bool tzparse(const char *name, struct state * sp, bool lastditch);
#endif /* _PGTZ_H */

View File

@ -25,6 +25,18 @@
#define GRANDPARENTED "Local time zone must be set--see zic manual page"
/*
* IANA has a bunch of HAVE_FOO #defines here, but in PG we want pretty
* much all of that to be done by PG's configure script.
*/
#ifndef ENOTSUP
#define ENOTSUP EINVAL
#endif
#ifndef EOVERFLOW
#define EOVERFLOW EINVAL
#endif
#ifndef WIFEXITED
#define WIFEXITED(status) (((status) & 0xff) == 0)
#endif /* !defined WIFEXITED */
@ -35,6 +47,10 @@
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t) -1)
#endif
/*
* SunOS 4.1.1 libraries lack remove.
*/
@ -45,31 +61,11 @@ extern int unlink(const char *filename);
#define remove unlink
#endif /* !defined remove */
/*
* Private function declarations.
*/
extern char *icalloc(int nelem, int elsize);
extern char *icatalloc(char *old, const char *new);
extern char *icpyalloc(const char *string);
extern char *imalloc(int n);
extern void *irealloc(void *pointer, int size);
extern void icfree(char *pointer);
extern void ifree(char *pointer);
extern const char *scheck(const char *string, const char *format);
/*
* Finally, some convenience items.
*/
#ifndef TRUE
#define TRUE 1
#endif /* !defined TRUE */
#ifndef FALSE
#define FALSE 0
#endif /* !defined FALSE */
#ifndef TYPE_BIT
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
#endif /* !defined TYPE_BIT */
@ -78,14 +74,18 @@ extern 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.
*/
#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
#ifndef TYPE_INTEGRAL
#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
#endif /* !defined TYPE_INTEGRAL */
/*
* Max and min values of the integer type T, of which only the bottom
* B bits are used, and where the highest-order used bit is considered
* to be a sign bit if T is signed.
*/
#define MAXVAL(t, b) \
((t) (((t) 1 << ((b) - 1 - TYPE_SIGNED(t))) \
- 1 + ((t) 1 << ((b) - 1 - TYPE_SIGNED(t)))))
#define MINVAL(t, b) \
((t) (TYPE_SIGNED(t) ? - TWOS_COMPLEMENT(t) - MAXVAL(t, b) : 0))
#ifndef INT_STRLEN_MAXIMUM
/*
@ -95,34 +95,36 @@ extern const char *scheck(const char *string, const char *format);
* add one more for a minus sign if the type is signed.
*/
#define INT_STRLEN_MAXIMUM(type) \
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
1 + TYPE_SIGNED(type))
#endif /* !defined INT_STRLEN_MAXIMUM */
/*
* INITIALIZE(x)
*/
#define INITIALIZE(x) ((x) = 0)
#undef _
#define _(msgid) (msgid)
#ifndef YEARSPERREPEAT
#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
#endif /* !defined YEARSPERREPEAT */
/*
** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
*/
* The Gregorian year averages 365.2425 days, which is 31556952 seconds.
*/
#ifndef AVGSECSPERYEAR
#define AVGSECSPERYEAR 31556952L
#define AVGSECSPERYEAR 31556952L
#endif /* !defined AVGSECSPERYEAR */
#ifndef SECSPERREPEAT
#define SECSPERREPEAT ((int64) YEARSPERREPEAT * (int64) AVGSECSPERYEAR)
#define SECSPERREPEAT ((int64) YEARSPERREPEAT * (int64) AVGSECSPERYEAR)
#endif /* !defined SECSPERREPEAT */
#ifndef SECSPERREPEAT_BITS
#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
#endif /* !defined SECSPERREPEAT_BITS */
/*
* UNIX was a registered trademark of The Open Group in 2003.
*/
#endif /* !defined PRIVATE_H */

View File

@ -1,62 +0,0 @@
/*
* This file is in the public domain, so clarified as of
* 2006-07-17 by Arthur David Olson.
*
* IDENTIFICATION
* src/timezone/scheck.c
*/
#include "postgres_fe.h"
#include "private.h"
const char *
scheck(const char *string, const char *format)
{
char *fbuf;
const char *fp;
char *tp;
int c;
const char *result;
char dummy;
result = "";
if (string == NULL || format == NULL)
return result;
fbuf = imalloc((int) (2 * strlen(format) + 4));
if (fbuf == NULL)
return result;
fp = format;
tp = fbuf;
while ((*tp++ = c = *fp++) != '\0')
{
if (c != '%')
continue;
if (*fp == '%')
{
*tp++ = *fp++;
continue;
}
*tp++ = '*';
if (*fp == '*')
++fp;
while (is_digit(*fp))
*tp++ = *fp++;
if (*fp == 'l' || *fp == 'h')
*tp++ = *fp++;
else if (*fp == '[')
do
*tp++ = *fp++;
while (*fp != '\0' && *fp != ']');
if ((*tp++ = *fp++) == '\0')
break;
}
*(tp - 1) = '%';
*tp++ = 'c';
*tp = '\0';
if (sscanf(string, fbuf, &dummy) != 1)
result = (char *) format;
ifree(fbuf);
return result;
}

View File

@ -1,18 +1,38 @@
/* Convert a broken-down time stamp to a string. */
/*
* Copyright (c) 1989 The Regents of the University of California.
* Copyright 1989 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 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.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Based on the UCB version with the copyright notice appearing above.
*
* This is ANSIish only when "multibyte character == plain character".
*
* IDENTIFICATION
* src/timezone/strftime.c
@ -92,8 +112,7 @@ static char *_add(const char *, char *, const char *);
static char *_conv(int, const char *, char *, const char *);
static char *_fmt(const char *, const struct pg_tm *, char *,
const char *, int *);
static char *_yconv(const int, const int, const int, const int,
char *, const char *const);
static char *_yconv(int, int, bool, bool, char *, const char *);
#define IN_NONE 0
#define IN_SOME 1
@ -162,8 +181,8 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim,
* ...whereas now POSIX 1003.2 calls for something
* completely different. (ado, 1993-05-24)
*/
pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
pt, ptlim);
pt = _yconv(t->tm_year, TM_YEAR_BASE,
true, false, pt, ptlim);
continue;
case 'c':
{
@ -224,7 +243,7 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim,
case 'K':
/*
* * After all this time, still unclaimed!
* After all this time, still unclaimed!
*/
pt = _add("kitchen sink", pt, ptlim);
continue;
@ -296,7 +315,7 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim,
* (01-53)."
* (ado, 1993-05-24)
*
* From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
* From <http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html> by Markus Kuhn:
* "Week 01 of a year is per definition the first week which has the
* Thursday in this year, which is equivalent to the week which contains
* the fourth day of January. In other words, the first week of a new year
@ -367,11 +386,13 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim,
else if (*format == 'g')
{
*warnp = IN_ALL;
pt = _yconv(year, base, 0, 1,
pt = _yconv(year, base,
false, true,
pt, ptlim);
}
else
pt = _yconv(year, base, 1, 1,
pt = _yconv(year, base,
true, true,
pt, ptlim);
}
continue;
@ -409,11 +430,13 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim,
continue;
case 'y':
*warnp = IN_ALL;
pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
pt = _yconv(t->tm_year, TM_YEAR_BASE,
false, true,
pt, ptlim);
continue;
case 'Y':
pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
pt = _yconv(t->tm_year, TM_YEAR_BASE,
true, true,
pt, ptlim);
continue;
case 'Z':
@ -427,7 +450,7 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim,
continue;
case 'z':
{
int diff;
long diff;
char const *sign;
if (t->tm_isdst < 0)
@ -441,9 +464,10 @@ _fmt(const char *format, const struct pg_tm * t, char *pt, const char *ptlim,
else
sign = "+";
pt = _add(sign, pt, ptlim);
diff /= 60;
pt = _conv((diff / 60) * 100 + diff % 60,
"%04d", pt, ptlim);
diff /= SECSPERMIN;
diff = (diff / MINSPERHOUR) * 100 +
(diff % MINSPERHOUR);
pt = _conv(diff, "%04d", pt, ptlim);
}
continue;
case '+':
@ -473,7 +497,7 @@ _conv(int n, const char *format, char *pt, const char *ptlim)
{
char buf[INT_STRLEN_MAXIMUM(int) +1];
(void) sprintf(buf, format, n);
sprintf(buf, format, n);
return _add(buf, pt, ptlim);
}
@ -493,13 +517,13 @@ _add(const char *str, char *pt, const char *ptlim)
* with more only if necessary.
*/
static char *
_yconv(const int a, const int b, const int convert_top,
const int convert_yy, char *pt, const char *const ptlim)
_yconv(int a, int b, bool convert_top, bool convert_yy,
char *pt, const char *ptlim)
{
int lead;
int trail;
#define DIVISOR 100
#define DIVISOR 100
trail = a % DIVISOR + b % DIVISOR;
lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
trail %= DIVISOR;

View File

@ -33,8 +33,8 @@
struct tzhead
{
char tzh_magic[4]; /* TZ_MAGIC */
char tzh_version[1]; /* '\0' or '2' as of 2005 */
char tzh_reserved[15]; /* reserved--must be zero */
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 */
char tzh_leapcnt[4]; /* coded number of leap seconds */
@ -43,30 +43,29 @@ struct tzhead
char tzh_charcnt[4]; /* coded number of abbr. chars */
};
/*----------
/*
* . . .followed by. . .
*
* 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
* tzh_leapcnt repetitions of
* one (char [4]) coded leap second transition times
* one (char [4]) total correction after above
* tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
* time is standard time, if FALSE,
* tzh_ttisstdcnt (char)s indexed by type; if 1, transition
* time is standard time, if 0,
* transition time is wall clock time
* 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,
* tzh_ttisgmtcnt (char)s indexed by type; if 1, transition
* time is UT, if 0,
* transition time is local time
* if absent, transition times are
* assumed to be local time
*----------
*/
/*
@ -77,6 +76,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.
*/
/*
@ -84,8 +90,9 @@ struct tzhead
* exceed any of the limits below.
*/
#define TZ_MAX_TIMES 1200
#define TZ_MAX_TIMES 2000
/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
@ -100,7 +107,7 @@ struct tzhead
#define DAYSPERNYEAR 365
#define DAYSPERLYEAR 366
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
#define SECSPERDAY ((int32) SECSPERHOUR * HOURSPERDAY)
#define MONSPERYEAR 12
#define TM_SUNDAY 0
@ -143,6 +150,6 @@ struct tzhead
* We use this to avoid addition overflow problems.
*/
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
#endif /* !defined TZFILE_H */

File diff suppressed because it is too large Load Diff