git: 7ef70d24eee7 - stable/13 - Update tzcode to 2023c.

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Wed, 13 Dec 2023 20:06:21 UTC
The branch stable/13 has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=7ef70d24eee731375fe17a8ef1a30573338d9468

commit 7ef70d24eee731375fe17a8ef1a30573338d9468
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2023-04-26 09:46:18 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2023-12-13 16:11:02 +0000

    Update tzcode to 2023c.
    
    MFC after:      3 weeks
    Sponsored by:   Klara, Inc.
    Reviewed by:    philip
    Differential Revision:  https://reviews.freebsd.org/D39712
    
    (cherry picked from commit 75411d157232ee3b4789b92c9205453e7d59a3d2)
---
 contrib/tzcode/CONTRIBUTING   |   2 +-
 contrib/tzcode/Makefile       |  54 ++++----
 contrib/tzcode/NEWS           | 143 ++++++++++++++++++---
 contrib/tzcode/asctime.c      |  29 ++++-
 contrib/tzcode/date.1         |   5 +-
 contrib/tzcode/date.c         |  15 +--
 contrib/tzcode/localtime.c    | 152 ++++++++++++----------
 contrib/tzcode/newctime.3     |  22 +++-
 contrib/tzcode/newstrftime.3  |   2 +-
 contrib/tzcode/newtzset.3     |   5 +-
 contrib/tzcode/private.h      | 135 +++++++++++++++-----
 contrib/tzcode/strftime.c     |   6 +-
 contrib/tzcode/theory.html    |  66 ++++++----
 contrib/tzcode/time2posix.3   |   3 -
 contrib/tzcode/tz-art.html    |  21 +++-
 contrib/tzcode/tz-how-to.html |   6 +-
 contrib/tzcode/tz-link.html   |  93 ++++++++++----
 contrib/tzcode/tzfile.5       |   5 +-
 contrib/tzcode/tzfile.h       |   6 +-
 contrib/tzcode/tzselect.8     |   2 +-
 contrib/tzcode/tzselect.ksh   | 287 +++++++++++++++++++++++++++++-------------
 contrib/tzcode/version        |   2 +-
 contrib/tzcode/zdump.8        |   3 -
 contrib/tzcode/zdump.c        |  85 +++++++------
 contrib/tzcode/zic.8          |  19 +--
 contrib/tzcode/zic.c          |  67 +++++-----
 lib/libc/stdtime/Symbol.map   |   1 +
 27 files changed, 839 insertions(+), 397 deletions(-)

diff --git a/contrib/tzcode/CONTRIBUTING b/contrib/tzcode/CONTRIBUTING
index 4c0f56a50265..6d800e4c03a3 100644
--- a/contrib/tzcode/CONTRIBUTING
+++ b/contrib/tzcode/CONTRIBUTING
@@ -18,7 +18,7 @@ To email small changes, please run a POSIX shell command like
 'diff -u old/europe new/europe >myfix.patch', and attach
 'myfix.patch' to the email.
 
-For more-elaborate or possibly-controversial changes,
+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>.
diff --git a/contrib/tzcode/Makefile b/contrib/tzcode/Makefile
index afb9d538a203..0e56af89e2a4 100644
--- a/contrib/tzcode/Makefile
+++ b/contrib/tzcode/Makefile
@@ -35,22 +35,14 @@ DATAFORM=		main
 
 LOCALTIME=	Factory
 
-# The POSIXRULES macro controls interpretation of nonstandard and obsolete
-# POSIX-like TZ settings like TZ='EET-2EEST' that lack DST transition rules.
-# Such a setting uses the rules in a template file to determine
-# "spring forward" and "fall back" days and times; the environment
-# variable itself specifies UT offsets of standard and daylight saving time.
-#
+# The POSIXRULES macro controls interpretation of POSIX-like TZ
+# settings like TZ='EET-2EEST' that lack DST transition rules.
 # If POSIXRULES is '-', no template is installed; this is the default.
-#
 # Any other value for POSIXRULES is obsolete and should not be relied on, as:
 # * It does not work correctly in popular implementations such as GNU/Linux.
 # * It does not work even in tzcode, except for historical timestamps
 #   that precede the last explicit transition in the POSIXRULES file.
 #   Hence it typically does not work for current and future timestamps.
-# In short, software should avoid ruleless settings like TZ='EET-2EEST'
-# and so should not depend on the value of POSIXRULES.
-#
 # If, despite the above, you want a template for handling these settings,
 # you can change the line below (after finding the timezone you want in the
 # one of the $(TDATA) source files, or adding it to a source file).
@@ -63,7 +55,7 @@ LOCALTIME=	Factory
 POSIXRULES=	-
 
 # Also see TZDEFRULESTRING below, which takes effect only
-# if the time zone files cannot be accessed.
+# if POSIXRULES is '-' or if the template file cannot be accessed.
 
 
 # Installation locations.
@@ -211,7 +203,7 @@ LDLIBS=
 #  -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ'
 #  -DHAVE_DECL_TIMEGM=0 if <time.h> does not declare timegm
 #  -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows)
-#  -DHAVE_GENERIC=0 if _Generic does not work*
+#  -DHAVE__GENERIC=0 if _Generic does not work*
 #  -DHAVE_GETRANDOM if getrandom works (e.g., GNU/Linux),
 #	-DHAVE_GETRANDOM=0 to avoid using getrandom
 #  -DHAVE_GETTEXT if gettext works (e.g., GNU/Linux, FreeBSD, Solaris),
