Import tzcode 2026d

This commit is contained in:
Dag-Erling Smørgrav committed 2026-09-13 15:18:34 +02:00
1 parent 2479b6921a
commit 4d4fdb78db
17 files changed
+531 -428

No files matched your search

+1 -1
View File
@@ -22,7 +22,7 @@ To email small changes, please run a POSIX shell command like
For more-elaborate or possibly controversial changes,
such as renaming, adding or removing zones, please read
“Theory and pragmatics of the tz code and data”
<https://www.iana.org/time-zones/repository/theory.html>.
<https://data.iana.org/time-zones/theory.html>
It is also good to browse the mailing list archives
<https://lists.iana.org/hyperkitty/list/[email protected]/>
for examples of patches that tend to work well.
+12 -7
View File
@@ -172,9 +172,9 @@ EXPIRES_LINE= 0
TZDATA_TEXT= leapseconds tzdata.zi
# For backward-compatibility links for old zone names, use
# For backward-compatibility links and zones for old names, use
# BACKWARD= backward
# To omit these links, use
# To omit these links and zones, use
# BACKWARD=
BACKWARD= backward
@@ -574,7 +574,7 @@ SAFE_CHAR= '[]'$(SAFE_CHARSET)'-]'
# These non-alphabetic, non-ASCII printable characters are
# used in commentary or in generated *.txt files
# and are not likely to cause confusion.
UNUSUAL_OK_CHARSET= §«°±»½¾×–‘’“”•→−≤★⟨⟩⯪
UNUSUAL_OK_CHARSET= §«°±»½¾¿×–‘’“”•→−≤★⟨⟩⯪
# Put this in a bracket expression to match spaces.
s = [:space:]
@@ -922,7 +922,7 @@ check_mild: check_web check_zishrink \
UTF8_LOCALE_MISSING = \
{ test ! '$(UTF8_LOCALE)' \
|| ! printf 'A\304\200B\n' \
| LC_ALL='$(UTF8_LOCALE)' grep -q '^A.B$$' >/dev/null 2>&1 \
| LC_ALL='$(UTF8_LOCALE)' grep -q '^A[[:alpha:]]B$$' >/dev/null 2>&1 \
|| { export LC_ALL='$(UTF8_LOCALE)'; false; }; }
character-set.ck: $(ENCHILADA)
@@ -1006,11 +1006,11 @@ now.ck: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab
now=$(CHECK_NOW_TIMESTAMP) && \
future=$$(($(CHECK_NOW_FUTURE_SECS) + $$now)) && \
./zdump -i -t $$now,$$future \
$$(find "$$PWD/$@d"/????*/ -type f) \
$$(find "$$PWD/$@d"/????*/ -type f -o -type l) \
>$@d/zdump-now.tab && \
./zdump -i -t 0,$$future \
$$(find "$$PWD/$@d" -name Etc -prune \
-o -type f ! -name '*.tab' -print) \
-o \( -type f -o -type l \) ! -name '*.tab' -print) \
>$@d/zdump-1970.tab && \
$(AWK) \
-v now=$$now \
@@ -1018,7 +1018,12 @@ now.ck: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab
-v zdump_table=$@d/zdump-now.tab \
-f checknow.awk zonenow.tab
$(AWK) \
'BEGIN {print "-\t-\tUTC"} /^Zone/ {print "-\t-\t" $$2}' \
'BEGIN { \
SysVzone["EST5EDT"] = 1; SysVzone["CST6CDT"] = 1; \
SysVzone["MST7MDT"] = 1; SysVzone["PST8PDT"] = 1; \
print "-\t-\tUTC" \
} \
$$1 == "Zone" && !SysVzone[$$2] {print "-\t-\t" $$2}' \
$(PRIMARY_YDATA) backward factory | \
$(AWK) \
-v zdump_table=$@d/zdump-1970.tab \
+114 -1
View File
@@ -1,5 +1,87 @@
News for the tz database
Release 2026d - 2026-09-11 15:21:07 -0700
Briefly:
Canada’s Northwest Territories moved to permanent -06 on 2026-08-21.
Obsolescent settings like TZ="EST5EDT" now conform better to POSIX.
Fix security, performance and porting bugs in zic and localtime.
Changes to future timestamps
Canada’s Northwest Territories will not fall back on 2026-11-01
and will stay on -06 year-round, matching Alberta’s recent change.
Model this with its traditional abbreviation CST. Although the
change to permanent -06 legally took place on 2026-08-21,
temporarily model the change to occur on 2026-11-01 at 02:00
for the same reason as other recent temporary hacks. (Caution:
see “NOTE FOR 2026b TEMPORARY HACK FOR CLDR AND CANADA” below.)
This affects only America/Inuvik as the rest of the territory is
covered by America/Edmonton, for which the equivalent change was
released in 2026c.
Changes to past timestamps
Colombia’s 1992-05-02 spring forward was at 00:00, not 24:00.
Iran’s 1979-05-26 spring forward was at 00:00, not 24:00.
(Thanks to N.F. Hase.)
The backward-compatibility names EST5EDT, CST6CDT, MST7MDT, and
PST8PDT now conform better to POSIX. For example, EST5EDT now
always uses the abbreviation "EST" for standard time (now always 5
hours behind UT) and "EDT" for daylight saving time, whereas it
formerly had different UT offsets before standard time was
introduced and sometimes used abbreviations like "LMT", "EWT" and
"EPT", all contrary to POSIX. Also, though not required by POSIX
these names now use US federal rules rather than rules of places
like New York, reverting to 2024a behavior. This change affects
only timestamps before 1966-10-30 at 01:00 standard time.
Other data changes
The temporary hacks used for North American timekeeping changes
now work around a libstdc++ std::chrono bug in GCC 14.1-14.4,
15.1-15.2, and 16.1; see GCC bug 124851. This data change does
not affect TZif files or timestamps. The change does not work
around the related but less serious GCC bugs 116110 and 124513.
These GCC bugs are all fixed in GCC 16.2.
Changes to code
zic now rejects Link targets that would have invalid names, and
more efficiently processes Expires, Leap and Rule lines with years
far in the past or future. (Thanks to Darren Carreras.)
zic now ports to systems that report lack of link support via
EINVAL, ENOSYS or EPERM errno values. (Thanks to Tom Lane.)
When tzset and related functions encounter a TZif file that is too
large for them, they now consistently fail instead of sometimes
silently ignoring excess parts of the file.
localtime-related functions no longer mishandle extreme timestamps
when given TZif files holding some unlikely timezone histories.
(Problem reported by David Sarkisyan.)
localtime-related functions no longer check the values of TZif
files’ standard/wall and UT/local indicators, which these
functions have not used since 2026a’s removal of the old
posixrules feature.
tzcode has been ported to Haiku.
localtime.c now works again by default on AIX and DragonFly BSD.
zic now rejects ‘:’ and ‘\’ in Zone and Link names when running on
Microsoft Windows. (Problem reported by David Diaz.)
Changes to documentation
URLs for release tarballs in tz-link.html have been updated to
reflect their new canonical URLs on data.iana.org.
Release 2026c - 2026-07-08 10:23:58 -0700
Briefly:
@@ -15,7 +97,13 @@ Release 2026c - 2026-07-08 10:23:58 -0700
CST. Although the change to permanent -06 legally took place on
2026-06-18, temporarily model the change to occur on 2026-11-01 at
02:00 instead, for the same reason we introduced a similarly
temporary hack for British Columbia in 2026b.
temporary hack for British Columbia in 2026b. (Caution: see
“NOTE FOR 2026b TEMPORARY HACK FOR CLDR AND CANADA” below.)
As the change affects both America/Edmonton and its backward
compatibility link, the obsolescent setting TZ="Canada/Mountain"
will now use the abbreviation CST for affected timestamps,
akin to TZ="Canada/Pacific" behavior introduced in 2026b.
Although another TZDB release will likely be needed soon because
Northwest Territories will likely follow Alberta, the legal
@@ -67,6 +155,7 @@ Release 2026b - 2026-04-22 23:06:43 -0700
Briefly:
British Columbia moved to permanent -07 on 2026-03-09.
zic no longer mishandles a last transition to a new time type.
Some more overflow bugs have been fixed in zic.
Changes to future timestamps
@@ -79,9 +168,33 @@ Release 2026b - 2026-04-22 23:06:43 -0700
limitation in CLDR 48.1 (2026-01-08). This temporary hack is
planned to be removed after CLDR is fixed.
To match longstanding practice for -07 standard time in North
America, such as for America/Dawson, America/Dawson_Creek,
America/Fort_Nelson and America/Whitehorse, affected BC
timestamps use the abbreviation MST. As the change affects both
America/Vancouver and its backward compatibility link, the
obsolescent setting TZ="Canada/Pacific" will now use the
abbreviation MST. Future TZDB releases may change the
abbreviation if something else becomes popular across areas
observing -07, and may change it to "-07" if no alphabetic
consensus emerges.
Changes to code
zic no longer mishandles a last transition to a new time type.
NOTE FOR 2026b TEMPORARY HACK FOR CLDR AND CANADA:
This zic fix is needed for the temporary hack (mentioned above)
that works around the Canadian timekeeping bug in Unicode CLDR.
Without the fix, the temporary hack causes zic versions 2023d
through 2026a, in their default mode that generates slim output,
to generate a TZif file that violates Internet RFC 9636 §3.3.
The buggy file in turn causes some TZif readers, including tzcode
itself, to ignore America/Vancouver’s 2026-11-01 02:00 transition
from PDT (tm_isdst=1) to MST (tm_isdst=0). Although the buggy
file does not cause any known TZif reader to mishandle UT offsets,
caution is advised when using zic 2023d through 2026a to compile
data from more-recent tz releases. To work around this problem
when using these older zic versions, use ‘zic -b fat’.
zic no longer overflows a buffer when generating a TZ string like
"PST-167:59:58PDT-167:59:59,M11.5.6/-167:59:59,M12.5.6/-167:59:59",
+1 -1
View File
@@ -10,7 +10,7 @@ locations around the globe. It is updated periodically to reflect
changes made by political bodies to time zone boundaries, UTC offsets,
and daylight-saving rules.
See <https://www.iana.org/time-zones/repository/tz-link.html> or the
See <https://data.iana.org/time-zones/tz-link.html> or the
file tz-link.html for how to acquire the code and data.
Once acquired, read the leading comments in the file ‘Makefile’
+167 -232
View File
@@ -64,7 +64,7 @@ struct stat { char st_ctime, st_dev, st_ino; };
# endif
# if THREAD_PREFER_SINGLE
# ifndef HAVE___ISTHREADED
# if defined __FreeBSD__ || defined __OpenBSD__
# if defined __FreeBSD__ || defined __OpenBSD__ || defined __DragonFly__
# define HAVE___ISTHREADED 1
# else
# define HAVE___ISTHREADED 0
@@ -348,6 +348,10 @@ static int fstatat(int dd, char const *path, struct stat *st, int flags)
# include <sys/auxv.h>
# endif
/* Avoid clash if headers declare but libraries do not define issetugid. */
# undef issetugid
# define issetugid localtime_issetugid
/* Return 1 if the process is privileged, 0 otherwise. */
static int
issetugid(void)
@@ -475,8 +479,6 @@ struct ttinfo { /* time type information */
-2**31 + 1 .. 2**31 - 1 */
desigidx_type tt_desigidx; /* abbreviation list index */
bool tt_isdst; /* used to set tm_isdst */
bool tt_ttisstd; /* transition is std time */
bool tt_ttisut; /* transition is UT */
};
struct lsinfo { /* leap second information */
@@ -505,7 +507,6 @@ struct state {
int timecnt;
int typecnt;
int charcnt;
bool goback;
bool goahead;
time_t ats[TZ_MAX_TIMES];
unsigned char types[TZ_MAX_TIMES];
@@ -569,12 +570,11 @@ struct rule {
};
static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
struct tm *);
static bool increment_overflow(int *, int);
struct tm *, time_t *);
static bool increment_overflow_time(time_t *, int_fast32_2s);
static int_fast32_2s leapcorr(struct state const *, time_t);
static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
struct tm *);
struct tm *, time_t *);
static bool tzparse(char const *, struct state *, struct state const *);
#ifndef ALL_STATE
@@ -641,8 +641,6 @@ init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst,
s->tt_utoff = utoff;
s->tt_isdst = isdst;
s->tt_desigidx = desigidx;
s->tt_ttisstd = false;
s->tt_ttisut = false;
}
/* Return true if SP's time type I does not specify local time. */
@@ -838,10 +836,11 @@ tzfile_changed(int fd, struct stat *st)
resolution if available, as this can help distinguish files on
non-POSIX platforms where st_dev and st_ino are unreliable. */
struct timespec ctim;
#if HAVE_STRUCT_STAT_ST_CTIM
ctim = st->st_ctim;
#else
/* Copy via members, as AIX 7.3 defaults to an incompatible st_ctim. */
ctim.tv_sec = st->st_ctime;
#if HAVE_STRUCT_STAT_ST_CTIM
ctim.tv_nsec = st->st_ctim.tv_nsec;
#else
ctim.tv_nsec = 0;
#endif
@@ -896,9 +895,19 @@ union local_storage {
};
/* These tzload flags can be ORed together, and fit into 'char'. */
enum { TZLOAD_FROMENV = 1 }; /* The TZ string came from the environment. */
enum { TZLOAD_TZSTRING = 2 }; /* Read any newline-surrounded TZ string. */
enum { TZLOAD_TZDIR_SUB = 4 }; /* TZ should be a file under TZDIR. */
/* TZLOAD_FROMENV means the TZ string is a process-wide setting either
taken from the TZ environment variable or inferred from TZ being unset.
When 0 <= tz_change_interval, TZLOAD_FROMENV lets us skip reanalysis
of a TZif file that did not change during the interval. */
enum { TZLOAD_FROMENV = 1 };
/* Read any newline-surrounded TZ string. */
enum { TZLOAD_TZSTRING = 2 };
/* TZ should be a file under TZDIR. */
enum { TZLOAD_TZDIR_SUB = 4 };
/* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS.
Use **LSPP for temporary storage. Return 0 on
@@ -923,7 +932,7 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
struct stat st;
st.st_ctime = 0;
sp->goback = sp->goahead = false;
sp->goahead = false;
if (! name) {
name = TZDEFAULT;
@@ -1198,30 +1207,9 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
}
set_leapcount(sp, leapcnt);
for (i = 0; i < sp->typecnt; ++i) {
register struct ttinfo * ttisp;
ttisp = &sp->ttis[i];
if (ttisstdcnt == 0)
ttisp->tt_ttisstd = false;
else {
if (*p != true && *p != false)
return EFTYPE;
ttisp->tt_ttisstd = *p++;
}
}
for (i = 0; i < sp->typecnt; ++i) {
register struct ttinfo * ttisp;
ttisp = &sp->ttis[i];
if (ttisutcnt == 0)
ttisp->tt_ttisut = false;
else {
if (*p != true && *p != false)
return EFTYPE;
ttisp->tt_ttisut = *p++;
}
}
/* Do not bother to validate standard/wall and UT/local
indicators, as they are no longer used here. */
p += ttisstdcnt + ttisutcnt;
}
nread -= p - up->buf;
@@ -1232,13 +1220,13 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
break;
}
if ((tzloadflags & TZLOAD_TZSTRING) && nread > 2 &&
up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
sp->typecnt + 2 <= TZ_MAX_TYPES) {
up->buf[0] == '\n' && up->buf[nread - 1] == '\n') {
struct state *ts = &lsp->u.st;
up->buf[nread - 1] = '\0';
if (tzparse(&up->buf[1], ts, sp)) {
if (!tzparse(&up->buf[1], ts, sp))
return EFTYPE;
else {
/* Attempt to reuse existing abbreviations.
Without this, America/Anchorage would
consume 50 bytes for abbreviations, as
@@ -1246,7 +1234,6 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
AHDT YST AKDT AKST) and ts->charcnt equals 10
(for AKST AKDT). Reusing means sp->charcnt can
stay 40 in this example. */
int gotabbr = 0;
int charcnt = sp->charcnt;
for (i = 0; i < ts->typecnt; i++) {
char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx;
@@ -1254,22 +1241,25 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
for (j = 0; j < charcnt; j++)
if (strcmp(sp->chars + j, tsabbr) == 0) {
ts->ttis[i].tt_desigidx = j;
gotabbr++;
break;
}
if (! (j < charcnt)) {
int tsabbrlen = strnlen(tsabbr, TZ_MAX_CHARS - j);
if (j + tsabbrlen < TZ_MAX_CHARS) {
if (TZ_MAX_CHARS <= j + tsabbrlen)
return EOVERFLOW;
else {
char *cp = sp->chars + j;
cp = mempcpy(cp, tsabbr, tsabbrlen);
*cp = '\0';
charcnt = j + tsabbrlen + 1;
ts->ttis[i].tt_desigidx = j;
gotabbr++;
}
}
}
if (gotabbr == ts->typecnt) {
if (TZ_MAX_TYPES - sp->typecnt < ts->typecnt)
return EOVERFLOW;
else {
sp->charcnt = charcnt;
/* Ignore any trailing, no-op transitions generated
@@ -1288,10 +1278,8 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
|| (0 < sp->timecnt
&& t <= sp->ats[sp->timecnt - 1]))
continue;
if (TZ_MAX_TIMES <= sp->timecnt) {
sp->goahead = false;
break;
}
if (TZ_MAX_TIMES <= sp->timecnt)
return EOVERFLOW;
sp->ats[sp->timecnt] = t;
sp->types[sp->timecnt] = (sp->typecnt
+ ts->types[i]);
@@ -1334,10 +1322,6 @@ static const int mon_lengths[2][MONSPERYEAR] = {
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
static const int year_lengths[2] = {
DAYSPERNYEAR, DAYSPERLYEAR
};
/* Is C an ASCII digit? */
static bool
is_digit(char c)
@@ -1537,40 +1521,26 @@ getrule(const char *strp, register struct rule *const rulep)
*/
static int_fast32_t
transtime(const int year, register const struct rule *const rulep,
transtime(time_t year, register const struct rule *const rulep,
const int_fast32_t offset)
{
int d; /* Day of year (zero-origin). */
register bool leapyear;
register int_fast32_t value;
register int i;
int d, m1, yy0, yy1, yy2, dow;
leapyear = isleap(year);
switch (rulep->r_type) {
case JULIAN_DAY:
if (rulep->r_type <= DAY_OF_YEAR) {
/*
** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
** years.
** In non-leap years, or if the day number is 59 or less, just
** add SECSPERDAY times the day number-1 to the time of
** January 1, midnight, to get the day.
*/
value = (rulep->r_day - 1) * SECSPERDAY;
if (leapyear && rulep->r_day >= 60)
value += SECSPERDAY;
break;
case DAY_OF_YEAR:
/*
** use the day number - 1.
**
** n - day of year.
** Just add SECSPERDAY times the day number to the time of
** January 1, midnight, to get the day.
*/
value = rulep->r_day * SECSPERDAY;
break;
case MONTH_NTH_DAY_OF_WEEK:
d = rulep->r_day - ((rulep->r_type < DAY_OF_YEAR)
& (!leapyear | (rulep->r_day <= 59)));
} else {
/*
** Mm.n.d - nth "dth day" of month m.
*/
@@ -1579,14 +1549,16 @@ transtime(const int year, register const struct rule *const rulep,
** Use Zeller's Congruence to get day-of-week of first day of
** month.
*/
m1 = (rulep->r_mon + 9) % 12 + 1;
yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
yy1 = yy0 / 100;
yy2 = yy0 % 100;
dow = ((26 * m1 - 2) / 10 +
1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
if (dow < 0)
dow += DAYSPERWEEK;
int i;
bool janfeb = rulep->r_mon <= 2;
int month = (rulep->r_mon
+ (janfeb ? MONSPERYEAR : 0)); /* 3..14 */
int adjustment = (TYPE_SIGNED(time_t) ? 0 : 400) - janfeb;
int ay_rem = (year + adjustment) % YEARSPERREPEAT;
int y = ay_rem + (ay_rem < 0 ? YEARSPERREPEAT : 0);
int dow = (((13 * (month + 1)) / 5
+ y + y / 4 - y / 100 + y / 400)
% DAYSPERWEEK);
/*
** "dow" is the day-of-week of the first day of the month. Get
@@ -1594,33 +1566,24 @@ transtime(const int year, register const struct rule *const rulep,
** month.
*/
d = rulep->r_day - dow;
if (d < 0)
d += DAYSPERWEEK;
for (i = 1; i < rulep->r_week; ++i) {
if (d + DAYSPERWEEK >=
mon_lengths[leapyear][rulep->r_mon - 1])
break;
d += DAYSPERWEEK;
}
d += (rulep->r_week - (0 <= d)) * DAYSPERWEEK;
if (mon_lengths[leapyear][rulep->r_mon - 1] <= d)
d -= DAYSPERWEEK;
/*
** "d" is the day-of-month (zero-origin) of the day we want.
*/
value = d * SECSPERDAY;
for (i = 0; i < rulep->r_mon - 1; ++i)
value += mon_lengths[leapyear][i] * SECSPERDAY;
break;
default: unreachable();
d += mon_lengths[leapyear][i];
}
/*
** "value" is the year-relative time of 00:00:00 UT on the day in
** d is the origin-0 year-relative 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 UT.
** from UT to d * SECSPERDAY.
*/
return value + rulep->r_time + offset;
return d * SECSPERDAY + rulep->r_time + offset;
}
/*
@@ -1670,11 +1633,11 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
}
} else
set_leapcount(sp, 0); /* So, we're off a little. */
sp->goback = sp->goahead = false;
sp->goahead = false;
if (*name != '\0') {
struct rule start, end;
int year, yearbeg, yearlim, timecnt;
time_t janfirst;
int timecnt;
time_t janfirst, repeatbeg, year, yearbeg, yearlim;
int_fast32_t janoffset = 0;
if (*name == '<') {
@@ -1712,18 +1675,20 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
if (!name || *name)
return false;
sp->typecnt = 2; /* standard time and DST */
/*
** Two transitions per year, from EPOCH_YEAR forward.
*/
/* Two transitions per year, from atlo forward, and going on
for years_of_observations past max(atlo, leaplo). */
init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
timecnt = 0;
janfirst = 0;
yearbeg = EPOCH_YEAR;
repeatbeg = (atlo / SECSPERREPEAT
+ (atlo < 0 && 0 < atlo % SECSPERREPEAT));
yearbeg = repeatbeg * YEARSPERREPEAT + EPOCH_YEAR;
janfirst = repeatbeg * SECSPERREPEAT;
do {
int_fast32_t yearsecs
= year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
= year_days(yearbeg - 1) * SECSPERDAY;
time_t janfirst1 = janfirst;
yearbeg--;
if (increment_overflow_time(&janfirst1, -yearsecs)) {
@@ -1731,30 +1696,25 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
break;
}
janfirst = janfirst1;
} while (atlo < janfirst
&& EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
} while (atlo < janfirst);
while (true) {
int_fast32_t yearsecs
= year_lengths[isleap(yearbeg)] * SECSPERDAY;
int yearbeg1 = yearbeg;
= year_days(yearbeg) * SECSPERDAY;
time_t janfirst1 = janfirst;
if (increment_overflow_time(&janfirst1, yearsecs)
|| increment_overflow(&yearbeg1, 1)
|| atlo <= janfirst1)
break;
yearbeg = yearbeg1;
yearbeg++;
janfirst = janfirst1;
}
yearlim = yearbeg;
if (increment_overflow(&yearlim, years_of_observations))
yearlim = INT_MAX;
yearlim = yearbeg + years_of_observations;
for (year = yearbeg; year < yearlim; year++) {
int_fast32_t
starttime = transtime(year, &start, stdoffset),
endtime = transtime(year, &end, dstoffset),
yearsecs = year_lengths[isleap(year)] * SECSPERDAY;
yearsecs = year_days(year) * SECSPERDAY;
bool reversed = endtime < starttime;
if (reversed) {
int_fast32_t swap = starttime;
@@ -1764,24 +1724,25 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
if (reversed
|| (starttime < endtime
&& endtime - starttime < yearsecs)) {
if (TZ_MAX_TIMES - 2 < timecnt)
break;
sp->ats[timecnt] = janfirst;
if (! increment_overflow_time(&sp->ats[timecnt],
janoffset + starttime)
&& atlo <= sp->ats[timecnt])
time_t at_added = TIME_T_MAX;
time_t at = janfirst;
if (! increment_overflow_time(&at, janoffset + starttime)
&& atlo <= at) {
if (TZ_MAX_TIMES <= timecnt)
return false;
sp->ats[timecnt] = at_added = at;
sp->types[timecnt++] = !reversed;
sp->ats[timecnt] = janfirst;
if (! increment_overflow_time(&sp->ats[timecnt],
janoffset + endtime)
&& atlo <= sp->ats[timecnt]) {
}
at = janfirst;
if (! increment_overflow_time(&at, janoffset + endtime)
&& atlo <= at) {
if (TZ_MAX_TIMES <= timecnt)
return false;
sp->ats[timecnt] = at_added = at;
sp->types[timecnt++] = reversed;
}
}
if (endtime < leaplo) {
yearlim = year;
if (increment_overflow(&yearlim, years_of_observations))
yearlim = INT_MAX;
if (at_added < leaplo)
yearlim = year + years_of_observations;
}
if (increment_overflow_time(&janfirst, janoffset + yearsecs))
break;
@@ -1792,7 +1753,7 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
sp->ttis[0] = sp->ttis[1];
sp->typecnt = 1; /* Perpetual DST. */
} else if (years_of_observations <= year - yearbeg)
sp->goback = sp->goahead = true;
sp->goahead = true;
} else {
dstlen = 0;
sp->typecnt = 1; /* only standard time */
@@ -1849,7 +1810,7 @@ zoneinit(struct state *sp, char const *name, char tzloadflags)
sp->timecnt = 0;
sp->typecnt = 0;
sp->charcnt = 0;
sp->goback = sp->goahead = false;
sp->goahead = false;
init_ttinfo(&sp->ttis[0], 0, false, 0);
strcpy(sp->chars, utc);
return 0;
@@ -2069,12 +2030,15 @@ tzfree(timezone_t sp)
** since in that case tzset should have already done this step correctly.
** SETNAME's type is int_fast32_t for compatibility with gmtsub,
** but it is actually a boolean and its value should be 0 or 1.
**
** If LTM_YEAR, store the resulting year-1900 into *LTM_YEAR rather
** than into the default TMP->tm_year; this prevents year overflow.
*/
/*ARGSUSED*/
static struct tm *
localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
struct tm *const tmp)
struct tm *tmp, time_t *ltm_year)
{
register const struct ttinfo * ttisp;
register int i;
@@ -2083,52 +2047,39 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
if (sp == NULL) {
/* Don't bother to set tzname etc.; tzset has already done it. */
return gmtsub(gmtptr, timep, 0, tmp);
return gmtsub(gmtptr, timep, 0, tmp, ltm_year);
}
if ((sp->goback && t < sp->ats[0]) ||
(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
time_t newt;
register time_t seconds;
register time_t years;
if (sp->goahead && sp->ats[sp->timecnt - 1] < t) {
/* Avoid integer overflow when time_t is signed, by
using secs_div_2 twice; the full value would
always be even, so halving does not round. */
time_t
tlo = sp->ats[sp->timecnt - 1],
diffyears = ((t / 2 - tlo / 2
+ ((t % 2 - tlo % 2 + 2) / 2 - 1))
/ (SECSPERREPEAT / 2)
* YEARSPERREPEAT),
years = diffyears + YEARSPERREPEAT,
secs_div_2 = (diffyears * (AVGSECSPERYEAR / 2)
+ SECSPERREPEAT / 2),
newt = t - secs_div_2 - secs_div_2,
ryear;
if (t < sp->ats[0])
seconds = sp->ats[0] - t;
else seconds = t - sp->ats[sp->timecnt - 1];
--seconds;
/* Beware integer overflow, as SECONDS might
be close to the maximum time_t. */
years = seconds / SECSPERREPEAT * YEARSPERREPEAT;
seconds = years * AVGSECSPERYEAR;
years += YEARSPERREPEAT;
if (t < sp->ats[0])
newt = t + seconds + SECSPERREPEAT;
else
newt = t - seconds - SECSPERREPEAT;
if (newt < sp->ats[0] ||
newt > sp->ats[sp->timecnt - 1])
return NULL; /* "cannot happen" */
result = localsub(sp, &newt, setname, tmp);
result = localsub(sp, &newt, setname, tmp, &ryear);
if (result) {
# if defined ckd_add && defined ckd_sub
if (t < sp->ats[0]
? ckd_sub(&result->tm_year,
result->tm_year, years)
: ckd_add(&result->tm_year,
result->tm_year, years))
if (ltm_year)
*ltm_year = ryear + years;
else {
# ifdef ckd_add
if (ckd_add(&result->tm_year, ryear, years))
return NULL;
# else
register int_fast64_t newy;
newy = result->tm_year;
if (t < sp->ats[0])
newy -= years;
else newy += years;
time_t newy = ryear + years;
if (! (INT_MIN <= newy && newy <= INT_MAX))
return NULL;
result->tm_year = newy;
# endif
}
}
return result;
}
@@ -2152,9 +2103,9 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
** To get (wrong) behavior that's compatible with System V Release 2.0
** you'd replace the statement below with
** t += ttisp->tt_utoff;
** timesub(&t, 0, sp, tmp);
** timesub(&t, 0, sp, tmp, ltm_year);
*/
result = timesub(&t, ttisp->tt_utoff, sp, tmp);
result = timesub(&t, ttisp->tt_utoff, sp, tmp, ltm_year);
if (result) {
result->tm_isdst = ttisp->tt_isdst;
# ifdef TM_ZONE
@@ -2204,7 +2155,7 @@ struct tm *
localtime_rz(struct state *restrict sp, time_t const *restrict timep,
struct tm *restrict tmp)
{
return localsub(sp, timep, 0, tmp);
return localsub(sp, timep, 0, tmp, NULL);
}
# endif
@@ -2219,7 +2170,7 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
}
if (0 <= tz_change_interval || setname || !lcl_is_set)
tzset_unlocked(!err, false, now);
tmp = localsub(lclptr, timep, setname, tmp);
tmp = localsub(lclptr, timep, setname, tmp, NULL);
unlock(!err);
return tmp;
}
@@ -2246,11 +2197,11 @@ localtime_r(const time_t *restrict timep, struct tm *restrict tmp)
static struct tm *
gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
int_fast32_t offset, struct tm *tmp)
int_fast32_t offset, struct tm *tmp, time_t *ltm_year)
{
register struct tm * result;
result = timesub(timep, offset, gmtptr, tmp);
result = timesub(timep, offset, gmtptr, tmp, ltm_year);
#ifdef TM_ZONE
/*
** Could get fancy here and deliver something such as
@@ -2273,7 +2224,7 @@ struct tm *
gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
{
gmtcheck();
return gmtsub(gmtptr, timep, 0, tmp);
return gmtsub(gmtptr, timep, 0, tmp, NULL);
}
struct tm *
@@ -2294,7 +2245,7 @@ struct tm *
offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp)
{
gmtcheck();
return gmtsub(gmtptr, timep, offset, tmp);
return gmtsub(gmtptr, timep, offset, tmp, NULL);
}
struct tm *
@@ -2330,7 +2281,7 @@ leaps_thru_end_of(time_t y)
static struct tm *
timesub(const time_t *timep, int_fast32_t offset,
const struct state *sp, struct tm *tmp)
const struct state *sp, struct tm *tmp, time_t *ltm_year)
{
register time_t tdays;
register const int * ip;
@@ -2380,7 +2331,7 @@ timesub(const time_t *timep, int_fast32_t offset,
idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT;
idays %= DAYSPERREPEAT;
/* Increase Y and decrease IDAYS until IDAYS is in range for Y. */
while (year_lengths[isleap(y)] <= idays) {
while (year_days(y) <= idays) {
int tdelta = idays / DAYSPERLYEAR;
int_fast32_t ydelta = tdelta + !tdelta;
time_t newy = y + ydelta;
@@ -2392,29 +2343,34 @@ timesub(const time_t *timep, int_fast32_t offset,
y = newy;
}
if (ltm_year) {
*ltm_year = y - TM_YEAR_BASE;
} else {
#ifdef ckd_add
if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) {
errno = EOVERFLOW;
return NULL;
}
if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) {
errno = EOVERFLOW;
return NULL;
}
#else
if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) {
int signed_y = y;
tmp->tm_year = signed_y - TM_YEAR_BASE;
} else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y)
&& y - TM_YEAR_BASE <= INT_MAX)
tmp->tm_year = y - TM_YEAR_BASE;
else {
errno = EOVERFLOW;
return NULL;
}
if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) {
int signed_y = y;
tmp->tm_year = signed_y - TM_YEAR_BASE;
} else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y)
&& y - TM_YEAR_BASE <= INT_MAX)
tmp->tm_year = y - TM_YEAR_BASE;
else {
errno = EOVERFLOW;
return NULL;
}
#endif
}
tmp->tm_yday = idays;
/*
** The "extra" mods below avoid overflow problems.
*/
tmp->tm_wday = (TM_WDAY_BASE
+ ((tmp->tm_year % DAYSPERWEEK)
+ ((y % DAYSPERWEEK - TM_YEAR_BASE % DAYSPERWEEK)
% DAYSPERWEEK
* (DAYSPERNYEAR % DAYSPERWEEK))
+ leaps_thru_end_of(y - 1)
- leaps_thru_end_of(TM_YEAR_BASE - 1)
@@ -2459,27 +2415,6 @@ timesub(const time_t *timep, int_fast32_t offset,
** Normalize logic courtesy Paul Eggert.
*/
static bool
increment_overflow(int *ip, int j)
{
#ifdef ckd_add
return ckd_add(ip, *ip, j);
#else
register int const i = *ip;
/*
** 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;
#endif
}
static bool
increment_overflow_64(int *ip, int_fast64_t j)
{
@@ -2588,7 +2523,7 @@ mktmcpy(struct tm *dest, struct tm const *src)
static time_t
time2sub(struct tm *const tmp,
struct tm *funcp(struct state const *, time_t const *,
int_fast32_t, struct tm *),
int_fast32_t, struct tm *, time_t *),
struct state const *sp,
const int_fast32_t offset,
bool *okayp,
@@ -2648,12 +2583,12 @@ time2sub(struct tm *const tmp,
while (mday <= 0) {
iinntt li = y - (yourtm.tm_mon <= 1);
mday += year_lengths[isleap(li)];
mday += year_days(li);
y--;
}
while (DAYSPERLYEAR < mday) {
iinntt li = y + (1 < yourtm.tm_mon);
mday -= year_lengths[isleap(li)];
mday -= year_days(li);
y++;
}
yourtm.tm_mday = mday;
@@ -2705,7 +2640,7 @@ time2sub(struct tm *const tmp,
t = lo;
else if (t > hi)
t = hi;
if (! funcp(sp, &t, offset, &mytm)) {
if (! funcp(sp, &t, offset, &mytm, NULL)) {
/*
** Assume that t is too extreme to be represented in
** a struct tm; arrange things so that it is less
@@ -2761,7 +2696,7 @@ time2sub(struct tm *const tmp,
# endif
if (!v && !increment_overflow_time_64(&altt, offdiff)) {
struct tm alttm;
if (funcp(sp, &altt, offset, &alttm)
if (funcp(sp, &altt, offset, &alttm, NULL)
&& alttm.tm_isdst == mytm.tm_isdst
&& alttm.TM_GMTOFF == yourtm.TM_GMTOFF
&& tmcomp(&alttm, &yourtm) == 0) {
@@ -2795,7 +2730,7 @@ time2sub(struct tm *const tmp,
utoff_diff(sp->ttis[j].tt_utoff,
sp->ttis[i].tt_utoff)))
continue;
if (! funcp(sp, &newt, offset, &mytm))
if (! funcp(sp, &newt, offset, &mytm, NULL))
continue;
if (tmcomp(&mytm, &yourtm) != 0)
continue;
@@ -2813,7 +2748,7 @@ time2sub(struct tm *const tmp,
label:
if (increment_overflow_time_iinntt(&t, saved_seconds))
return WRONG;
if (funcp(sp, &t, offset, tmp))
if (funcp(sp, &t, offset, tmp, NULL))
*okayp = true;
return t;
}
@@ -2821,7 +2756,7 @@ label:
static time_t
time2(struct tm * const tmp,
struct tm *funcp(struct state const *, time_t const *,
int_fast32_t, struct tm *),
int_fast32_t, struct tm *, time_t *),
struct state const *sp,
const int_fast32_t offset,
bool *okayp)
@@ -2840,7 +2775,7 @@ time2(struct tm * const tmp,
static time_t
time1(struct tm *const tmp,
struct tm *funcp(struct state const *, time_t const *,
int_fast32_t, struct tm *),
int_fast32_t, struct tm *, time_t *),
struct state const *sp,
const int_fast32_t offset)
{
+13 -2
View File
@@ -255,6 +255,9 @@ strnlen (char const *s, size_t maxlen)
#ifndef ENOMEM
# define ENOMEM EINVAL
#endif
#ifndef ENOSYS
# define ENOSYS EINVAL
#endif
#ifndef ENOTCAPABLE
# define ENOTCAPABLE EINVAL
#endif
@@ -264,6 +267,9 @@ strnlen (char const *s, size_t maxlen)
#ifndef EOVERFLOW
# define EOVERFLOW EINVAL
#endif
#ifndef EPERM
# define EPERM EINVAL
#endif
#if HAVE_GETTEXT
# include <libintl.h>
@@ -305,6 +311,7 @@ extern int optind;
#ifndef HAVE_ISSETUGID
# if (defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
|| defined __DragonFly__ \
|| (defined __linux__ && !defined __GLIBC__) /* Android, musl, etc. */ \
|| (defined __APPLE__ && defined __MACH__) || defined __sun)
# define HAVE_ISSETUGID 1
@@ -813,6 +820,7 @@ void tzset(void);
# if (202311 <= __STDC_VERSION__ \
|| defined __GLIBC__ || defined __tm_zone /* musl */ \
|| defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
|| defined __DragonFly__ || defined __HAIKU__ \
|| (defined __APPLE__ && defined __MACH__))
# define HAVE_DECL_TIMEGM 1
# else
@@ -841,7 +849,8 @@ extern char **environ;
#ifndef HAVE_MEMPCPY
# if (defined mempcpy \
|| defined __FreeBSD__ || defined __NetBSD__ || defined __linux__)
|| defined __FreeBSD__ || defined __NetBSD__ || defined __DragonFly__ \
|| defined __linux__)
# define HAVE_MEMPCPY 1
# else
# define HAVE_MEMPCPY 0
@@ -906,6 +915,7 @@ time_t posix2time(time_t);
|| defined __GLIBC__ \
|| defined __tm_zone /* musl */ \
|| defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
|| defined __DragonFly__ || defined __HAIKU__ \
|| (defined __APPLE__ && defined __MACH__))
# if !defined TM_GMTOFF && !defined NO_TM_GMTOFF
# define TM_GMTOFF tm_gmtoff
@@ -1170,6 +1180,7 @@ enum {
};
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
#define year_days(y) (DAYSPERNYEAR + isleap(y))
/*
** Since everything in isleap is modulo 400 (or a factor of 400), we know that
@@ -1183,6 +1194,6 @@ enum {
** We use this to avoid addition overflow problems.
*/
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
#define year_sum_days(a, b) (DAYSPERNYEAR + isleap((a) % 400 + (b) % 400))
#endif /* !defined PRIVATE_H */
+3 -6
View File
@@ -464,9 +464,7 @@ label:
int bot;
int top;
len = isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
len = year_sum_days(year, base);
/*
** What yday (-3 ... 3) does
** the ISO year begin on?
@@ -493,9 +491,8 @@ label:
break;
}
--base;
yday += isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
yday += year_sum_days(year,
base);
}
#ifdef XPG4_1994_04_09
if ((w == 52 &&
+32 -31
View File
@@ -12,6 +12,7 @@
</head>
<body>
<main>
<h1>Theory and pragmatics of the <code><abbr>tz</abbr></code> code and data</h1>
<nav>
<ul>
@@ -26,10 +27,10 @@
<li><a href="#leapsec">Leap seconds</a></li>
<li><a href="#calendar">Calendrical issues</a></li>
<li><a href="#planets">Time and time zones off earth</a></li>
<li><a href="#see-also">See also</a></li>
</ul>
</nav>
<section>
<h2 id="scope">Scope of the <code><abbr>tz</abbr></code> database</h2>
<p>
The <a
@@ -112,9 +113,6 @@ It does not always make sense to talk about a timezone’s
“base offset”, which is not necessarily a single number.
</p>
</section>
<section>
<h2 id="naming">Timezone identifiers</h2>
<p>
Each timezone has a name that uniquely identifies the timezone.
@@ -345,8 +343,7 @@ These legacy names are mostly defined in the file
"<code>etcetera</code>".
Also, the file "<code>backward</code>" defines the legacy names
<code>Etc/GMT0</code>, <code>Etc/GMT-0</code>, <code>Etc/GMT+0</code>,
<code>GMT0</code>, <code>GMT-0</code> and <code>GMT+0</code>,
and the file "<code>northamerica</code>" defines the legacy names
<code>GMT0</code>, <code>GMT-0</code>, <code>GMT+0</code>,
<code>EST5EDT</code>, <code>CST6CDT</code>,
<code>MST7MDT</code>, and <code>PST8PDT</code>.
</li>
@@ -387,11 +384,11 @@ and <code>zone.tab</code>.
<p>
The database defines each timezone name to be a zone, or a link to a zone.
The source file <code>backward</code> defines links for backward
compatibility; it does not define zones.
The source file <code>backward</code> defines links
and a few zones for backward compatibility.
Although <code>backward</code> was originally designed to be optional,
nowadays distributions typically use it
and no great weight should be attached to whether a link
and no great weight should be attached to whether a link or zone
is defined in <code>backward</code> or in some other file.
The source file <code>etcetera</code> defines names that may be useful
on platforms that do not support proleptic <code>TZ</code> strings
@@ -404,9 +401,7 @@ second information on platforms that support leap seconds.
Another <code>etcetera</code> name, <code>GMT</code>,
is used by older code releases.
</p>
</section>
<section>
<h2 id="abbreviations">Time zone abbreviations</h2>
<p>
When this package is installed, it generates time zone abbreviations
@@ -610,9 +605,7 @@ Israel.
To avoid ambiguity, use numeric <abbr>UT</abbr> offsets like
<code>-</code>0600 instead of time zone abbreviations like CST.
</p>
</section>
<section>
<h2 id="accuracy">Accuracy of the <code><abbr>tz</abbr></code> database</h2>
<p>
The <code><abbr>tz</abbr></code> database is not authoritative, and it
@@ -876,9 +869,7 @@ merely because two locations
differ in <abbr>LMT</abbr> or transitioned to standard time at
different dates.
</p>
</section>
<section>
<h2 id="functions">Time and date functions</h2>
<p>
The <code><abbr>tz</abbr></code> code contains time and date functions
@@ -1284,9 +1275,7 @@ The vestigial <abbr>API</abbr>s are:
much the better.
</li>
</ul>
</section>
<section>
<h2 id="stability">Interface stability</h2>
<p>
The <code><abbr>tz</abbr></code> code and data supply the following interfaces:
@@ -1353,9 +1342,7 @@ than Bangkok by putting <samp>Asia/Bangkok</samp> in the event’s record,
the application should be robust in the presence of timezone splits
between now and the future time.
</p>
</section>
<section>
<h2 id="leapsec">Leap seconds</h2>
<p>
Leap seconds were introduced in 1972 to accommodate the
@@ -1430,9 +1417,7 @@ Alternatively, you can install just one set of <abbr>TZif</abbr> files
in the first place; see the <code>REDO</code> variable in this package’s
<a href="https://en.wikipedia.org/wiki/Makefile">makefile</a>.
</p>
</section>
<section>
<h2 id="calendar">Calendrical issues</h2>
<p>
Calendrical issues are a bit out of scope for a time zone database,
@@ -1446,22 +1431,30 @@ Other information and sources are given in the file "<code>calendars</code>"
in the <code><abbr>tz</abbr></code> distribution.
They sometimes disagree.
</p>
</section>
<section>
<h2 id="planets">Time and time zones off Earth</h2>
<p>
The European Space Agency is <a
href="https://www.esa.int/Applications/Satellite_navigation/Telling_time_on_the_Moon">considering</a>
the establishment of a reference timescale for the Moon, which has
Efforts are underway to establish a reference timescale for the Moon, which has
days roughly equivalent to 29.5 Earth days, and where relativistic
effects cause clocks to tick slightly faster than on Earth.
Also, <abbr title="National Aeronautics and Space Administration">NASA</abbr>
has been <a
The European Space Agency <a
href="https://www.esa.int/Applications/Satellite_navigation/Telling_time_on_the_Moon">began
considering</a> the problem in 2023, and in 2024
<abbr title="National Aeronautics and Space Administration">NASA</abbr>
was <a
href="https://bidenwhitehouse.archives.gov/wp-content/uploads/2024/04/Celestial-Time-Standardization-Policy.pdf">ordered</a>
to consider the establishment of Coordinated Lunar Time (<abbr>LTC</abbr>).
It is not yet known whether the US and European efforts will result in
multiple timescales on the Moon.
In 2025 a team at China’s
<a href="https://en.wikipedia.org/wiki/Purple_Mountain_Observatory">Purple
Mountain Observatory</a> published
<a href="https://doi.org/10.1051/0004-6361/202557345">Lunar Time Ephemeris
440</a>, the first formal proposal for a standard
for Temps Coordonné Lunaire (<abbr>TCL</abbr>).
A <a href="https://www.bipm.org/documents/20126/284836054/CGPM-2026-Draft-Resolutions.pdf">draft
resolution of the 13–15 October 2026 General Conference on Weights
and Measures</a> recommends that the <a href="https://www.bipm.org/en/">Bureau
International des Poids et Mesures</a> collaborate with space agencies
and other organizations on this matter.
</p>
<p>
@@ -1583,7 +1576,15 @@ Sources for time on other planets:
(2016-01-20).
</li>
</ul>
</section>
</main>
<aside>
<h2 id="see-also">See also</h2>
<ul>
<li><a href="tz-link.html">Time zone and daylight saving time data</a></li>
<li><a href="tz-art.html">Time and the arts</a></li>
</ul>
</aside>
<footer>
<hr>
+11 -3
View File
@@ -9,6 +9,7 @@ ul {padding-left: 1.3rem;}
<title>Time and the arts</title>
</head>
<body>
<main>
<h1>Time and the arts</h1>
<h2>Documentaries</h2>
<ul>
@@ -466,8 +467,10 @@ Unlike minimalism, it does not assume that the listener has plenty of time.
<li>
The webcomic <em>xkcd</em> has the strips
“<a href="https://xkcd.com/673/">The Sun</a>” (2009-12-09),
“<a href="https://xkcd.com/1655/">Doomsday Clock</a>” (2016-03-14) and
“<a href="https://xkcd.com/1655/">Doomsday Clock</a>” (2016-03-14),
“<a href="https://xkcd.com/2549/">Edge Cake</a>” (2021-12-01),
“<a href="https://xkcd.com/2867/">DateTime</a>” (2023-12-13),
and “<a href="https://xkcd.com/3272/">Time Change</a>” (2026-07-15),
along with the panels
“<a href="https://xkcd.com/448/">Good Morning</a>” (2008-07-11),
“<a href="https://xkcd.com/1017/">Backward in Time</a>” (2012-02-14),
@@ -482,8 +485,7 @@ along with the panels
“<a href="https://xkcd.com/2266/">Leap Smearing</a>” (2020-02-10),
“<a href="https://xkcd.com/2594/">Consensus Time</a>” (2022-03-16),
“<a href="https://xkcd.com/2846/">Daylight Saving Choice</a>” (2023-10-25),
“<a href="https://xkcd.com/2854/">Date Line</a>” (2023-11-13),
and “<a href="https://xkcd.com/2867/">DateTime</a>” (2023-12-13).
and “<a href="https://xkcd.com/2854/">Date Line</a>” (2023-11-13).
The related book <em>What If?</em> has an entry
“<a href="https://what-if.xkcd.com/26/">Leap Seconds</a>” (2012-12-31).
</li>
@@ -611,10 +613,16 @@ but maybe in your time zone I haven’t finished yet. So stay tuned!”
(Goldie Hawn, <em>Rowan &amp; Martin’s Laugh-In</em> No. 65, 1970-03-09)
</li>
</ul>
</main>
<aside>
<h2>See also</h2>
<ul>
<li><a href="tz-link.html">Time zone and daylight saving time data</a></li>
<li><a href="theory.html">Theory and pragmatics of the
<code><abbr>tz</abbr></code> code and data</a></li>
</ul>
</aside>
<footer>
<hr>
+11 -7
View File
@@ -15,6 +15,7 @@ ul {padding-left: 1.3rem;}
</style>
</head>
<body>
<main>
<h1>How to Read the <a href="https://en.wikipedia.org/wiki/Tz_database">tz
Database</a> Source Files</h1>
<h2>by Bill Seymour</h2>
@@ -415,17 +416,19 @@ Line. For example:</p>
<pre>
#Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Juneau 15:02:19 - LMT 1867 Oct 18
Zone America/Juneau 15:02:19 - LMT 1867 Oct 19 0:31:13u
-8:57:41 - LMT ...
</pre>
<p>When Alaska was purchased from Russia in 1867, the Date Line moved
from the Alaska/Canada border to the Bering Strait; and the time in
Alaska was then 24 hours earlier than it had
been. <code>&lt;aside&gt;</code>(6 October in the Julian calendar,
which Russia was still using then for religious reasons, was followed
by <i>a second instance of the same day with a different name</i>, 18
October in the Gregorian calendar. Isn’t civil time
been. <code>&lt;aside&gt;</code>(This also means that, although the sun had set
on Friday 6 October and risen on Saturday 7 October in the Julian calendar,
which Russia was still using then for religious reasons, upon the transfer
Saturday afternoon became Friday afternoon, and then the sun set and rose once
more on <i>second instances of the same days with different names</i>,
Friday 18 and Saturday 19 October in the Gregorian calendar. Isn’t civil time
wonderful? <code>8-)</code>)<code>&lt;/aside&gt;</code></p>
<p>The abbreviation, “LMT” stands for “local mean
@@ -660,14 +663,15 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00
</table>
<p>There will be a short quiz later. <code>8-)</code></p>
</main>
<footer>
<hr>
<address>
This web page is in the public domain, so clarified as of
2015-10-20 by Bill Seymour.
<br>
All suggestions and corrections will be welcome; all flames will be amusing.
Mail to was at pobox dot com.
</address>
</footer>
</body>
</html>
+60 -58
View File
@@ -11,6 +11,7 @@ ul {padding-left: 1.3rem;}
</style>
</head>
<body>
<main>
<h1>Time zone and daylight saving time data</h1>
<p>
<a href="https://en.wikipedia.org/wiki/Time_zone">Time zone</a> and
@@ -61,7 +62,6 @@ area.
</ul>
</nav>
<section>
<h2 id="tzdb">The <code><abbr title="time zone">tz</abbr></code> database</h2>
<p>
The <a href="https://en.wikipedia.org/wiki/Public_domain">public-domain</a>
@@ -84,6 +84,7 @@ title="Berkeley Software Distribution">BSD</abbr></a>,
<a href="https://netbsd.org">Net<abbr>BSD</abbr></a>,
<a href="https://www.openbsd.org">Open<abbr>BSD</abbr></a>,
<a href="https://www.chromium.org/chromium-os/">ChromiumOS</a>,
<a href="https://en.wikipedia.org/wiki/OpenHarmony">OpenHarmony</a>,
<a href="https://cygwin.com">Cygwin</a>,
<a href="https://mariadb.org">MariaDB</a>,
<a href="https://musl.libc.org">musl libc</a>,
@@ -133,9 +134,7 @@ Universal Time</a> (<abbr>UTC</abbr>).
The database also records when daylight saving time was in use,
along with some time zone abbreviations such as <abbr>EST</abbr>
for Eastern Standard Time in the <abbr>US</abbr>.</p>
</section>
<section>
<h2 id="download">Downloading the <code><abbr>tz</abbr></code> database</h2>
<p>
The following <a
@@ -145,15 +144,15 @@ the latest release’s two
to a <abbr>GNU</abbr>/Linux or similar host.</p>
<pre><code>mkdir tzdb
cd tzdb
<a href="https://www.gnu.org/software/wget/">wget</a> https://www.iana.org/time-zones/repository/tzcode-latest.tar.gz
wget https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz
<a href="https://www.gnu.org/software/wget/">wget</a> https://data.iana.org/time-zones/tzcode-latest.tar.gz
wget https://data.iana.org/time-zones/tzdata-latest.tar.gz
<a href="https://www.gnu.org/software/gzip/">gzip</a> -dc tzcode-latest.tar.gz | <a href="https://www.gnu.org/software/tar/">tar</a> -xf -
gzip -dc tzdata-latest.tar.gz | tar -xf -
</code></pre>
<p>Alternatively, the following shell commands download the same
release in a single-tarball format containing extra data
useful for regression testing:</p>
<pre><code>wget <a href="https://www.iana.org/time-zones/repository/tzdb-latest.tar.lz">https://www.iana.org/time-zones/repository/tzdb-latest.tar.lz</a>
<pre><code>wget <a href="https://data.iana.org/time-zones/tzdb-latest.tar.lz">https://data.iana.org/time-zones/tzdb-latest.tar.lz</a>
<a href="https://www.nongnu.org/lzip/">lzip</a> -dc tzdb-latest.tar.lz | tar -xf -
</code></pre>
<p>These commands use convenience links to the latest release
@@ -183,7 +182,7 @@ title="Hypertext Transfer Protocol Secure">HTTPS</abbr></a>,
<a href="https://en.wikipedia.org/wiki/Rsync"><abbr
title="remote sync">rsync</abbr></a>, and
<a href="https://en.wikipedia.org/wiki/FTP"><abbr
title="File Transfer Protocol">FTP</abbr></a>.
title="File Transfer Protocol">FTP</abbr></a>.</p>
<p>Alternatively, a development repository of code and data can be
retrieved from <a href="https://github.com">GitHub</a> via the shell
command:</p>
@@ -205,9 +204,7 @@ Time Zone Information Format (<abbr>TZif</abbr>)</a>
The code also lets
you read a <abbr>TZif</abbr> file and interpret timestamps for that
location.</p>
</section>
<section>
<h2 id="changes">Changes to the <code><abbr>tz</abbr></code> database</h2>
<p>
The <code><abbr>tz</abbr></code> code and data
@@ -234,7 +231,10 @@ the process by tailoring the generic instructions in
the <code><abbr>tz</abbr> README</code> file and installing the latest
data yourself. System-specific instructions for installing the
latest <code><abbr>tz</abbr></code> data have also been published
for <a href="https://www.ibm.com/support/pages/aix-time-zone-olson-tzdata-updates"><abbr>AIX</abbr></a>,
for <a href="https://community.ibm.com/community/user/blogs/ravindra-shinde/2024/12/13/time-zone-update-tool-tz"><abbr>AIX</abbr></a>
(and
<a href="https://www.ibm.com/support/pages/aix-time-zone-olson-tzdata-updates">older
<abbr>AIX</abbr></a>),
<a
href="https://source.android.com/docs/core/permissions/timezone-rules">Android</a>,
<a
@@ -276,16 +276,14 @@ found in <a href="theory.html">Theory and pragmatics of the
<a href="https://a0.github.io/a0-tzmigration/">A0 TimeZone Migration</a>
displays changes between recent <code><abbr>tzdb</abbr></code> versions.
</p>
</section>
<section>
<h2 id="coordinating">Coordinating with governments and distributors</h2>
<p>
As discussed in
“<a href="https://www.icann.org/en/blogs/details/how-time-zones-are-coordinated-13-03-2023-en">How
Time Zones Are Coordinated</a>”, the time zone database relies on
collaboration among governments, the time zone database volunteer
community, and data distributors downstream.
community, and data distributors downstream.</p>
<p>
If your government plans to change its time zone boundaries or
daylight saving rules, please send email as described in
@@ -326,9 +324,7 @@ The shorter the notice, the more likely clock problems will arise; see “<a
href="https://codeofmatt.com/on-the-timing-of-time-zone-changes/">On
the Timing of Time Zone Changes</a>” for examples.
</p>
</section>
<section>
<h2 id="commentary">Commentary on the <code><abbr>tz</abbr></code> database</h2>
<ul>
<li>The article
@@ -344,9 +340,7 @@ database’s style.</li>
<li><a href="https://doi.org/10.1145/3340301.3341125">What time is it:
managing time in the internet</a> analyzes the database longitudinally.</li>
</ul>
</section>
<section>
<h2 id="web">Web sites using recent versions of the
<code><abbr>tz</abbr></code> database</h2>
<p>
@@ -380,9 +374,7 @@ calculates the current time difference between locations.</li>
<li><a href="https://www.wx-now.com">Weather Now</a> and
<a href="https://www.thetimenow.com">The Time Now</a> list the weather too.</li>
</ul>
</section>
<section>
<h2 id="protocols">Network protocols for <code><abbr>tz</abbr></code> data</h2>
<ul>
<li><a href="https://www.rfc-editor.org/info/rfc7808/">Time Zone
@@ -405,9 +397,7 @@ title="Extensible Markup Language">XML</abbr></a> format, and a variant
uses <a href="https://www.json.org/json-en.html"><abbr
title="JavaScript Object Notation">JSON</abbr></a> format.</li>
</ul>
</section>
<section>
<h2 id="compilers">Other <code><abbr>tz</abbr></code> compilers</h2>
<p>Although some of these do not fully support
<code><abbr>tz</abbr></code> data, in recent <code><abbr>tzdb</abbr></code>
@@ -416,7 +406,7 @@ running the command <code>make rearguard_tarballs</code> and compiling
from the resulting tarballs instead.</p>
<ul>
<li><a href="https://github.com/libical">Libical</a>
contains <code>vzic</code>, <a
contains <code>vzic</code>, a <a
href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a>
program that compiles
<code><abbr>tz</abbr></code> source into iCalendar-compatible VTIMEZONE files.
@@ -425,6 +415,23 @@ available under the <a
href="https://www.gnu.org/copyleft/gpl.html"><abbr>GNU</abbr>
General Public License (<abbr
title="General Public License">GPL</abbr>)</a>.</li>
<li>The <a id="TZDP"
href="https://howardhinnant.github.io/date/tz.html">Time Zone
Database Parser</a> contains a
<a href="https://en.wikipedia.org/wiki/C++">C++</a> runtime parser
supporting the <a
href="https://en.cppreference.com/cpp/chrono#Time_zone"><code>std::chrono::time_zone</code> API</a>
that is standardized in
<a href="https://en.wikipedia.org/wiki/C%2B%2B20">C++20</a> and later.
It is freely available under the
<a href="https://en.wikipedia.org/wiki/MIT_License"><abbr
title="Massachusetts Institute of Technology">MIT</abbr> license</a>.
This approach is used by the <code>std::chrono::time_zone</code> implementation
of <a href="https://gcc.gnu.org/"><abbr
title="the GNU Compiler Collection">GCC</abbr></a>
<code>libstdc++</code>, which is available under the GPL combined
with the <a href="https://www.gnu.org/licenses/gcc-exception.html">GCC
Runtime Library Exception</a>.</li>
<li><a
href="https://metacpan.org/release/DateTime-TimeZone">DateTime::TimeZone</a>
contains a script <code>parse_olson</code> that compiles
@@ -436,14 +443,6 @@ available under both the <abbr>GPL</abbr> and the Perl Artistic
License. DateTime::TimeZone also contains a script
<code>tests_from_zdump</code> that generates test cases for each clock
transition in the <code><abbr>tz</abbr></code> database.</li>
<li>The <a href="https://howardhinnant.github.io/date/tz.html">Time Zone
Database Parser</a> is a
<a href="https://en.wikipedia.org/wiki/C++">C++</a> parser and
runtime library with a <a
href="https://en.cppreference.com/cpp/chrono"><code>std::chrono</code> API</a>
that is a standard part of C++.
It is freely available under the
<abbr title="Massachusetts Institute of Technology">MIT</abbr> license.</li>
<li><a id="ICU" href="https://icu.unicode.org">International Components for
Unicode (<abbr>ICU</abbr>)</a> contains C/C++ and <a
href="https://en.wikipedia.org/wiki/Java_(programming_language)">Java</a>
@@ -498,6 +497,7 @@ License">LGPL</abbr>)</a>.</li>
<li><abbr>ICU</abbr> (mentioned <a href="#ICU">above</a>) contains compilers and
Java-based libraries.</li>
</ul>
</li>
<li><a href="https://nodatime.org">Noda Time – Date and
time <abbr>API</abbr> for .NET</a>
is like Joda-Time and Time4J, but for the .NET framework instead of Java.
@@ -549,6 +549,7 @@ objects</a> let programs access an abstract view of
<code><abbr>tzdb</abbr></code> data, and are designed to replace <a
href="https://codeofmatt.com/javascript-date-type-is-horribly-broken/">JavaScript’s
problematic <code>Date</code> objects</a> when working with dates and times.
</li>
<li><a href="https://github.com/JuliaTime">JuliaTime</a> contains a
compiler from <code><abbr>tz</abbr></code> source into
<a href="https://julialang.org">Julia</a>. It is freely available
@@ -587,9 +588,7 @@ source into text files, along with a runtime that can read those
files. Tcl is freely available under a <abbr>BSD</abbr>-style
license.</li>
</ul>
</section>
<section>
<h2 id="TZif">Other <abbr>TZif</abbr> readers</h2>
<ul>
<li>The <a
@@ -604,6 +603,17 @@ a <abbr>TZif</abbr> file reader written in C that
creates a <code>GTimeZone</code> object representing sets
of <abbr>UT</abbr> offsets.
It is freely available under the <abbr>LGPL</abbr>.</li>
<li>The <a href="https://en.wikipedia.org/wiki/Musl">musl</a> C library
also has an <abbr>TZif</abbr> reader.
It is freely available under the <abbr>MIT</abbr> license.</li>
<li>The Time Zone Database Parser for C++, mentioned <a href="#TZDP">above,</a>
can be configured to read TZif binary files.
A similar approach is taken in
<a href="https://www.llvm.org/"><abbr>LLVM</abbr></a>
<code>std::chrono::time_zone</code>, which is available
under the Apache License with
<a href="https://llvm.org/docs/DeveloperPolicy.html#open-source-licensing-terms">LLVM
Exceptions</a>.</li>
<li>The
<a href="https://github.com/bloomberg/bde/wiki">BDE Standard Library</a>’s
<code>baltzo::TimeZoneUtil</code> component contains a C++
@@ -659,15 +669,20 @@ converts <abbr>TZif</abbr> data into
<abbr>JSON</abbr>-format data suitable for use
in its JavaScript library for time zone conversion. Dates before 1970
are not supported.</li>
<li>The <a href="https://crates.io/crates/jiff">jiff</a> datetime library
for <a href="https://rust-lang.org/">Rust</a> either compiles
<code><abbr>tz</abbr></code> source into Rust,
or consults <abbr>TZif</abbr> data at runtime.
It is in the public domain.
It intends to supplant the soft-deprecated
<a href="https://crates.io/crates/chrono-tz">Chrono-TZ</a>.</li>
<li>The <a
href="https://hackage.haskell.org/package/timezone-olson">timezone-olson</a>
package contains <a href="https://www.haskell.org">Haskell</a> code that
parses and uses <abbr>TZif</abbr> data. It is freely
available under a <abbr>BSD</abbr>-style license.</li>
</ul>
</section>
<section>
<h2 id="software">Other <code><abbr>tz</abbr></code>-based time zone software</h2>
<ul>
<li><a href="https://foxclocks.org">FoxClocks</a>
@@ -684,7 +699,10 @@ data (mentioned <a href="#CLDR">below</a>) used by the
<a href="https://en.wikipedia.org/wiki/Windows_Runtime">Windows Runtime</a> /
<a href="https://en.wikipedia.org/wiki/Universal_Windows_Platform">Universal Windows Platform</a> classes
<a href="https://learn.microsoft.com/en-us/uwp/api/Windows.Globalization.DateTimeFormatting.DateTimeFormatter"><code>DateTimeFormatter</code></a> and
<a href="https://learn.microsoft.com/en-us/uwp/api/windows.globalization.calendar"><code>Calendar</code></a>.
<a href="https://learn.microsoft.com/en-us/uwp/api/windows.globalization.calendar"><code>Calendar</code></a>,
and with updates discussed in the
<a href="https://techcommunity.microsoft.com/category/windows/blog/dstblog">Daylight
Saving Time &amp; Time Zone Blog</a>.
<a id="System.TimeZoneInfo"
href="https://learn.microsoft.com/en-us/archive/blogs/bclteam/exploring-windows-time-zones-with-system-timezoneinfo-josh-free">Exploring
Windows Time Zones with <code>System.TimeZoneInfo</code></a> describes
@@ -700,16 +718,14 @@ to <code><abbr>tz</abbr></code> names.
These mappings can be performed programmatically via the
<a href="https://github.com/mattjohnsonpint/TimeZoneConverter">TimeZoneConverter</a>
.NET library,
or the ICU Java and C++ libraries mentioned <a href="#ICU">above</a>.
or the ICU Java and C++ libraries mentioned <a href="#ICU">above</a>.</li>
<li><a
href="https://www.oracle.com/java/">Oracle
Java</a> contains a copy of a subset of a recent
<code><abbr>tz</abbr></code> database in a
Java-specific format.</li>
</ul>
</section>
<section>
<h2 id="other-dbs">Other time zone databases</h2>
<ul>
<li><a href="https://www.astro.com/atlas">Time-zone Atlas</a>
@@ -733,9 +749,7 @@ Schedules Information Manual</a> of the
International Air Transport Association
gives current time zone rules for airports served by commercial aviation.</li>
</ul>
</section>
<section>
<h2 id="maps">Maps</h2>
<ul>
<li><a href="https://www.worldtimezone.com">World Time Zone Map
@@ -757,9 +771,7 @@ World Factbook</em></a>, formerly published by the
Although the maps’ pictorial quality is good,
the maps do not indicate daylight saving time.</li>
</ul>
</section>
<section>
<h2 id="boundaries">Time zone boundaries</h2>
<p>Geographical boundaries between timezones are available
from several <a
@@ -810,9 +822,7 @@ for land and territorial waters only). A captain can change ship’s
clocks any time after entering a new time zone; midnight changes are
common.</li>
</ul>
</section>
<section>
<h2 id="civil">Civil time concepts and history</h2>
<ul>
<li><a href="https://www.nist.gov/pml/time-and-frequency-division/popular-links/walk-through-time">A
@@ -835,9 +845,7 @@ time zone boundary.</li>
<li><a href="https://statoids.com/tconcept.html">Basic Time
Zone Concepts</a> discusses terminological issues behind time zones.</li>
</ul>
</section>
<section>
<h2 id="national">National histories of legal time</h2>
<dl>
<dt>Australia</dt>
@@ -935,9 +943,7 @@ Navy (SOHMA) publishes an annual <a
href="https://sohma.armada.mil.uy/index.php/servicios/datos-astronomicos" hreflang="es">almanac
(in Spanish)</a>.</dd>
</dl>
</section>
<section>
<h2 id="costs">Costs and benefits of time shifts</h2>
<p>Various sources argue for and against daylight saving time and time
zone shifts, and many scientific studies have been conducted. This
@@ -1016,9 +1022,7 @@ opposes <abbr>DST</abbr> changes and permanent <abbr>DST</abbr>,
and advocates that governments adopt
“permanent Standard Time for the health and safety of their citizens”.</li>
</ul>
</section>
<section>
<h2 id="precision">Precision timekeeping</h2>
<ul>
<li><a
@@ -1053,7 +1057,7 @@ a client’s time zone and daylight saving settings automatically.</li>
Scales</a> describes astronomical time scales like
<abbr title="Terrestrial Dynamic Time">TDT</abbr>,
<abbr title="Geocentric Coordinate Time">TCG</abbr>, and
<abbr title="Barycentric Dynamic Time">TDB</abbr>.
<abbr title="Barycentric Dynamic Time">TDB</abbr>.</li>
<li>The <a href="https://www.iau.org"><abbr
title="International Astronomical Union">IAU</abbr></a>’s <a
href="https://www.iausofa.org"><abbr
@@ -1170,9 +1174,7 @@ However, there is still no consensus on whether this is the best way
to replace leap seconds.
</li>
</ul>
</section>
<section>
<h2 id="notation">Time notation</h2>
<ul>
<li>The <a id="CLDR" href="https://cldr.unicode.org">Unicode Common Locale Data
@@ -1183,7 +1185,7 @@ contains French translations for “Eastern European Summer Time”,
<a href="https://unicode.org/cldr/charts/latest/by_type/">by-type
charts</a> show these values for many locales. Data values are available in
both <abbr title="Locale Data Markup Language">LDML</abbr>
(an <abbr>XML</abbr> format) and <abbr>JSON</abbr>.
(an <abbr>XML</abbr> format) and <abbr>JSON</abbr>.</li>
<li>
<a href="https://www.cl.cam.ac.uk/~mgk25/iso-time.html">A summary of
the international standard date and time notation</a> covers
@@ -1209,7 +1211,7 @@ An extension, <a href="https://www.rfc-editor.org/info/rfc9557/">Date
and Time on the Internet: Timestamps with Additional Information</a>
(Internet <abbr>RFC</abbr> 9557) extends this profile
to let you specify the <code><abbr>tzdb</abbr></code> timezone of a timestamp
via suffixes like <code>[Asia/Tokyo]</code>.
via suffixes like <code>[Asia/Tokyo]</code>.</li>
<li>
<a href="https://web.archive.org/web/20190130042457/https://www.hackcraft.net/web/datetime/">Date &amp; Time
Formats on the Web</a> surveys web- and Internet-oriented date and time
@@ -1243,16 +1245,16 @@ any future changes to the rules. One should never set
local time is nine hours ahead of <abbr>UT</abbr> and the time zone
is called “<abbr>GMT</abbr>”.</li>
</ul>
</section>
</main>
<section>
<aside>
<h2 id="see-also">See also</h2>
<ul>
<li><a href="theory.html">Theory and pragmatics of the
<code><abbr>tz</abbr></code> code and data</a></li>
<li><a href="tz-art.html">Time and the arts</a></li>
</ul>
</section>
</aside>
<footer>
<hr>
+1 -2
View File
@@ -402,7 +402,6 @@ SEE ALSO
time(2), localtime(3), tzset(3), tzselect(8), zdump(8), zic(8).
Olson A, Eggert P, Murchison K. The Time Zone Information Format
(TZif). October 2024. Internet RFC 9636 ⟨https://www.rfc-editor.org/
rfc/rfc9636⟩ doi:10.17487/RFC9636 ⟨https://doi.org/10.17487/RFC9636⟩.
(TZif). October 2024. Internet RFC 9636 doi:10.17487/RFC9636.
Time Zone Database tzfile(5)
+1 -1
View File
@@ -1 +1 @@
2026c
2026d
+2 -2
View File
@@ -719,7 +719,7 @@ delta_nonneg(struct tm *newp, struct tm *oldp)
intmax_t sec = SECSPERREPEAT, result = cycles * sec;
int tmy = oldp->tm_year + cycles * YEARSPERREPEAT;
for ( ; tmy < newp->tm_year; ++tmy)
result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
result += year_sum_days(tmy, TM_YEAR_BASE);
result += newp->tm_yday - oldp->tm_yday;
result *= HOURSPERDAY;
result += newp->tm_hour - oldp->tm_hour;
@@ -746,7 +746,7 @@ adjusted_yday(struct tm const *a, struct tm const *b)
{
int yday = a->tm_yday;
if (b->tm_year < a->tm_year)
yday += 365 + isleap_sum(b->tm_year, TM_YEAR_BASE);
yday += year_sum_days(b->tm_year, TM_YEAR_BASE);
return yday;
}
#endif
+30 -13
View File
@@ -330,12 +330,8 @@ for the
POSIX Portable Character Set (PPCS)
.UE
and the encoding's non-unibyte characters should consist entirely of
non-PPCS bytes. Non-PPCS characters typically occur only in comments:
although output file names and time zone abbreviations can contain
nearly any character, other software will work better if these are
limited to the restricted syntax described under the
.B \-v
option.
non-PPCS bytes.
Non-PPCS characters typically occur only in comments.
.PP
Input lines are made up of fields.
Fields are separated from one another by one or more white space characters.
@@ -350,15 +346,16 @@ Any line that is blank (after comment stripping) is ignored.
Nonblank lines are expected to be of one of three types:
rule lines, zone lines, and link lines.
.PP
Names must be in English and are case insensitive.
Keywords are in English and are case insensitive.
They are not reserved words.
They appear in several contexts, and include month and weekday names
and keywords such as
and other words such as
.BR "maximum" ,
.BR "only" ,
.BR "Rolling" ,
and
.BR "Zone" .
A name can be abbreviated by omitting all but an initial prefix; any
A keyword can be abbreviated by omitting all but an initial prefix; any
abbreviation must be unambiguous in context.
.PP
A rule line has the form
@@ -586,11 +583,26 @@ The name of the timezone.
This is the name used in creating the time conversion information file for the
timezone.
It should not contain a file name component
that is empty or is
.q ".\&"
or
.q ".." ;
a file name component is a maximal substring that does not contain
.q "/" .
Names can be further restricted by the operating system or file system.
Most systems reject a name
.IB A / B
if there is another name
.IR A ,
some reject names differing only in case,
and some reject names containing special characters like
.q ":"
and
.q "\e" .
Other software will work better if names are
limited to the restricted syntax described under the
.B \-v
option.
.TP
.B STDOFF
The amount of time to add to UT to get standard time,
@@ -737,8 +749,16 @@ A link line has the form
.ta \w'Link\0\0'u +\w'Europe/Istanbul\0\0'u
Link TARGET LINK-NAME
.sp
.fi
where
.B TARGET
and
.B LINK-NAME
both have the same syntax as a zone line's
.BR NAME .
For example:
.sp
.nf
.ti +2
Link Europe/Istanbul Asia/Istanbul
.sp
@@ -752,10 +772,7 @@ field in some zone line or as the
field in some link line.
The
.B LINK-NAME
field is used as an alternative name for that zone;
it has the same syntax as a zone line's
.B NAME
field.
field is an alternative name for that zone.
Links can chain together, although the behavior is unspecified if a
chain of one or more links does not terminate in a Zone name.
A link line can appear before the line that defines the link target.
+23 -21
View File
@@ -186,13 +186,9 @@ FILES
zero or more lines, each ending in a newline byte and containing at
most 2048 bytes counting the newline, and without any NUL bytes. The
input text's encoding is typically UTF-8 or ASCII; it should have a
unibyte representation for the POSIX Portable Character Set (PPCS)
⟨https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap06
.html⟩ and the encoding's non-unibyte characters should consist
entirely of non-PPCS bytes. Non-PPCS characters typically occur only
in comments: although output file names and time zone abbreviations can
contain nearly any character, other software will work better if these
are limited to the restricted syntax described under the -v option.
unibyte representation for the POSIX Portable Character Set (PPCS) and
the encoding's non-unibyte characters should consist entirely of non-
PPCS bytes. Non-PPCS characters typically occur only in comments.
Input lines are made up of fields. Fields are separated from one
another by one or more white space characters. The white space
@@ -206,11 +202,11 @@ FILES
lines are expected to be of one of three types: rule lines, zone lines,
and link lines.
Names must be in English and are case insensitive. They appear in
several contexts, and include month and weekday names and keywords such
as maximum, only, Rolling, and Zone. A name can be abbreviated by
omitting all but an initial prefix; any abbreviation must be
unambiguous in context.
Keywords are in English and are case insensitive. They are not
reserved words. They appear in several contexts, and include month and
weekday names and other words such as maximum, only, Rolling, and Zone.
A keyword can be abbreviated by omitting all but an initial prefix; any
abbreviation must be unambiguous in context.
A rule line has the form
@@ -330,8 +326,14 @@ FILES
NAME The name of the timezone. This is the name used in creating the
time conversion information file for the timezone. It should
not contain a file name component “.” or “..”; a file name
component is a maximal substring that does not contain “/”.
not contain a file name component that is empty or is “.” or
“..”; a file name component is a maximal substring that does not
contain “/”. Names can be further restricted by the operating
system or file system. Most systems reject a name A/B if there
is another name A, some reject names differing only in case, and
some reject names containing special characters like “:” and
“\”. Other software will work better if names are limited to
the restricted syntax described under the -v option.
STDOFF The amount of time to add to UT to get standard time, without
any adjustment for daylight saving. This field has the same
@@ -418,17 +420,17 @@ FILES
Link TARGET LINK-NAME
For example:
where TARGET and LINK-NAME both have the same syntax as a zone line's
NAME. For example:
Link Europe/Istanbul Asia/Istanbul
The TARGET field should appear as the NAME field in some zone line or
as the LINK-NAME field in some link line. The LINK-NAME field is used
as an alternative name for that zone; it has the same syntax as a zone
line's NAME field. Links can chain together, although the behavior is
unspecified if a chain of one or more links does not terminate in a
Zone name. A link line can appear before the line that defines the
link target. For example:
as the LINK-NAME field in some link line. The LINK-NAME field is an
alternative name for that zone. Links can chain together, although the
behavior is unspecified if a chain of one or more links does not
terminate in a Zone name. A link line can appear before the line that
defines the link target. For example:
Link Greenwich G_M_T
Link Etc/GMT Greenwich
+49 -40
View File
@@ -528,10 +528,6 @@ static const int len_months[2][MONSPERYEAR] = {
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
static const int len_years[2] = {
DAYSPERNYEAR, DAYSPERLYEAR
};
static struct attype {
zic_t at;
bool dontmerge;
@@ -783,6 +779,7 @@ arg2num(char const *arg, int base, unsigned long maxval, char const *msgid)
#ifndef HAVE_SETMODE
# if (defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
|| defined __DragonFly__ \
|| (defined __APPLE__ && defined __MACH__))
# define HAVE_SETMODE 1
# else
@@ -1467,6 +1464,12 @@ namecheck(const char *name)
register char const *component = name;
for (cp = name; *cp; cp++) {
unsigned char c = *cp;
#if defined _WIN32 || defined __CYGWIN__
if (c == ':' || c == '\\') {
error(N_("file name '%s' contains '%c'"), name, c);
return false;
}
#endif
if (noise && !strchr(benign, c)) {
warning((strchr(printable_and_not_benign, c)
? N_("file name '%s' contains byte '%c'")
@@ -1781,8 +1784,20 @@ dolink(char const *target, char const *linkname, bool staysymlink)
break;
}
link_errno = errno;
/* When hard links are not supported, some MS-Windows file system
drivers fail with EINVAL, contrary to the intent of
MS-FSA 42.0 (2025) section 2.1.5.15.7. */
if (link_errno == EINVAL)
link_errno = ENOTSUP;
}
#endif
/* On platforms like AIX, the Linux kernel, macOS, and Solaris,
link/linkat can fail with ENOSYS or EPERM if the file system
does not support hard links, or if other problems occur.
It is too much trouble to suss out the other problems. */
if (link_errno == ENOSYS || link_errno == EPERM)
link_errno = ENOTSUP;
if (link_errno == EXDEV || link_errno == ENOTSUP)
break;
@@ -1849,7 +1864,8 @@ dolink(char const *target, char const *linkname, bool staysymlink)
strerror(link_errno));
else if (symlink_errno < 0)
warning(N_("copy used because symbolic link not obvious"));
else if (symlink_errno != ENOTSUP)
else if (symlink_errno != ENOSYS && symlink_errno != ENOTSUP
&& symlink_errno != EPERM)
warning(N_("copy used because symbolic link failed: %s"),
strerror(symlink_errno));
}
@@ -2307,18 +2323,13 @@ inzsub(char **fields, int nfields, bool iscont)
static zic_t
getleapdatetime(char **fields, bool expire_line)
{
register const char * cp;
register const struct lookup * lp;
register zic_t i, j;
zic_t year;
int month, day;
zic_t dayoff, tod;
zic_t t;
char xs;
struct rule r;
dayoff = 0;
cp = fields[LP_YEAR];
if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
if (sscanf(fields[LP_YEAR], "%"SCNdZIC"%c", &year, &xs) != 1) {
/*
** Leapin' Lizards!
*/
@@ -2332,38 +2343,20 @@ getleapdatetime(char **fields, bool expire_line)
leapminyear = year;
leapseen = true;
}
j = EPOCH_YEAR;
while (j != year) {
if (year > j) {
i = len_years[isleap(j)];
++j;
} else {
--j;
i = -len_years[isleap(j)];
}
dayoff = oadd(dayoff, i);
}
if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
error(N_("invalid month name"));
return -1;
}
month = lp->l_value;
j = TM_JANUARY;
while (j != month) {
i = len_months[isleap(year)][j];
dayoff = oadd(dayoff, i);
++j;
}
cp = fields[LP_DAY];
if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
day <= 0 || day > len_months[isleap(year)][month]) {
r.r_month = lp->l_value;
if (! (sscanf(fields[LP_DAY], "%d%c", &r.r_dayofmonth, &xs) == 1
&& 0 < r.r_dayofmonth
&& r.r_dayofmonth <= len_months[isleap(year)][r.r_month])) {
error(N_("invalid day of month"));
return -1;
}
dayoff = oadd(dayoff, day - 1);
t = omul(dayoff, SECSPERDAY);
tod = gethms(fields[LP_TIME], N_("invalid time of day"));
t = tadd(t, tod);
r.r_dycode = DC_DOM;
r.r_tod = gethms(fields[LP_TIME], N_("invalid time of day"));
t = rpytime(&r, year);
if (t < 0)
error(N_("leap second precedes Epoch"));
return t;
@@ -2419,6 +2412,8 @@ inlink(char **fields, int nfields)
error(N_("blank TARGET field on Link line"));
return;
}
if (! namecheck(fields[LF_TARGET]))
return;
if (! namecheck(fields[LF_LINKNAME]))
return;
l.l_filenum = filenum;
@@ -3552,10 +3547,13 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
} else
defaulttype = type;
} else {
zic_t year;
for (year = min_year; year <= max_year; ++year) {
zic_t year, next_year;
bool try_next_year = true;
for (year = min_year; try_next_year; year = next_year) {
if (useuntil && year > zp->z_untilrule.r_hiyear)
break;
try_next_year = false;
next_year = max_year;
/*
** Mark which rules to do in the current year.
** For those to do, calculate rpytime(rp, year);
@@ -3567,6 +3565,17 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
struct rule *rp = &zp->z_rules[j];
eats(zp->z_filenum, zp->z_linenum,
rp->r_filenum, rp->r_linenum);
/* Keep track of the earliest year after YEAR
in which some rule <= J applies. */
if (year < rp->r_hiyear) {
zic_t next = max(year + 1, rp->r_loyear);
if (next <= next_year) {
next_year = next;
try_next_year = true;
}
}
rp->r_todo = year >= rp->r_loyear &&
year <= rp->r_hiyear;
if (rp->r_todo) {
@@ -4147,7 +4156,7 @@ rpytime(const struct rule *rp, zic_t wantedy)
wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT;
while (wantedy != y) {
i = len_years[isleap(y)];
i = year_days(y);
dayoff = oadd(dayoff, i);
y++;
}