summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile20
-rw-r--r--NEWS113
-rw-r--r--asctime.c12
-rw-r--r--date.14
-rw-r--r--date.1.txt2
-rw-r--r--localtime.c68
-rw-r--r--theory.html38
-rw-r--r--time2posix.39
-rw-r--r--time2posix.3.txt13
-rw-r--r--tz-link.html64
-rw-r--r--tzfile.h6
-rw-r--r--version2
-rw-r--r--zic.832
-rw-r--r--zic.8.txt20
-rw-r--r--zic.c70
15 files changed, 250 insertions, 223 deletions
diff --git a/Makefile b/Makefile
index 96a7462e9a28..06b758eff234 100644
--- a/Makefile
+++ b/Makefile
@@ -129,6 +129,9 @@ TIME_T_ALTERNATIVES_TAIL = int_least32_t.ck uint_least32_t.ck \
# What kind of TZif data files to generate. (TZif is the binary time
# zone data format that zic generates; see Internet RFC 9636.)
+# Although TZif files with leap second info are rarely used and the last
+# leap second was in 2016, they are still supported for compatibility
+# with historical timestamps generated via TZif files with leap seconds.
# If you want only POSIX time, with time values interpreted as
# seconds since the epoch (not counting leap seconds), use
# REDO= posix_only
@@ -151,14 +154,17 @@ TIME_T_ALTERNATIVES_TAIL = int_least32_t.ck uint_least32_t.ck \
REDO= posix_only
# Whether to put an "Expires" line in the leapseconds file.
-# Use EXPIRES_LINE=1 to put the line in, 0 to omit it.
-# The EXPIRES_LINE value matters only if REDO's value contains "right".
+# Use EXPIRES_LINE=1 to put the "Expires" line in, 0 to omit it.
+# This variable is obsolescent and should be removed in a future release.
+# It defaults to 0 because the circa 2020 effort to support it
+# became obsolete after the 2026 decision to discontinue leap seconds.
+# The EXPIRES_LINE value does not affect the contents of TZif files;
+# it affects only the leapseconds file itself, so it matters only if
+# the leapseconds file is used directly by third-party software.
# If you change EXPIRES_LINE, remove the leapseconds file before running "make".
# zic's support for the Expires line was introduced in tzdb 2020a,
-# and was modified in tzdb 2021b to generate version 4 TZif files.
-# EXPIRES_LINE defaults to 0 for now so that the leapseconds file
-# can be given to pre-2020a zic implementations and so that TZif files
-# built by newer zic implementations can be read by pre-2021b libraries.
+# was modified in tzdb 2021b to generate version 4 TZif files,
+# and was removed after tzdb 2026e was released.
EXPIRES_LINE= 0
# To install data in text form that has all the information of the TZif data,
@@ -317,6 +323,8 @@ LDLIBS=
# It also costs CPU time and memory.
# -Dtime_tz=\"T\" to use T as the time_t type, rather than the system time_t
# This is intended for internal use only; it mangles external names.
+# -DMIN_TRANSITION_GAP=N to reject TZif files containing transitions
+# separated by fewer than N seconds. See localtime.c.
# -DTZ_CHANGE_INTERVAL=N if functions depending on TZ should check
# no more often than every N seconds for TZif file changes.
# If N is negative (the default), no such checking is done.
diff --git a/NEWS b/NEWS
index fe2d7c62b624..7a05dc32ebe6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,66 @@
News for the tz database
+Release 2026f - 2026-10-27 23:16:49 -0700
+
+ Briefly:
+ Cuba will not fall back 2026-11-01; stays on -04 through 2027-11-07.
+ No more leap seconds, and leap second tables no longer expire.
+ Improve 1965/1966 data for Brazil.
+
+ Changes to future timestamps
+
+ Cuba will not fall back to -05 on 2026-11-01 and instead plans to
+ maintain -04 through 2027-11-07.
+
+ Changes to past timestamps
+
+ In 1965 Brazil ended DST on 03-31 at 24:00 not 00:00, and in 1966
+ it ended DST on 03-01 at 01:00 not 00:00. (Thanks to Daniel Dias
+ Rodrigues.)
+
+ Changes to code
+
+ zic now ignores Expires lines, as leap second tables in TZif files
+ no longer expire now that there are no more leap seconds;
+ see Internet RFC 9636 §3.2. (Thanks to Garrett Wollman for the
+ heads-up re no more leap seconds.)
+
+ localtime.c no longer supports 49 leap seconds, as 27 now suffice.
+ zic now warns if you go over the new limit.
+
+ A new compile-time flag -DMIN_TRANSITION_GAP=N specifies a minimum
+ transition gap of N seconds when reading TZif files. It currently
+ defaults to 0, but can be set to 1 if TZif files generated by zic
+ 2021b and earlier are no longer of concern.
+
+ With 32-bit time_t, localtime.c functions now check for transition
+ ordering in TZif data as carefully as they do with 64-bit time_t.
+ (Problem reported by Ana Bobillo.)
+
+ On platforms like FreeBSD that have O_RESOLVE_BENEATH but lack
+ O_REGULAR, localtime.c compiled with -DOPENAT_TZDIR now checks
+ that a TZ setting with ".." components names a regular file
+ before opening it in an unprivileged program, as it already did
+ for other settings that might name a file outside TZDIR.
+ This fixes a bug introduced in 2026c. (Thanks to Ana Bobillo.)
+
+ Changes to documentation and commentary
+
+ Documentation and commentary now reflect leap seconds’ demise.
+
+ Changes to commentary
+
+ Discussion on timekeeping in northwestern Ontario has been updated
+ to reflect that provincial regulation has been issued to allow these
+ areas to stay aligned with America/Winnipeg and follow Manitoba’s
+ adoption of year-round -05 after all. (Thanks to Aoun Khan,
+ Chris Walton, and Heitor David Pinto.)
+
+ Discussion on timekeeping in Saskatchewan has been updated to
+ document its new Time Act, 2026 which comes into force on
+ 2026-10-30. (Thanks to Heitor David Pinto.) No change is expected.
+
+
Release 2026e - 2026-09-29 17:14:38 -0700
Briefly:
@@ -12,7 +73,10 @@ Release 2026e - 2026-09-29 17:14:38 -0700
its traditional abbreviation EST. Although the change to
permanent -05 legally takes place on 2026-10-31, 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
+ other recent temporary hacks. This new temporary hack works
+ around a limitation in Unicode CLDR 48.2.2 (2026-09-21)
+ and ICU 78.3 (2026-03-17), and is planned to be removed after
+ CLDR and ICU are fixed. (Caution: see “NOTE FOR 2026
TEMPORARY HACK FOR CLDR AND CANADA” below.)
As the change affects both America/Winnipeg and its backward
@@ -22,7 +86,7 @@ Release 2026e - 2026-09-29 17:14:38 -0700
Another TZDB release may be needed soon if any of the portions of
northwestern Ontario historically aligned with America/Winnipeg do
- not follow. For now, given the short leadtime with Manitoba’s
+ not follow. For now, given the short lead time with Manitoba’s
announcement, assume that they will, to avoid creating new zones
that may not be needed if no divergence occurs.
@@ -52,8 +116,11 @@ Release 2026d - 2026-09-11 15:21:07 -0700
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.)
+ for the same reason as other recent temporary hacks.
+ This new temporary hack works around a limitation in Unicode CLDR
+ 48.2.1 (2026-07-08) and and ICU 78.3 (2026-03-17), and is planned
+ to be removed after CLDR and ICU are fixed. (Caution:
+ see “NOTE FOR 2026 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.
@@ -135,8 +202,11 @@ 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. (Caution: see
- “NOTE FOR 2026b TEMPORARY HACK FOR CLDR AND CANADA” below.)
+ temporary hack for British Columbia in 2026b. This new temporary
+ hack works around a limitation in Unicode CLDR 48.1 (2026-01-08)
+ and ICU 78.2 (2025-01-30), and is planned to be removed after CLDR
+ and ICU are fixed. (Caution: see “NOTE FOR 2026 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"
@@ -202,9 +272,10 @@ Release 2026b - 2026-04-22 23:06:43 -0700
foreseeable clock change, as it moved to permanent -07 thereafter.
(Thanks to Arthur David Olson.) Although the change to permanent
-07 legally took place on 2026-03-09, temporarily model the change
- to occur on 2026-11-01 at 02:00 instead. This works around a
- limitation in CLDR 48.1 (2026-01-08). This temporary hack is
- planned to be removed after CLDR is fixed.
+ to occur on 2026-11-01 at 02:00 instead. This temporary hack
+ works around a limitation in Unicode CLDR 48 (2025-10-29) and
+ ICU 78 (2025-10-30), and is planned to be removed after CLDR and
+ ICU are fixed.
To match longstanding practice for -07 standard time in North
America, such as for America/Dawson, America/Dawson_Creek,
@@ -217,15 +288,15 @@ Release 2026b - 2026-04-22 23:06:43 -0700
observing -07, and may change it to "-07" if no alphabetic
consensus emerges.
- Changes to code
+ NOTE FOR 2026 TEMPORARY HACK FOR CLDR AND CANADA:
- 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.
+ This temporary hack works around limitations in Unicode CLDR and
+ ICU, and is planned to be removed after CLDR and ICU are fixed.
+ See <https://cldr.unicode.org/downloads/cldr-48> and
+ <https://www.unicode.org/releases/> for 2026 changes there.
+ Unfortunately the temporary hack also causes zic in tzcode
+ 2023d through 2026a, in the default slim mode, to generate a
+ TZif file that does not conform to 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
@@ -234,6 +305,10 @@ Release 2026b - 2026-04-22 23:06:43 -0700
data from more-recent tz releases. To work around this problem
when using these older zic versions, use ‘zic -b fat’.
+ Changes to code
+
+ zic no longer mishandles a last transition to a new time type.
+
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",
which can occur with adversarial input. (Thanks to Naveed Khan.)
@@ -5318,9 +5393,9 @@ Release 2012a - 2012-03-01 18:28:10 +0700
foreseeable future, though 2012 is all we're fairly certain of.)
Armenia has abolished Summer Time.
Tokelau jumped the International Date Line back last December
- (just the same as their near neighbour, Samoa).
+ (just the same as their near neighbor, Samoa).
America/Creston is a new zone for a small area of British Columbia
- There will be a leapsecond 2012-06-30 23:59:60 UTC.
+ There will be a leap second 2012-06-30 23:59:60 UTC.
Other minor changes are:
Corrections to 1918 Canadian summer time end dates.
diff --git a/asctime.c b/asctime.c
index 696bb97a57f7..f9ca75d063d6 100644
--- a/asctime.c
+++ b/asctime.c
@@ -76,8 +76,9 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf)
register const char * mn;
int year, mday, hour, min, sec;
long long_TM_YEAR_BASE = TM_YEAR_BASE;
- int bufsize = (buf == buf_asctime
- ? sizeof buf_asctime : STD_ASCTIME_BUF_SIZE);
+ int buflen;
+ size_t bufsize = (buf == buf_asctime
+ ? sizeof buf_asctime : STD_ASCTIME_BUF_SIZE);
if (timeptr == NULL) {
strcpy(buf, "??? ??? ?? ??:??:?? ????\n");
@@ -112,7 +113,8 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf)
Also, avoid overflow when formatting tm_year + TM_YEAR_BASE. */
- if ((year <= LONG_MAX - TM_YEAR_BASE
+ buflen
+ = (year <= LONG_MAX - TM_YEAR_BASE
? snprintf (buf, bufsize,
((-999 - TM_YEAR_BASE <= year
&& year <= 9999 - TM_YEAR_BASE)
@@ -124,8 +126,8 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf)
"%s %s%3d %.2d:%.2d:%.2d %d%d\n",
wn, mn, mday, hour, min, sec,
year / 10 + TM_YEAR_BASE / 10,
- year % 10))
- < bufsize)
+ year % 10));
+ if (0 <= buflen && buflen < bufsize)
return buf;
else {
errno = EOVERFLOW;
diff --git a/date.1 b/date.1
index 8f2c212b2cf3..a9d50d9344fb 100644
--- a/date.1
+++ b/date.1
@@ -18,6 +18,8 @@ date \- show and set date and time
\fR[\fIyyyy\fR]\fImmddhhmm\fR[\fIyy\fR][\fB.\fIss\fR]
]
.SH DESCRIPTION
+.ie '\(en'' .ds en \-
+.el .ds en \(en
.ie '\(lq'' .ds lq \&"\"
.el .ds lq \(lq\"
.ie '\(rq'' .ds rq \&"\"
@@ -77,6 +79,6 @@ hexadecimal (leading 0x), preceded by an optional sign.
.br
/usr/share/zoneinfo timezone directory
.br
-/usr/share/zoneinfo/Etc/UTC for UTC leap seconds, if supported
+/usr/share/zoneinfo/Etc/UTC for leap seconds (1972\*(en2016), if supported
.SH SEE ALSO
.BR strftime (3).
diff --git a/date.1.txt b/date.1.txt
index a2e52c035214..74bb63f03562 100644
--- a/date.1.txt
+++ b/date.1.txt
@@ -37,7 +37,7 @@ FILES
/etc/localtime local timezone file
/usr/lib/locale/L/LC_TIME description of time locale L
/usr/share/zoneinfo timezone directory
- /usr/share/zoneinfo/Etc/UTC for UTC leap seconds, if supported
+ /usr/share/zoneinfo/Etc/UTC for leap seconds (1972–2016), if supported
SEE ALSO
strftime(3).
diff --git a/localtime.c b/localtime.c
index 29a70eb48b50..2a10dcb3a1af 100644
--- a/localtime.c
+++ b/localtime.c
@@ -443,6 +443,16 @@ static char const *utc = etc_utc + sizeof "Etc/" - 1;
# define SUPPRESS_TZDIR 0
#endif
+/* Minimum separation in seconds between adjacent transition times,
+ as a nonnegative signed integer. RFC 9636 says it must be at most 1.
+ Currently it defaults to 0, to accept nonconforming
+ TZif files containing multiple transitions at the same time,
+ such as TZif files generated by bugs in zic 2021b and earlier.
+ It can default to 1 once the old zic versions are no longer of concern. */
+#ifndef MIN_TRANSITION_GAP
+# define MIN_TRANSITION_GAP 0
+#endif
+
/* Limit to time zone abbreviation length in proleptic TZ strings.
This is distinct from TZ_MAX_CHARS, which limits TZif file contents.
It defaults to 254, not 255, so that desigidx_type can be an unsigned char.
@@ -962,21 +972,21 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
}
if (relname[0] != '/') {
- if (!OPENAT_TZDIR || !O_RESOLVE_BENEATH) {
- /* Fail if a relative name contains a non-terminal ".." component,
- as such a name could read a non-directory outside TZDIR
- when AT_FDCWD and O_RESOLVE_BENEATH are not available. */
- char const *component;
- for (component = relname; component[0]; component++)
- if (component[0] == '.' && component[1] == '.'
- && component[2] == '/'
- && (component == relname || component[-1] == '/')) {
- if (issetugid())
- return ENOTCAPABLE;
- might_escape = true;
- break;
- }
- }
+ /* Set might_escape if a relative name contains a non-terminal
+ ".." component, as such a name could read a non-directory
+ outside TZDIR. If privileged, fail unless openat with
+ O_RESOLVE_BENEATH will confine the lookup to TZDIR. */
+ char const *component;
+ for (component = relname; component[0]; component++)
+ if (component[0] == '.' && component[1] == '.'
+ && component[2] == '/'
+ && (component == relname || component[-1] == '/')) {
+ if (! (OPENAT_TZDIR && !SUPPRESS_TZDIR && O_RESOLVE_BENEATH)
+ && issetugid())
+ return ENOTCAPABLE;
+ might_escape = true;
+ break;
+ }
if (OPENAT_TZDIR && !SUPPRESS_TZDIR) {
/* Prefer O_SEARCH or O_PATH if available;
@@ -1108,6 +1118,7 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
else {
int_fast64_t prevtr = -1;
int_fast32_2s prevcorr;
+ int_fast64_t atmin = INT_FAST64_MIN;
set_leapcount(sp, leapcnt);
sp->timecnt = timecnt;
sp->typecnt = typecnt;
@@ -1120,14 +1131,30 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
for (i = 0; i < sp->timecnt; ++i) {
int_fast64_t at
= stored == 4 ? detzcode(p) : detzcode64(p);
+ if (at < atmin)
+ return EFTYPE;
+ else {
+#ifdef ckd_add
+ bool v = ckd_add(&atmin, at, MIN_TRANSITION_GAP);
+#else
+ bool v = INT_FAST64_MAX - MIN_TRANSITION_GAP < at;
+ if (!v)
+ atmin = at + MIN_TRANSITION_GAP;
+#endif
+ /* If the next minimum value for 'at' overflows,
+ any new 'at' value is less than what it
+ should be, so fail if such a value exists. */
+ if (v && i + 1 < sp->timecnt)
+ return EFTYPE;
+ }
+
sp->types[i] = at <= TIME_T_MAX;
if (sp->types[i]) {
time_t attime
= ((TYPE_SIGNED(time_t) ? at < TIME_T_MIN : at < 0)
? TIME_T_MIN : at);
- if (timecnt && attime <= sp->ats[timecnt - 1]) {
- if (attime < sp->ats[timecnt - 1])
- return EFTYPE;
+ if (!MIN_TRANSITION_GAP && timecnt
+ && sp->ats[timecnt - 1] == attime) {
sp->types[i - 1] = 0;
timecnt--;
}
@@ -1139,10 +1166,11 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
timecnt = 0;
for (i = 0; i < sp->timecnt; ++i) {
unsigned char typ = *p++;
+ unsigned char kepttype = sp->types[i];
if (sp->typecnt <= typ)
return EFTYPE;
- if (sp->types[i])
- sp->types[timecnt++] = typ;
+ sp->types[timecnt] = typ;
+ timecnt += kepttype;
}
sp->timecnt = timecnt;
for (i = 0; i < sp->typecnt; ++i) {
diff --git a/theory.html b/theory.html
index 84c6b8df8a71..3d322b314291 100644
--- a/theory.html
+++ b/theory.html
@@ -838,12 +838,12 @@ href="https://dissentmagazine.org/online_articles/booked-a-global-history-of-tim
The relationship between POSIX time (that is, <abbr>UTC</abbr> but
ignoring <a href="https://en.wikipedia.org/wiki/Leap_second">leap
seconds</a>) and <abbr>UTC</abbr> is not agreed upon.
- This affects time stamps during the leap second era (1972–2035).
+ This affects time stamps during the leap second era (1972–2016).
Although the POSIX
- clock officially stops during an inserted leap second, at least one
- proposed standard has it jumping back a second instead; and in
- practice POSIX clocks more typically either progress glacially during
- a leap second, or are slightly slowed while near a leap second.
+ clock officially stopped during an inserted leap second,
+ at least one proposed standard had it jumping back a second instead;
+ and in practice POSIX clocks more typically either progressed glacially
+ during a leap second, or were slightly slowed while near a leap second.
</li>
<li>
The <code><abbr>tz</abbr></code> database does not represent how
@@ -1347,35 +1347,33 @@ between now and the future time.
<p>
Leap seconds were introduced in 1972 to accommodate the
difference between atomic time and the less regular rotation of the earth.
-Unfortunately they have caused so many problems with civil
-timekeeping that there are
-<a href="https://www.bipm.org/en/cgpm-2022/resolution-4">plans
-to discontinue them by 2035</a>.
-Even if these plans come to fruition, a record of leap seconds will still be
-needed to resolve timestamps from 1972 through 2035,
-and there may also be a need to record whatever mechanism replaces them.
+Unfortunately they caused so many problems with civil
+timekeeping that the last leap second was in 2016.
+A record of leap seconds is still
+needed to resolve timestamps from 1972 through 2016,
+and there may also be a need to record whatever mechanism replaces them
+in the likely-distant future.
</p>
<p>
The <code><abbr>tz</abbr></code> code and data can account for leap seconds,
thanks to code contributed by Bradley White.
-However, the leap second support of this package is rarely used directly
+However, the leap second support of this package's code was rarely used
+even before leap seconds were discontinued,
because POSIX requires leap seconds to be excluded and many
software packages would mishandle leap seconds if they were present.
-Instead, leap seconds are more commonly handled by occasionally adjusting
+Instead, leap seconds were more commonly handled by occasionally adjusting
the operating system kernel clock as described in
-<a href="tz-link.html#precision">Precision timekeeping</a>,
+<a href="tz-link.html#leaps">Leap seconds</a>,
and this package by default installs a <samp>leapseconds</samp> file
commonly used by
<a href="https://www.ntp.org"><abbr title="Network Time Protocol">NTP</abbr></a>
-software that adjusts the kernel clock.
-However, kernel-clock twiddling approximates UTC only roughly,
-and systems needing more precise UTC can use this package’s leap
-second support directly.
+software that adjusted the kernel clock.
</p>
<p>
-The directly supported mechanism assumes that <code>time_t</code>
+In the rare case where this package's code is configured to support
+leap seconds, it assumes that <code>time_t</code>
counts of seconds since the POSIX epoch normally include leap seconds,
as opposed to POSIX <code>time_t</code> counts which exclude leap seconds.
This modified timescale is converted to <abbr>UTC</abbr>
diff --git a/time2posix.3 b/time2posix.3
index f76915b14456..5c56a407a1f1 100644
--- a/time2posix.3
+++ b/time2posix.3
@@ -27,15 +27,15 @@ IEEE Standard 1003.1
(POSIX)
says that
.B time_t
-values cannot count leap
+values do not count leap
seconds and,
therefore,
-that the system time must be adjusted as each leap occurs.
+that the system time was adjusted as each leap occurred.
.PP
If the time package is configured with leap-second support
enabled,
however,
-no such adjustment is needed and
+no such adjustment was needed and
.B time_t
values continue to increase over leap events
(as a true
@@ -120,7 +120,8 @@ DATE TIME T X Y
.in
.fi
.PP
-A leap second deletion would look like the following, and
+No leap second deletion ever occurred.
+However, if one had occurred it would have looked like the following, and
posix2time(B+1) would return either A or A+1.
.PP
.in +2
diff --git a/time2posix.3.txt b/time2posix.3.txt
index 57556b8789dc..0a9e9f082ca1 100644
--- a/time2posix.3.txt
+++ b/time2posix.3.txt
@@ -13,12 +13,12 @@ SYNOPSIS
cc ... -ltz
DESCRIPTION
- IEEE Standard 1003.1 (POSIX) says that time_t values cannot count leap
- seconds and, therefore, that the system time must be adjusted as each
- leap occurs.
+ IEEE Standard 1003.1 (POSIX) says that time_t values do not count leap
+ seconds and, therefore, that the system time was adjusted as each leap
+ occurred.
If the time package is configured with leap-second support enabled,
- however, no such adjustment is needed and time_t values continue to
+ however, no such adjustment was needed and time_t values continue to
increase over leap events (as a true “seconds since...” value). This
means that these values will differ from those required by POSIX by the
net number of leap seconds inserted since the Epoch.
@@ -58,8 +58,9 @@ DESCRIPTION
1993-07-01 00:00:00 A+2 B+1 A+1 or A+2
1993-07-01 00:00:01 A+3 B+2 A+3
- A leap second deletion would look like the following, and
- posix2time(B+1) would return either A or A+1.
+ No leap second deletion ever occurred. However, if one had occurred it
+ would have looked like the following, and posix2time(B+1) would return
+ either A or A+1.
DATE TIME T X Y
????-06-30 23:59:58 A B A
diff --git a/tz-link.html b/tz-link.html
index 8f836909d7e8..80e1aaf72e09 100644
--- a/tz-link.html
+++ b/tz-link.html
@@ -1074,6 +1074,18 @@ href="https://www.giss.nasa.gov/tools/mars24/help/notes.html">Mars24 Sunclock
– Time on Mars</a> describes Airy Mean Time (<abbr>AMT</abbr>) and the
diverse local time
scales used by each landed mission on Mars.</li>
+</ul>
+
+<h3 id="leaps">Leap seconds</h3>
+<p>Leap seconds were introduced to adjust UTC on occasion
+so that it agreed more closely with UT1, astronomical time.
+There were 27 leap seconds,
+ranging from 1972-06-30 23:59:60 through 2016-12-31 23:59:60 UTC.
+The leap second approach was discontinued in 2026 due to difficulties
+in implementing their use, and the current plan is to address the
+disagreement between UTC and UT1 in a different way,
+probably decades or centuries from now.</p>
+<ul>
<li><a href="http://leapsecond.com">LeapSecond.com</a> is
dedicated not only to leap seconds but to precise time and frequency
in general. It covers the state of the art in amateur timekeeping, and
@@ -1086,11 +1098,11 @@ Radiocommunication Sector (ITU-R) Recommendation TF.460-6 (02/2002).</li>
href="https://www.iers.org/IERS/EN/Publications/Bulletins/bulletins.html"><abbr
title="International Earth Rotation and Reference Systems Service">IERS</abbr>
Bulletins</a> contains official publications of the International
-Earth Rotation and Reference Systems Service, which decides when leap
-seconds occur.
+Earth Rotation and Reference Systems Service, which decided when leap
+seconds occurred.
The <code><abbr>tz</abbr></code> code and data support leap seconds
via an optional <code>"right"</code> configuration where a computer’s internal
-<code>time_t</code> integer clock counts every <abbr>TAI</abbr> second,
+<code>time_t</code> integer clock counted every <abbr>TAI</abbr> second,
as opposed to the default <code>"posix"</code> configuration
where the internal clock ignores leap seconds.
The two configurations agree for timestamps starting with 1972-01-01 00:00:00
@@ -1106,7 +1118,7 @@ neither <abbr>UTC</abbr> nor <abbr>TAI</abbr>
is well-defined for sufficiently old timestamps.</li>
<li><a href="https://kb.meinbergglobal.com/kb/time_sync/ntp/configuration/ntp_leap_second_file">The
<abbr>NTP</abbr> Leap Second File</a> covers the text file
-<code>leap-seconds.list</code>, which lists the currently known leap seconds.
+<code>leap-seconds.list</code>, which lists the historical leap seconds.
The <abbr>IERS</abbr> maintains this file, and a copy is distributed by
<code><abbr>tzdb</abbr></code> for use by <abbr>NTP</abbr> implementations like
<a href="https://www.ntp.org">classic
@@ -1119,16 +1131,16 @@ example, <code>right/UTC</code> can be used
by <a href="https://chrony-project.org"><code>chrony</code></a>,
another <abbr>NTP</abbr> implementation.</li>
<li><a href="https://developers.google.com/time/smear">Leap Smear</a>
-discusses how to gradually adjust <abbr>POSIX</abbr> clocks near a
-leap second so that they disagree with <abbr>UTC</abbr> by at most a
+discusses how systems gradually adjusted <abbr>POSIX</abbr> clocks near a
+leap second so that they disagreed with <abbr>UTC</abbr> by at most a
half second, even though every <abbr>POSIX</abbr> minute has exactly
sixty seconds. This approach works with the default <code><abbr>tz</abbr></code>
<code>"posix"</code> configuration, is <a
href="https://gitlab.com/NTPsec/ntpsec/-/blob/master/docs/leapsmear.adoc">supported</a>
by the <abbr>NTP</abbr> implementations mentioned above, <a
href="https://github.com/google/unsmear">supports</a> conversion between
-<abbr>UTC</abbr> and smeared <abbr>POSIX</abbr> timestamps, and is used by major
-cloud service providers. However, according to
+<abbr>UTC</abbr> and smeared <abbr>POSIX</abbr> timestamps,
+and was used by major cloud service providers. However, according to
<a href="https://www.rfc-editor.org/info/rfc8633#section-3.7.1">§3.7.1 of
Network Time Protocol Best Current Practices</a>
(Internet <abbr>RFC</abbr> 8633), leap smearing is not suitable for
@@ -1140,38 +1152,12 @@ href="https://gge.ext.unb.ca/Resources/gpsworld.november99.pdf">McCarthy
and Klepczynski’s 1999 proposal to discontinue leap seconds</a>,
discussed further in
<a href="https://www.cl.cam.ac.uk/~mgk25/time/metrologia-leapsecond.pdf">The
-leap second: its history and possible future</a>.
+leap second: its history and possible future</a> and in
<a href="https://www.ucolick.org/~sla/leapsecs/"><abbr>UTC</abbr>
-might be redefined
-without Leap Seconds</a> gives pointers on this
-contentious issue.
-The General Conference on Weights and Measures (CGPM)
-<a href="https://www.bipm.org/en/cgpm-2022/resolution-4">decided in 2022</a>
-to discontinue the use of leap seconds by 2035, and requested that no
-discontinuous adjustments be made to UTC for at least a century.
-The World Radiocommunication Conference <a
-href="https://www.itu.int/dms_pub/itu-r/opb/act/R-ACT-WRC.15-2023-PDF-E.pdf">resolved
-in 2023</a> to cooperate with this process. A draft <a
-href="https://www.bipm.org/documents/d/guest/cgpm-2026-draft-resolutions">Resolution
-C to make continuous UTC effective on 2027-05-20</a>,
-and thereby discontinue leap seconds,
-has been scheduled for the 28th CGPM starting 2026-10-13 in Paris.
-One proposal to implement this
-would replace leap seconds with seven 13-second leap smears occurring once per
-decade until 2100, with leap smears after that gradually increasing in size.
-See:
-<ul>
-<li>Levine J. <a href="https://tf.nist.gov/general/pdf/3242.pdf">A
-proposal to change the leap-second adjustments to
-coordinated universal time</a>. <em>Metrologia.</em> 2024;61(5):055002. doi:<a
-href="https://doi.org/10.1088/1681-7575/ad6266">10.1088/1681-7575/ad6266</a>
-with followups in doi:<a
-href="https://doi.org/10.1088/1681-7575/ade314">10.1088/1681-7575/ade314</a>
-and doi:<a
-href="https://doi.org/10.1088/1681-7575/ade315">10.1088/1681-7575/ade315</a>.</li>
-</ul>
-However, there is still no consensus on whether this is the best way
-to replace leap seconds.
+might be redefined without Leap Seconds</a>.
+In 2026 the General Conference on Weights and Measures (CGPM)
+<a href="https://www.bipm.org/en/cgpm-2026/resolution-5">resolved</a>
+to discontinue the use of leap seconds.
</li>
</ul>
diff --git a/tzfile.h b/tzfile.h
index 1941bc3b7693..8a53330e1fe9 100644
--- a/tzfile.h
+++ b/tzfile.h
@@ -107,9 +107,9 @@ struct tzhead {
#ifndef TZ_MAX_LEAPS
/* The following limit applies to localtime.c; zic has no such limit.
- The limit must be at least 27 for leap seconds from 1972 through mid-2023.
- There's a plan to discontinue leap seconds by 2035. */
-# define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+ It must be at least 27 for all 27 historical leap seconds (1972-2016),
+ plus 1 for leap second table expiry as per TZif version 4. */
+# define TZ_MAX_LEAPS (27 + 1) /* Maximum number of leap second corrections */
#endif /* !defined TZ_MAX_LEAPS */
#endif /* !defined TZFILE_H */
diff --git a/version b/version
index 2c2d640a0f1c..3a0e3555219a 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-2026e
+2026f
diff --git a/zic.8 b/zic.8
index fcdbb6736dd6..15937e1e9018 100644
--- a/zic.8
+++ b/zic.8
@@ -291,10 +291,9 @@ The output contains a truncated leap second table,
which can cause some older TZif readers to misbehave.
This can occur if the
.B "\-L"
-option is used, and either an Expires line is present or
-the
+and
.B "\-r"
-option is also used.
+options are both used.
.PP
The output file contains more than 1200 transitions,
which may be mishandled by some clients.
@@ -796,8 +795,7 @@ lines may appear in any order in the input.
However, the behavior is unspecified if multiple zone or link lines
define the same name.
.PP
-The file that describes leap seconds can have leap lines and an
-expiration line.
+The file that describes leap seconds can have leap lines.
Leap lines have the following form:
.nf
.ti +2
@@ -852,26 +850,10 @@ However, rolling leap seconds are not supported if the
.B \-r
option is used.
.PP
-The expiration line, if present, has the form:
-.nf
-.ti +2
-.ta \w'Expires\0\0'u +\w'YEAR\0\0'u +\w'MONTH\0\0'u +\w'DAY\0\0'u
-.sp
-Expires YEAR MONTH DAY HH:MM:SS
-.sp
-For example:
-.ti +2
-.sp
-Expires 2020 Dec 28 00:00:00
-.sp
-.fi
-The
-.BR YEAR ,
-.BR MONTH ,
-.BR DAY ,
-and
-.B HH:MM:SS
-fields give the expiration timestamp in UTC for the leap second table.
+Any expiration line is ignored, as the last leap second was in 2016
+and there is no longer any reason for leap second tables to expire.
+The ignored expiration line, if present, begins with the word
+.q "Expires" .
.br
.ne 22
.SH "EXTENDED EXAMPLE"
diff --git a/zic.8.txt b/zic.8.txt
index 945a810dcb50..c9f458feaa3a 100644
--- a/zic.8.txt
+++ b/zic.8.txt
@@ -162,8 +162,7 @@ OPTIONS
The output contains a truncated leap second table, which can
cause some older TZif readers to misbehave. This can occur if
- the -L option is used, and either an Expires line is present or
- the -r option is also used.
+ the -L and -r options are both used.
The output file contains more than 1200 transitions, which may
be mishandled by some clients. The current reference client
@@ -443,8 +442,8 @@ FILES
input. However, the behavior is unspecified if multiple zone or link
lines define the same name.
- The file that describes leap seconds can have leap lines and an
- expiration line. Leap lines have the following form:
+ The file that describes leap seconds can have leap lines. Leap lines
+ have the following form:
Leap YEAR MONTH DAY HH:MM:SS CORR R/S
@@ -469,16 +468,9 @@ FILES
local broadcast day. However, rolling leap seconds are not supported
if the -r option is used.
- The expiration line, if present, has the form:
-
- Expires YEAR MONTH DAY HH:MM:SS
-
- For example:
-
- Expires 2020 Dec 28 00:00:00
-
- The YEAR, MONTH, DAY, and HH:MM:SS fields give the expiration timestamp
- in UTC for the leap second table.
+ Any expiration line is ignored, as the last leap second was in 2016 and
+ there is no longer any reason for leap second tables to expire. The
+ ignored expiration line, if present, begins with the word “Expires”.
EXTENDED EXAMPLE
Here is an extended example of zic input, intended to illustrate many
diff --git a/zic.c b/zic.c
index 6e18893af095..cd0dcac2e1bf 100644
--- a/zic.c
+++ b/zic.c
@@ -263,7 +263,6 @@ static void check_for_signal(void);
static void dolink(const char *, const char *, bool);
static int getfields(char *, char **, int);
static zic_t getsave(char *, bool *);
-static void inexpires(char **, int);
static void infile(int, char const *);
static void inleap(char ** fields, int nfields);
static void inlink(char ** fields, int nfields);
@@ -408,7 +407,7 @@ enum {
LP_ROLL,
LEAP_FIELDS,
- /* Expires lines are like Leap lines, except without CORR and ROLL fields. */
+ /* Expires lines were like Leap lines, but without CORR and ROLL fields. */
EXPIRES_FIELDS = LP_TIME + 1
};
@@ -1155,9 +1154,6 @@ static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
or lo_time, whichever is greater. */
static zic_t redundant_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
-/* The time specified by an Expires line, or negative if no such line. */
-static zic_t leapexpires = -1;
-
/* Set the time range of the output to TIMERANGE.
Return true if successful. */
static bool
@@ -2061,7 +2057,7 @@ infile(int fnum, char const *name)
wantcont = false;
break;
case LC_EXPIRES:
- inexpires(fields, nfields);
+ warning(N_("Expires line ignored"));
wantcont = false;
break;
default: unreachable();
@@ -2321,7 +2317,7 @@ inzsub(char **fields, int nfields, bool iscont)
}
static zic_t
-getleapdatetime(char **fields, bool expire_line)
+getleapdatetime(char **fields)
{
register const struct lookup * lp;
zic_t year;
@@ -2336,13 +2332,11 @@ getleapdatetime(char **fields, bool expire_line)
error(N_("invalid leaping year"));
return -1;
}
- if (!expire_line) {
- if (!leapseen || leapmaxyear < year)
+ if (!leapseen || leapmaxyear < year)
leapmaxyear = year;
- if (!leapseen || leapminyear > year)
+ if (!leapseen || leapminyear > year)
leapminyear = year;
- leapseen = true;
- }
+ leapseen = true;
if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
error(N_("invalid month name"));
return -1;
@@ -2368,7 +2362,7 @@ inleap(char **fields, int nfields)
if (nfields != LEAP_FIELDS)
error(N_("wrong number of fields on Leap line"));
else {
- zic_t t = getleapdatetime(fields, false);
+ zic_t t = getleapdatetime(fields);
if (0 <= t) {
struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
if (!lp)
@@ -2389,17 +2383,6 @@ inleap(char **fields, int nfields)
}
static void
-inexpires(char **fields, int nfields)
-{
- if (nfields != EXPIRES_FIELDS)
- error(N_("wrong number of fields on Expires line"));
- else if (0 <= leapexpires)
- error(N_("multiple Expires lines"));
- else
- leapexpires = getleapdatetime(fields, true);
-}
-
-static void
inlink(char **fields, int nfields)
{
struct link l;
@@ -2617,7 +2600,6 @@ struct timerange {
int defaulttype;
ptrdiff_t base, count;
ptrdiff_t leapbase, leapcount;
- bool leapexpiry;
};
static struct timerange
@@ -2656,9 +2638,6 @@ limitrange(struct timerange r, zic_t lo, zic_t hi,
r.leapcount--;
}
- /* Determine whether to append an expiration to the leap second table. */
- r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi;
-
return r;
}
@@ -2774,20 +2753,12 @@ writezone(const char *const name, const char *const string, char version,
ats, types);
range32 = limitrange(range64, ZIC32_MIN, ZIC32_MAX, ats, types);
- /* TZif version 4 is needed if a no-op transition is appended to
- indicate the expiration of the leap second table, or if the first
+ /* TZif version 4 is needed if the first
leap second transition is not to a +1 or -1 correction. */
for (pass = 1; pass <= 2; pass++) {
struct timerange const *r = pass == 1 ? &range32 : &range64;
if (pass == 1 && !want_bloat())
continue;
- if (r->leapexpiry) {
- if (noise)
- warning(N_("%s: pre-2021b clients may mishandle"
- " leap second expiry"),
- name);
- version = '4';
- }
if (0 < r->leapcount
&& leap[r->leapbase].corr != 1 && leap[r->leapbase].corr != -1) {
if (noise)
@@ -2807,7 +2778,7 @@ writezone(const char *const name, const char *const string, char version,
register ptrdiff_t thisleapi, thisleapcnt, thisleaplim;
struct tzhead tzh;
int pretranstype = -1, thisdefaulttype;
- bool locut, hicut, thisleapexpiry;
+ bool locut, hicut;
zic_t lo, thismin, thismax;
int old0;
char omittype[TZ_MAX_TYPES];
@@ -2825,7 +2796,6 @@ writezone(const char *const name, const char *const string, char version,
toomanytimes = thistimecnt >> 31 >> 1 != 0;
thisleapi = range32.leapbase;
thisleapcnt = range32.leapcount;
- thisleapexpiry = range32.leapexpiry;
thismin = ZIC32_MIN;
thismax = ZIC32_MAX;
} else {
@@ -2835,7 +2805,6 @@ writezone(const char *const name, const char *const string, char version,
toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
thisleapi = range64.leapbase;
thisleapcnt = range64.leapcount;
- thisleapexpiry = range64.leapexpiry;
thismin = min_time;
thismax = max_time;
}
@@ -2971,7 +2940,7 @@ writezone(const char *const name, const char *const string, char version,
&chars[desigidx[i]]);
if (pass == 1 && !want_bloat()) {
- hicut = thisleapexpiry = false;
+ hicut = false;
pretranstype = -1;
thistimecnt = thisleapcnt = 0;
thistypecnt = thischarcnt = 1;
@@ -2982,7 +2951,7 @@ writezone(const char *const name, const char *const string, char version,
tzh.tzh_version[0] = version;
convert(utcnt, tzh.tzh_ttisutcnt);
convert(stdcnt, tzh.tzh_ttisstdcnt);
- convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt);
+ convert(thisleapcnt, tzh.tzh_leapcnt);
convert((0 <= pretranstype) + thistimecnt + hicut,
tzh.tzh_timecnt);
convert(thistypecnt, tzh.tzh_typecnt);
@@ -3066,15 +3035,6 @@ writezone(const char *const name, const char *const string, char version,
puttzcodepass(todo, fp, pass);
puttzcode(leap[i].corr, fp);
}
- if (thisleapexpiry) {
- /* Append a no-op leap correction indicating when the leap
- second table expires. Although this does not conform to
- Internet RFC 9636, most clients seem to accept this and
- the plan is to amend the RFC to allow this in version 4
- TZif files. */
- puttzcodepass(leapexpires, fp, pass);
- puttzcode(thisleaplim ? leap[thisleaplim - 1].corr : 0, fp);
- }
if (stdcnt != 0)
for (i = old0; i < typecnt; i++)
if (!omittype[i])
@@ -3883,14 +3843,6 @@ adjleap(void)
leap[i].trans = tadd(prevtrans, last);
last = leap[i].corr += last;
}
-
- if (0 <= leapexpires) {
- leapexpires = oadd(leapexpires, last);
- if (! (leapcnt == 0 || (leap[leapcnt - 1].trans < leapexpires))) {
- error(N_("last Leap time does not precede Expires time"));
- exit(EXIT_FAILURE);
- }
- }
}
/* Is A a space character in the C locale? */