@@ -220,7 +212,7 @@ LDLIBS=
 #  -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares
 #	ctime_r and asctime_r incompatibly with the POSIX standard
 #	(Solaris when _POSIX_PTHREAD_SEMANTICS is not defined).
-#  -DHAVE_INTTYPES_H=0 if <inttypes.h> does not work*
+#  -DHAVE_INTTYPES_H=0 if <inttypes.h> does not work*+
 #  -DHAVE_LINK=0 if your system lacks a link function
 #  -DHAVE_LOCALTIME_R=0 if your system lacks a localtime_r function
 #  -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz
@@ -229,22 +221,24 @@ LDLIBS=
 #  -DHAVE_POSIX_DECLS=0 if your system's include files do not declare
 #	functions like 'link' or variables like 'tzname' required by POSIX
 #  -DHAVE_SETENV=0 if your system lacks the setenv function
-#  -DHAVE_SNPRINTF=0 if your system lacks the snprintf function
+#  -DHAVE_SNPRINTF=0 if your system lacks the snprintf function+
 #  -DHAVE_STDCKDINT_H=0 if neither <stdckdint.h> nor substitutes like
 #	__builtin_add_overflow work*
-#  -DHAVE_STDINT_H=0 if <stdint.h> does not work*
+#  -DHAVE_STDINT_H=0 if <stdint.h> does not work*+
 #  -DHAVE_STRFTIME_L if <time.h> declares locale_t and strftime_l
 #  -DHAVE_STRDUP=0 if your system lacks the strdup function
-#  -DHAVE_STRTOLL=0 if your system lacks the strtoll function
+#  -DHAVE_STRTOLL=0 if your system lacks the strtoll function+
 #  -DHAVE_SYMLINK=0 if your system lacks the symlink function
 #  -DHAVE_SYS_STAT_H=0 if <sys/stat.h> does not work*
 #  -DHAVE_TZSET=0 if your system lacks a tzset function
 #  -DHAVE_UNISTD_H=0 if <unistd.h> does not work*
 #  -DHAVE_UTMPX_H=0 if <utmpx.h> does not work*
 #  -Dlocale_t=XXX if your system uses XXX instead of locale_t
+#  -DPORT_TO_C89 if tzcode should also run on C89 platforms+
 #  -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers
 #	with external linkage, e.g., applications cannot define 'localtime'.
 #  -Dssize_t=long on hosts like MS-Windows that lack ssize_t
+#  -DSUPPORT_C89 if the tzcode library should support C89 callers+
 #  -DSUPPRESS_TZDIR to not prepend TZDIR to file names; this has
 #	security implications and is not recommended for general use
 #  -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires;
@@ -256,7 +250,13 @@ LDLIBS=
 #  -DTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory;
 #	the default is system-supplied, typically "/usr/lib/locale"
 #  -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified
-#	DST transitions if the time zone files cannot be accessed
+#	DST transitions for POSIX-style TZ strings lacking them,
+#	in the usual case where POSIXRULES is '-'.  If not specified,
+#	TZDEFRULESTRING defaults to US rules for future DST transitions.
+#	This mishandles some past timestamps, as US DST rules have changed.
+#	It also mishandles settings like TZ='EET-2EEST' for eastern Europe,
+#	as Europe and US DST rules differ.
+#  -DTZNAME_MAXIMUM=N to limit time zone abbreviations to N bytes (default 255)
 #  -DUNINIT_TRAP if reading uninitialized storage can cause problems
 #	other than simply getting garbage data
 #  -DUSE_LTZ=0 to build zdump with the system time zone library
@@ -273,6 +273,8 @@ LDLIBS=
 #  $(GCC_DEBUG_FLAGS) if you are using recent GCC and want lots of checking
 #
 # * Options marked "*" can be omitted if your compiler is C23 compatible.
+# * Options marked "+" are obsolescent and are planned to be removed
+#   once the code assumes C99 or later.
 #
 # Select instrumentation via "make GCC_INSTRUMENT='whatever'".
 GCC_INSTRUMENT = \
@@ -351,6 +353,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
 # functions to be added to the time conversion library.
 # "offtime" is like "gmtime" except that it accepts a second (long) argument
 # that gives an offset to add to the time_t when converting it.
+# "offtime_r" is to "offtime" what "gmtime_r" is to "gmtime".
 # "timelocal" is equivalent to "mktime".
 # "timeoff" is like "timegm" except that it accepts a second (long) argument
 # that gives an offset to use when converting to a time_t.
@@ -363,7 +366,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
 #	-DNETBSD_INSPIRED=0
 # to the end of the "CFLAGS=" line.  Otherwise, the functions
 # "localtime_rz", "mktime_z", "tzalloc", and "tzfree" are added to the
-# time library, and if STD_INSPIRED is also defined the functions
+# time library, and if STD_INSPIRED is also defined to nonzero the functions
 # "posix2time_z" and "time2posix_z" are added as well.
 # The functions ending in "_z" (or "_rz") are like their unsuffixed
 # (or suffixed-by-"_r") counterparts, except with an extra first
@@ -455,16 +458,13 @@ SAFE_CHARSET3=	'abcdefghijklmnopqrstuvwxyz{|}~'
 SAFE_CHARSET=	$(SAFE_CHARSET1)$(SAFE_CHARSET2)$(SAFE_CHARSET3)
 SAFE_CHAR=	'[]'$(SAFE_CHARSET)'-]'
 
