diff options
| -rw-r--r-- | Makefile | 20 | ||||
| -rw-r--r-- | NEWS | 113 | ||||
| -rw-r--r-- | asctime.c | 12 | ||||
| -rw-r--r-- | date.1 | 4 | ||||
| -rw-r--r-- | date.1.txt | 2 | ||||
| -rw-r--r-- | localtime.c | 68 | ||||
| -rw-r--r-- | theory.html | 38 | ||||
| -rw-r--r-- | time2posix.3 | 9 | ||||
| -rw-r--r-- | time2posix.3.txt | 13 | ||||
| -rw-r--r-- | tz-link.html | 64 | ||||
| -rw-r--r-- | tzfile.h | 6 | ||||
| -rw-r--r-- | version | 2 | ||||
| -rw-r--r-- | zic.8 | 32 | ||||
| -rw-r--r-- | zic.8.txt | 20 | ||||
| -rw-r--r-- | zic.c | 70 |
15 files changed, 250 insertions, 223 deletions
@@ -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. @@ -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; @@ -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> @@ -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 */ @@ -1 +1 @@ -2026e +2026f @@ -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 @@ -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? */ |