-# These characters are Latin-1, and so are likely to be displayable
-# even in editors with limited character sets.
-UNUSUAL_OK_LATIN_1 = «°±»½¾×
-# This IPA symbol is represented in Unicode as the composition of
-# U+0075 and U+032F, and U+032F is not considered alphabetic by some
-# grep implementations that do not grok composition.
-UNUSUAL_OK_IPA = u̯
+# These non-alphabetic, non-ASCII printable characters are Latin-1,
+# and so are likely displayable even in editors like XEmacs 21
+# that have limited display capabilities.
+UNUSUAL_OK_LATIN_1 = ¡¢£¤¥¦§¨©«¬®¯°±²³´¶·¸¹»¼½¾¿×÷
 # Non-ASCII non-letters that OK_CHAR allows, as these characters are
 # useful in commentary.
-UNUSUAL_OK_CHARSET= $(UNUSUAL_OK_LATIN_1)$(UNUSUAL_OK_IPA)
+UNUSUAL_OK_CHARSET= $(UNUSUAL_OK_LATIN_1)
 
 # Put this in a bracket expression to match spaces.
 s = [:space:]
@@ -833,7 +833,7 @@ check_slashed_abbrs: $(TDATA_TO_CHECK)
 
 CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; }
 
-check_sorted: backward backzone iso3166.tab zone.tab zone1970.tab
+check_sorted: backward backzone
 		$(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} !/./ {g++}' \
 		  backward | LC_ALL=C sort -cu
 		$(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu
diff --git a/contrib/tzcode/NEWS b/contrib/tzcode/NEWS
index 701e490e4834..b54538aa4a82 100644
--- a/contrib/tzcode/NEWS
+++ b/contrib/tzcode/NEWS
@@ -1,5 +1,116 @@
 News for the tz database
 
+Release 2023c - 2023-03-28 12:42:14 -0700
+
+  Changes to past and future timestamps
+
+    Model Lebanon's DST chaos by reverting data to tzdb 2023a.
+    (Thanks to Rany Hany for the heads-up.)
+
+
+Release 2023b - 2023-03-23 19:50:38 -0700
+
+  Changes to future timestamps
+
+    This year Lebanon springs forward April 20/21 not March 25/26.
+    (Thanks to Saadallah Itani.)  [This was reverted in 2023c.]
+
+
+Release 2023a - 2023-03-22 12:39:33 -0700
+
+  Briefly:
+    Egypt now uses DST again, from April through October.
+    This year Morocco springs forward April 23, not April 30.
+    Palestine delays the start of DST this year.
+    Much of Greenland still uses DST from 2024 on.
+    America/Yellowknife now links to America/Edmonton.
+    tzselect can now use current time to help infer timezone.
+    The code now defaults to C99 or later.
+    Fix use of C23 attributes.
+
+  Changes to future timestamps
+
+    Starting in 2023, Egypt will observe DST from April's last Friday
+    through October's last Thursday.  (Thanks to Ahmad ElDardiry.)
+    Assume the transition times are 00:00 and 24:00, respectively.
+
+    In 2023 Morocco's spring-forward transition after Ramadan
+    will occur April 23, not April 30.  (Thanks to Milamber.)
+    Adjust predictions for future years accordingly.  This affects
+    predictions for 2023, 2031, 2038, and later years.
+
+    This year Palestine will delay its spring forward from
+    March 25 to April 29 due to Ramadan.  (Thanks to Heba Hamad.)
+    Make guesses for future Ramadans too.
+
+    Much of Greenland, represented by America/Nuuk, will continue to
+    observe DST using European Union rules.  When combined with
+    Greenland's decision not to change the clocks in fall 2023,
+    America/Nuuk therefore changes from -03/-02 to -02/-01 effective
+    2023-10-29 at 01:00 UTC.  (Thanks to Thomas M. Steenholdt.)
+    This change from 2022g doesn't affect timestamps until 2024-03-30,
+    and doesn't affect tm_isdst until 2023-03-25.
+
+  Changes to past timestamps
+
+    America/Yellowknife has changed from a Zone to a backward
+    compatibility Link, as it no longer differs from America/Edmonton
+    since 1970.  (Thanks to Almaz Mingaleev.)  This affects some
+    pre-1948 timestamps.  The old data are now in 'backzone'.
+
+  Changes to past time zone abbreviations
+
+    When observing Moscow time, Europe/Kirov and Europe/Volgograd now
+    use the abbreviations MSK/MSD instead of numeric abbreviations,
+    for consistency with other timezones observing Moscow time.
+
+  Changes to code
+
+    You can now tell tzselect local time, to simplify later choices.
+    Select the 'time' option in its first prompt.
+
+    You can now compile with -DTZNAME_MAXIMUM=N to limit time zone
+    abbreviations to N bytes (default 255).  The reference runtime
+    library now rejects POSIX-style TZ strings that contain longer
+    abbreviations, treating them as UTC.  Previously the limit was
+    platform dependent and abbreviations were silently truncated to
+    16 bytes even when the limit was greater than 16.
+
+    The code by default is now designed for C99 or later.  To build in
+    a C89 environment, compile with -DPORT_TO_C89.  To support C89
+    callers of the tzcode library, compile with -DSUPPORT_C89.  The
+    two new macros are transitional aids planned to be removed in a
+    future version, when C99 or later will be required.
+
+    The code now builds again on pre-C99 platforms, if you compile
+    with -DPORT_TO_C89.  This fixes a bug introduced in 2022f.
+
+    On C23-compatible platforms tzcode no longer uses syntax like
+    'static [[noreturn]] void usage(void);'.  Instead, it uses
+    '[[noreturn]] static void usage(void);' as strict C23 requires.
+    (Problem reported by Houge Langley.)
+
+    The code's functions now constrain their arguments with the C
+    'restrict' keyword consistently with their documentation.
+    This may allow future optimizations.
+
+    zdump again builds standalone with ckdadd and without setenv,
+    fixing a bug introduced in 2022g.  (Problem reported by panic.)
+
+    leapseconds.awk can now process a leap seconds file that never
+    expires; this might be useful if leap seconds are discontinued.
+
+  Changes to commentary
+
+    tz-link.html has a new section "Coordinating with governments and
+    distributors".  (Thanks to Neil Fuller for some of the text.)
+
+    To improve tzselect diagnostics, zone1970.tab's comments column is
+    now limited to countries that have multiple timezones.
+
+    Note that leap seconds are planned to be discontinued by 2035.
+
+
 Release 2022g - 2022-11-29 08:58:31 -0800
 
   Briefly:
@@ -596,7 +707,7 @@ Release 2021b - 2021-09-24 16:23:00 -0700
     Starting with 2020a, zic -L truncated its output according to the
     "Expires" directive or "#expires" comment in the leapseconds file.
     The resulting TZif files omitted daylight saving transitions after
-    the leap second table expired, which led to far less-accurate
+    the leap second table expired, which led to far less accurate
     predictions of times after the expiry.  Although future timestamps
     cannot be converted accurately in the presence of leap seconds, it
     is more accurate to convert near-future timestamps with a few
@@ -616,7 +727,7 @@ Release 2021b - 2021-09-24 16:23:00 -0700
     zic -L LEAPFILE -r @LO no longer generates an invalid TZif file
     that omits leap second information for the range LO..B when LO
     falls between two leap seconds A and B.  Instead, it generates a
-    TZif version 4 file that represents the previously-missing
+    TZif version 4 file that represents the previously missing
     information.
 
     The TZif reader now allows the leap second table to begin with a
@@ -670,7 +781,7 @@ Release 2021b - 2021-09-24 16:23:00 -0700
     Fix a bug with 'zic -r @X' when X is a negative leap second that
     has a nonnegative correction.  Without the fix, the output file
     was truncated so that X appeared to be a positive leap second.
-    Fix a similar, even-less-likely bug when truncating at a positive
+    Fix a similar, even less likely bug when truncating at a positive
     leap second that has a nonpositive correction.
 
     zic -r now reports an error if given rolling leap seconds, as this
@@ -691,7 +802,7 @@ Release 2021b - 2021-09-24 16:23:00 -0700
     fixing a bug introduced in 2014g.
 
     zdump -v now outputs timestamps at boundaries of what localtime
-    and gmtime can represent, instead of the less-useful timestamps
+    and gmtime can represent, instead of the less useful timestamps
     one day after the minimum and one day before the maximum.
     (Thanks to Arthur David Olson for prototype code, and to Manuela
     Friedrich for debugging help.)
@@ -2311,7 +2422,7 @@ Release 2016g - 2016-09-13 08:56:38 -0700
     names internally.
 
     zdump has a new -i option to generate transitions in a
-    more-compact but still human-readable format.  This option is
+    smaller but still human-readable format.  This option is
     experimental, and the output format may change in future versions.
     (Thanks to Jon Skeet for suggesting that an option was needed,
     and thanks to Tim Parenti and Chris Rovick for further comments.)
@@ -2333,7 +2444,7 @@ Release 2016g - 2016-09-13 08:56:38 -0700
     release 2016g, the version number is now something like
     '2016g-23-g50556e3-dirty' instead of the misleading '2016g'.
     Tagged releases use the same version number format as before,
-    e.g., '2016g'.  To support the more-accurate version number, its
+    e.g., '2016g'.  To support the more accurate version number, its
     specification has moved from a line in the Makefile to a new
     source file 'version'.
 
@@ -2964,7 +3075,7 @@ Release 2014i - 2014-10-21 22:04:57 -0700
 
     Since Belarus is not changing its clocks even though Moscow is,
     the time zone abbreviation in Europe/Minsk is changing from FET
-    to its more-traditional value MSK on 2014-10-26 at 01:00.
+    to its more traditional value MSK on 2014-10-26 at 01:00.
     (Thanks to Alexander Bokovoy for the heads-up about Belarus.)
 
     The new abbreviation IDT stands for the pre-1976 use of UT +08 in
@@ -3056,7 +3167,7 @@ Release 2014h - 2014-09-25 18:59:03 -0700
 
   Changes affecting build procedure
 
-    'make check' now checks better for properly-sorted data.
+    'make check' now checks better for properly sorted data.
 
   Changes affecting documentation and commentary
 
@@ -3557,7 +3668,7 @@ Release 2014a - 2014-03-07 23:30:29 -0800
 
   Changes affecting past timestamps
 
-    Fiji ended DST on 2014-01-19 at 02:00, not the previously-scheduled 03:00.
+    Fiji ended DST on 2014-01-19 at 02:00, not the previously scheduled 03:00.
     (Thanks to Steffen Thorsen.)
 
     Ukraine switched from Moscow to Eastern European time on 1990-07-01
@@ -3811,7 +3922,7 @@ Release 2013e - 2013-09-19 23:50:04 -0700
     Allow POSIX-like TZ strings where the transition time's hour can
     range from -167 through 167, instead of the POSIX-required 0
     through 24.  E.g., TZ='FJT-12FJST,M10.3.1/146,M1.3.4/75' for the
-    new Fiji rules.  This is a more-compact way to represent
+    new Fiji rules.  This is a more compact way to represent
     far-future timestamps for America/Godthab, America/Santiago,
     Antarctica/Palmer, Asia/Gaza, Asia/Hebron, Asia/Jerusalem,
     Pacific/Easter, and Pacific/Fiji.  Other zones are unaffected by
@@ -3819,7 +3930,7 @@ Release 2013e - 2013-09-19 23:50:04 -0700
 
     Allow POSIX-like TZ strings where daylight saving time is in
     effect all year.  E.g., TZ='WART4WARST,J1/0,J365/25' for Western
-    Argentina Summer Time all year.  This supports a more-compact way
+    Argentina Summer Time all year.  This supports a more compact way
     to represent the 2013d data for America/Argentina/San_Luis.
     Because of the change for San Luis noted above this change does not
     affect the current data.  (Thanks to Andrew Main (Zefram) for
@@ -3908,13 +4019,13 @@ Release 2013e - 2013-09-19 23:50:04 -0700
 
     zdump now outputs "UT" when referring to Universal Time, not "UTC".
     "UTC" does not make sense for timestamps that predate the introduction
-    of UTC, whereas "UT", a more-generic term, does.  (Thanks to Steve Allen
+    of UTC, whereas "UT", a more generic term, does.  (Thanks to Steve Allen
     for clarifying UT vs UTC.)
 
   Data changes affecting behavior of tzselect and similar programs
 
-    Country code BQ is now called the more-common name "Caribbean Netherlands"
-    rather than the more-official "Bonaire, St Eustatius & Saba".
+    Country code BQ is now called the more common name "Caribbean Netherlands"
+    rather than the more official "Bonaire, St Eustatius & Saba".
 
     Remove from zone.tab the names America/Montreal, America/Shiprock,
     and Antarctica/South_Pole, as they are equivalent to existing
@@ -4098,7 +4209,7 @@ Release 2013c - 2013-04-19 16:17:40 -0700
     Macquarie Island is politically part of Australia, not Antarctica.
     (Thanks to Tobias Conradi.)
 
-    Sort Macquarie more-consistently with other parts of Australia.
+    Sort Macquarie more consistently with other parts of Australia.
     (Thanks to Tim Parenti.)
 
 
@@ -5322,7 +5433,7 @@ Release data1998g - 1998-08-11 03:28:35 -0000
 Release data1998f - 1998-07-20 13:50:00 -0000
   [tzdata1998f.tar.gz is missing!]
 
-  Update the "leapseconds" file to include the newly-announced
+  Update the "leapseconds" file to include the newly announced
   insertion at the end of 1998.
 
 
diff --git a/contrib/tzcode/asctime.c b/contrib/tzcode/asctime.c
index 1a6486f38163..b129ea22dd1b 100644
--- a/contrib/tzcode/asctime.c
+++ b/contrib/tzcode/asctime.c
@@ -52,8 +52,18 @@ enum { STD_ASCTIME_BUF_SIZE = 26 };
 */
 static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1];
 
+/* A similar buffer for ctime.
+   C89 requires that they be the same buffer.
+   This requirement was removed in C99, so support it only if requested,
+   as support is more likely to lead to bugs in badly written programs.  */
+#if SUPPORT_C89
+# define buf_ctime buf_asctime
+#else
+static char buf_ctime[sizeof buf_asctime];
+#endif
+
 char *
-asctime_r(register const struct tm *timeptr, char *buf)
+asctime_r(struct tm const *restrict timeptr, char *restrict buf)
 {
 	static const char	wday_name[][4] = {
 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
@@ -93,7 +103,8 @@ asctime_r(register const struct tm *timeptr, char *buf)
 		timeptr->tm_mday, timeptr->tm_hour,
 		timeptr->tm_min, timeptr->tm_sec,
 		year);
-	if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime)
+	if (strlen(result) < STD_ASCTIME_BUF_SIZE
+	    || buf == buf_ctime || buf == buf_asctime)
 		return strcpy(buf, result);
 	else {
 		errno = EOVERFLOW;
@@ -106,3 +117,17 @@ asctime(register const struct tm *timeptr)
 {
 	return asctime_r(timeptr, buf_asctime);
 }
+
+char *
+ctime_r(const time_t *timep, char *buf)
+{
+  struct tm mytm;
+  struct tm *tmp = localtime_r(timep, &mytm);
+  return tmp ? asctime_r(tmp, buf) : NULL;
+}
+
+char *
+ctime(const time_t *timep)
+{
+  return ctime_r(timep, buf_ctime);
+}
diff --git a/contrib/tzcode/date.1 b/contrib/tzcode/date.1
index 043e568117df..e8107212364d 100644
--- a/contrib/tzcode/date.1
+++ b/contrib/tzcode/date.1
@@ -1,6 +1,6 @@
 .\" This file is in the public domain, so clarified as of
 .\" 2009-05-17 by Arthur David Olson.
-.TH date 1
+.TH date 1 "" "Time Zone Database"
 .SH NAME
 date \- show and set date and time
 .SH SYNOPSIS
@@ -156,7 +156,8 @@ hexadecimal (leading 0x), preceded by an optional sign.
 .br
 /usr/share/zoneinfo	timezone information directory
 .br
-/usr/share/zoneinfo/posixrules	used with POSIX-style TZ's
+/usr/share/zoneinfo/posixrules	default DST rules (obsolete,
+	and can cause bugs if present)
 .br
 /usr/share/zoneinfo/GMT	for UTC leap seconds
 .sp
diff --git a/contrib/tzcode/date.c b/contrib/tzcode/date.c
index 11c5e5fe8d49..b62f04d768bc 100644
--- a/contrib/tzcode/date.c
+++ b/contrib/tzcode/date.c
@@ -42,7 +42,7 @@ static void		display(const char *, time_t);
 static void		dogmt(void);
 static void		errensure(void);
 static void		timeout(FILE *, const char *, const struct tm *);
-static ATTRIBUTE_NORETURN void usage(void);
+ATTRIBUTE_NORETURN static void usage(void);
 
 int
 main(const int argc, char *argv[])
@@ -86,7 +86,9 @@ main(const int argc, char *argv[])
 			else if (! (TIME_T_MIN <= secs && secs <= TIME_T_MAX))
 				errno = ERANGE;
 			if (errno) {
-				perror(optarg);
+				char const *e = strerror(errno);
+				fprintf(stderr, _("date: %s: %s\n"),
+					optarg, e);
 				errensure();
 				exit(retval);
 			}
@@ -124,10 +126,10 @@ dogmt(void)
 			continue;
 #if defined ckd_add && defined ckd_mul
 		if (!ckd_add(&n, n, 2) && !ckd_mul(&n, n, sizeof *fakeenv)
-		    && n <= SIZE_MAX)
+		    && n <= INDEX_MAX)
 		  fakeenv = malloc(n);
 #else
-		if (n <= min(PTRDIFF_MAX, SIZE_MAX) / sizeof *fakeenv - 2)
+		if (n <= INDEX_MAX / sizeof *fakeenv - 2)
 		  fakeenv = malloc((n + 2) * sizeof *fakeenv);
 #endif
 		if (fakeenv == NULL) {
@@ -194,10 +196,9 @@ timeout(FILE *fp, char const *format, struct tm const *tmp)
 
 	for ( ; ; ) {
 #ifdef ckd_mul
-		bool bigger = !ckd_mul(&size, size, 2) && size <= SIZE_MAX;
+		bool bigger = !ckd_mul(&size, size, 2) && size <= INDEX_MAX;
 #else
-		bool bigger = (size <= min(PTRDIFF_MAX, SIZE_MAX) / 2
-			       && (size *= 2, true));
+		bool bigger = size <= INDEX_MAX / 2 && (size *= 2, true);
 #endif
 		char *newcp = bigger ? realloc(cp, size) : NULL;
 		if (!newcp) {
diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c
index a8beaf47319a..3bf9378fe673 100644
--- a/contrib/tzcode/localtime.c
+++ b/contrib/tzcode/localtime.c
@@ -47,10 +47,6 @@ static int lock(void) { return 0; }
 static void unlock(void) { }
 #endif
 
-#ifndef TZ_ABBR_MAX_LEN
-# define TZ_ABBR_MAX_LEN 16
-#endif /* !defined TZ_ABBR_MAX_LEN */
-
 #ifndef TZ_ABBR_CHAR_SET
 # define TZ_ABBR_CHAR_SET \
 	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
@@ -128,12 +124,11 @@ static char const UNSPEC[] = "-00";
    for ttunspecified to work without crashing.  */
 enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 };
 
-#ifdef TZNAME_MAX
-# define MY_TZNAME_MAX TZNAME_MAX
-#endif /* defined TZNAME_MAX */
-#ifndef TZNAME_MAX
-# define MY_TZNAME_MAX 255
-#endif /* !defined TZNAME_MAX */
+/* Limit to time zone abbreviation length in POSIX-style TZ strings.
+   This is distinct from TZ_MAX_CHARS, which limits TZif file contents.  */
+#ifndef TZNAME_MAXIMUM
+# define TZNAME_MAXIMUM 255
+#endif
 
 struct state {
 	int		leapcnt;
@@ -146,7 +141,7 @@ struct state {
 	unsigned char	types[TZ_MAX_TIMES];
 	struct ttinfo	ttis[TZ_MAX_TYPES];
 	char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"),
-		       2 * (MY_TZNAME_MAX + 1))];
+		       2 * (TZNAME_MAXIMUM + 1))];
 	struct lsinfo	lsis[TZ_MAX_LEAPS];
 
 	/* The time type to use for early times or if no transitions.
@@ -203,6 +198,9 @@ static pthread_once_t	gmt_once = PTHREAD_ONCE_INIT;
 static pthread_once_t	gmtime_once = PTHREAD_ONCE_INIT;
 static pthread_key_t	gmtime_key;
 static int		gmtime_key_error;
+static pthread_once_t	offtime_once = PTHREAD_ONCE_INIT;
+static pthread_key_t	offtime_key;
+static int		offtime_key_error;
 static pthread_once_t	localtime_once = PTHREAD_ONCE_INIT;
 static pthread_key_t	localtime_key;
 static int		localtime_key_error;
@@ -213,9 +211,14 @@ static int		localtime_key_error;
 **	ctime, gmtime, localtime] return values in one of two static
 **	objects: a broken-down time structure and an array of char.
 ** Thanks to Paul Eggert for noting this.
+**
+** This requirement was removed in C99, so support it only if requested,
+** as support is more likely to lead to bugs in badly written programs.
 */
 
+#if SUPPORT_C89
 static struct tm	tm;
+#endif
 
 #if 2 <= HAVE_TZNAME + TZ_TIME_T
 char *			tzname[2] = {
@@ -367,27 +370,28 @@ settzname(void)
 #endif
 }
 
-static void
+/* Replace bogus characters in time zone abbreviations.
+   Return 0 on success, an errno value if a time zone abbreviation is
+   too long.  */
+static int
 scrub_abbrs(struct state *sp)
 {
 	int i;
-	/*
-	** First, replace bogus characters.
-	*/
+
+	/* Reject overlong abbreviations.  */
+	for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) {
+	  int len = strlen(&sp->chars[i]);
+	  if (TZNAME_MAXIMUM < len)
+	    return EOVERFLOW;
+	  i += len + 1;
+	}
+
+	/* Replace bogus characters.  */
 	for (i = 0; i < sp->charcnt; ++i)
 		if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
 			sp->chars[i] = TZ_ABBR_ERR_CHAR;
-	/*
-	** Second, truncate long abbreviations.
-	*/
-	for (i = 0; i < sp->typecnt; ++i) {
-		register const struct ttinfo * const	ttisp = &sp->ttis[i];
-		char *cp = &sp->chars[ttisp->tt_desigidx];
 
-		if (strlen(cp) > TZ_ABBR_MAX_LEN &&
-			strcmp(cp, GRANDPARENTED) != 0)
-				*(cp + TZ_ABBR_MAX_LEN) = '\0';
-	}
+	return 0;
 }
 
 #ifdef DETECT_TZ_CHANGES
@@ -898,7 +902,7 @@ is_digit(char c)
 ** Return a pointer to that character.
 */
 
-static ATTRIBUTE_REPRODUCIBLE const char *
+ATTRIBUTE_REPRODUCIBLE static const char *
 getzname(register const char *strp)
 {
 	register char	c;
@@ -919,7 +923,7 @@ getzname(register const char *strp)
 ** We don't do any checking here; checking is done later in common-case code.
 */
 
-static ATTRIBUTE_REPRODUCIBLE const char *
+ATTRIBUTE_REPRODUCIBLE static const char *
 getqzname(register const char *strp, const int delim)
 {
 	register int	c;
@@ -1199,14 +1203,12 @@ tzparse(const char *name, struct state *sp, struct state *basep)
 	  name = getzname(name);
 	  stdlen = name - stdname;
 	}
-	if (!stdlen)
+	if (! (0 < stdlen && stdlen <= TZNAME_MAXIMUM))
 	  return false;
 	name = getoffset(name, &stdoffset);
 	if (name == NULL)
 	  return false;
 	charcnt = stdlen + 1;
-	if (sizeof sp->chars < charcnt)
-	  return false;
 	if (basep) {
 	  if (0 < basep->timecnt)
 	    atlo = basep->ats[basep->timecnt - 1];
@@ -1233,11 +1235,9 @@ tzparse(const char *name, struct state *sp, struct state *basep)
 			name = getzname(name);
 			dstlen = name - dstname; /* length of DST abbr. */
 		}
-		if (!dstlen)
+		if (! (0 < dstlen && dstlen <= TZNAME_MAXIMUM))
 		  return false;
 		charcnt += dstlen + 1;
-		if (sizeof sp->chars < charcnt)
-		  return false;
 		if (*name != '\0' && *name != ',' && *name != ';') {
 			name = getoffset(name, &dstoffset);
 			if (name == NULL)
@@ -1511,7 +1511,7 @@ zoneinit(struct state *sp, char const *name)
     if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL))
       err = 0;
     if (err == 0)
-      scrub_abbrs(sp);
+      err = scrub_abbrs(sp);
     return err;
   }
 }
@@ -1732,7 +1732,8 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
 #if NETBSD_INSPIRED
 
 struct tm *
-localtime_rz(struct state *sp, time_t const *timep, struct tm *tmp)
+localtime_rz(struct state *restrict sp, time_t const *restrict timep,
+	     struct tm *restrict tmp)
 {
   return localsub(sp, timep, 0, tmp);
 }
@@ -1766,6 +1767,9 @@ localtime_key_init(void)
 struct tm *
 localtime(const time_t *timep)
 {
+#if !SUPPORT_C89
+	static struct tm tm;
+#endif
 	struct tm *p_tm = &tm;
 
 	if (__isthreaded != 0) {
@@ -1788,7 +1792,7 @@ localtime(const time_t *timep)
 }
 
 struct tm *
-localtime_r(const time_t *timep, struct tm *tmp)
+localtime_r(const time_t *restrict timep, struct tm *restrict tmp)
 {
   return localtime_tzset(timep, tmp, false);
 }
@@ -1821,7 +1825,7 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
 */
 
 struct tm *
-gmtime_r(const time_t *timep, struct tm *tmp)
+gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
 {
 	_once(&gmt_once, gmtcheck);
 	return gmtsub(gmtptr, timep, 0, tmp);
@@ -1837,6 +1841,9 @@ gmtime_key_init(void)
 struct tm *
 gmtime(const time_t *timep)
 {
+#if !SUPPORT_C89
+	static struct tm tm;
+#endif
 	struct tm *p_tm = &tm;
 
 	if (__isthreaded != 0) {
@@ -1858,16 +1865,50 @@ gmtime(const time_t *timep)
 	return gmtime_r(timep, p_tm);
 }
 
-#ifdef STD_INSPIRED
+#if STD_INSPIRED
+
+struct tm *
+offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp)
+{
+	_once(&gmt_once, gmtcheck);
+	return gmtsub(gmtptr, timep, offset, tmp);
+}
+
+static void
+offtime_key_init(void)
+{
+
+	offtime_key_error = _pthread_key_create(&offtime_key, free);
+}
 
 struct tm *
 offtime(const time_t *timep, long offset)
 {
-  _once(&gmt_once, gmtcheck);
-  return gmtsub(gmtptr, timep, offset, &tm);
+#if !SUPPORT_C89
+	static struct tm tm;
+#endif
+	struct tm *p_tm = &tm;
+
+	if (__isthreaded != 0) {
+		_pthread_once(&offtime_once, offtime_key_init);
+		if (offtime_key_error != 0) {
+			errno = offtime_key_error;
+			return (NULL);
+		}
+		if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) {
+			if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
+				return (NULL);
+			}
+			if (_pthread_setspecific(offtime_key, p_tm) != 0) {
+				free(p_tm);
+				return (NULL);
+			}
+		}
+	}
+	return offtime_r(timep, offset, p_tm);
 }
 
-#endif /* defined STD_INSPIRED */
+#endif
 
 /*
 ** Return the number of leap years through the end of the given year
@@ -2003,27 +2044,6 @@ timesub(const time_t *timep, int_fast32_t offset,
 	return tmp;
 }
 
-char *
-ctime(const time_t *timep)
-{
-/*
-** Section 4.12.3.2 of X3.159-1989 requires that
-**	The ctime function converts the calendar time pointed to by timer
-**	to local time in the form of a string. It is equivalent to
-**		asctime(localtime(timer))
-*/
-  struct tm *tmp = localtime(timep);
-  return tmp ? asctime(tmp) : NULL;
-}
-
-char *
-ctime_r(const time_t *timep, char *buf)
-{
-  struct tm mytm;
-  struct tm *tmp = localtime_r(timep, &mytm);
-  return tmp ? asctime_r(tmp, buf) : NULL;
-}
-
 /*
 ** Adapted from code provided by Robert Elz, who writes:
 **	The "best" way to do mktime I think is based on an idea of Bob
@@ -2465,7 +2485,7 @@ mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
 #if NETBSD_INSPIRED
 
 time_t
-mktime_z(struct state *sp, struct tm *tmp)
+mktime_z(struct state *restrict sp, struct tm *restrict tmp)
 {
   return mktime_tzname(sp, tmp, false);
 }
@@ -2487,7 +2507,7 @@ mktime(struct tm *tmp)
   return t;
 }
 
-#ifdef STD_INSPIRED
+#if STD_INSPIRED
 time_t
 timelocal(struct tm *tmp)
 {
@@ -2539,7 +2559,7 @@ leapcorr(struct state const *sp, time_t t)
 ** XXX--is the below the right way to conditionalize??
 */
 
-#ifdef STD_INSPIRED
+#if STD_INSPIRED
 
 /* NETBSD_INSPIRED_EXTERN functions are exported to callers if
    NETBSD_INSPIRED is defined, and are private otherwise.  */
@@ -2628,7 +2648,7 @@ posix2time(time_t t)
   return t;
 }
 
-#endif /* defined STD_INSPIRED */
+#endif /* STD_INSPIRED */
 
 #if TZ_TIME_T
 
diff --git a/contrib/tzcode/newctime.3 b/contrib/tzcode/newctime.3
index e25d841ef537..05bb7deaba51 100644
--- a/contrib/tzcode/newctime.3
+++ b/contrib/tzcode/newctime.3
@@ -1,6 +1,6 @@
 .\" This file is in the public domain, so clarified as of
 .\" 2009-05-17 by Arthur David Olson.
-.TH NEWCTIME 3
+.TH newctime 3 "" "Time Zone Database"
 .SH NAME
 asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
 .SH SYNOPSIS
@@ -11,13 +11,13 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
 .PP
 .BR "extern char *tzname[];" " /\(** (optional) \(**/"
 .PP
-.B char *ctime(time_t const *clock);
+.B [[deprecated]] char *ctime(time_t const *clock);
 .PP
 .B char *ctime_r(time_t const *clock, char *buf);
 .PP
 .B double difftime(time_t time1, time_t time0);
 .PP
-.B char *asctime(struct tm const *tm);
+.B [[deprecated]] char *asctime(struct tm const *tm);
 .PP
 .B "char *asctime_r(struct tm const *restrict tm,"
 .B "    char *restrict result);"
@@ -91,6 +91,15 @@ introduction of UTC and are some other flavor of Universal Time (UT).
 Some implementations support leap seconds, in contradiction to POSIX.
 .PP
 The
+.B ctime
+function is deprecated starting in C23.
+Callers can use
+.B localtime_r
+and
+.B strftime
+instead.
+.PP
+The
 .B localtime
 and
 .B gmtime
@@ -128,6 +137,10 @@ converts a time value contained in a
 structure to a string,
 as shown in the above example,
 and returns a pointer to the string.
+This function is deprecated starting in C23.
+Callers can use
+.B strftime
+instead.
 .PP
 The
 .B mktime
@@ -283,7 +296,8 @@ continue to exist in this form in future releases of this code.
 .br
 /usr/share/zoneinfo/localtime	local timezone file
*** 1870 LINES SKIPPED ***