aboutsummaryrefslogtreecommitdiff
path: root/contrib/tzcode
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2023-04-26 09:46:18 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2023-04-26 09:46:21 +0000
commit75411d157232ee3b4789b92c9205453e7d59a3d2 (patch)
tree0a9010d5ea347c903fafe0fa17176feb3ede6bae /contrib/tzcode
parentef661d4a5bf912e4d4850faaf50664532d82541c (diff)
parentd5228e8957c2b6a9cbb2a73947640ce3c70097e8 (diff)
downloadsrc-75411d157232ee3b4789b92c9205453e7d59a3d2.tar.gz
src-75411d157232ee3b4789b92c9205453e7d59a3d2.zip
Update tzcode to 2023c.
MFC after: 3 weeks Sponsored by: Klara, Inc. Reviewed by: philip Differential Revision: https://reviews.freebsd.org/D39712
Diffstat (limited to 'contrib/tzcode')
-rw-r--r--contrib/tzcode/CONTRIBUTING2
-rw-r--r--contrib/tzcode/Makefile54
-rw-r--r--contrib/tzcode/NEWS143
-rw-r--r--contrib/tzcode/asctime.c29
-rw-r--r--contrib/tzcode/date.15
-rw-r--r--contrib/tzcode/date.c15
-rw-r--r--contrib/tzcode/localtime.c152
-rw-r--r--contrib/tzcode/newctime.322
-rw-r--r--contrib/tzcode/newstrftime.32
-rw-r--r--contrib/tzcode/newtzset.35
-rw-r--r--contrib/tzcode/private.h135
-rw-r--r--contrib/tzcode/strftime.c6
-rw-r--r--contrib/tzcode/theory.html66
-rw-r--r--contrib/tzcode/time2posix.33
-rw-r--r--contrib/tzcode/tz-art.html21
-rw-r--r--contrib/tzcode/tz-how-to.html6
-rw-r--r--contrib/tzcode/tz-link.html93
-rw-r--r--contrib/tzcode/tzfile.55
-rw-r--r--contrib/tzcode/tzfile.h6
-rw-r--r--contrib/tzcode/tzselect.82
-rw-r--r--contrib/tzcode/tzselect.ksh287
-rw-r--r--contrib/tzcode/version2
-rw-r--r--contrib/tzcode/zdump.83
-rw-r--r--contrib/tzcode/zdump.c85
-rw-r--r--contrib/tzcode/zic.819
-rw-r--r--contrib/tzcode/zic.c67
26 files changed, 838 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
.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/newstrftime.3 b/contrib/tzcode/newstrftime.3
index d5d8ee104d9f..432c3e889344 100644
--- a/contrib/tzcode/newstrftime.3
+++ b/contrib/tzcode/newstrftime.3
@@ -35,7 +35,7 @@
.\" from: @(#)strftime.3 5.12 (Berkeley) 6/29/91
.\" $Id: strftime.3,v 1.4 1993/12/15 20:33:00 jtc Exp $
.\"
-.TH NEWSTRFTIME 3
+.TH newstrftime 3 "" "Time Zone Database"
.SH NAME
strftime \- format date and time
.SH SYNOPSIS
diff --git a/contrib/tzcode/newtzset.3 b/contrib/tzcode/newtzset.3
index 1e75acf0e6e3..78b6b6ce67c4 100644
--- a/contrib/tzcode/newtzset.3
+++ b/contrib/tzcode/newtzset.3
@@ -1,6 +1,6 @@
.\" This file is in the public domain, so clarified as of
.\" 2009-05-17 by Arthur David Olson.
-.TH NEWTZSET 3
+.TH newtzset 3 "" "Time Zone Database"
.SH NAME
tzset \- initialize time conversion information
.SH SYNOPSIS
@@ -333,7 +333,8 @@ from the rest of the specification.
.br
/usr/share/zoneinfo/localtime local timezone file
.br
-/usr/share/zoneinfo/posixrules used with POSIX-style TZ
+/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/private.h b/contrib/tzcode/private.h
index 35d2444d4ec1..44a927622987 100644
--- a/contrib/tzcode/private.h
+++ b/contrib/tzcode/private.h
@@ -17,12 +17,25 @@
** Thank you!
*/
+/* PORT_TO_C89 means the code should work even if the underlying
+ compiler and library support only C89. SUPPORT_C89 means the
+ tzcode library should support C89 callers in addition to the usual
+ support for C99-and-later callers. These macros are obsolescent,
+ and the plan is to remove them along with any code needed only when
+ they are nonzero. */
+#ifndef PORT_TO_C89
+# define PORT_TO_C89 0
+#endif
+#ifndef SUPPORT_C89
+# define SUPPORT_C89 0
+#endif
+
#ifndef __STDC_VERSION__
# define __STDC_VERSION__ 0
#endif
/* Define true, false and bool if they don't work out of the box. */
-#if __STDC_VERSION__ < 199901
+#if PORT_TO_C89 && __STDC_VERSION__ < 199901
# define true 1
# define false 0
# define bool int
@@ -30,6 +43,10 @@
# include <stdbool.h>
#endif
+#if __STDC_VERSION__ < 202311
+# define static_assert(cond) extern int static_assert_check[(cond) ? 1 : -1]
+#endif
+
/*
** zdump has been made independent of the rest of the time
** conversion package to increase confidence in the verification it provides.
@@ -52,19 +69,19 @@
# define HAVE_DECL_ASCTIME_R 1
#endif
-#if !defined HAVE_GENERIC && defined __has_extension
+#if !defined HAVE__GENERIC && defined __has_extension
# if __has_extension(c_generic_selections)
-# define HAVE_GENERIC 1
+# define HAVE__GENERIC 1
# else
-# define HAVE_GENERIC 0
+# define HAVE__GENERIC 0
# endif
#endif
/* _Generic is buggy in pre-4.9 GCC. */
-#if !defined HAVE_GENERIC && defined __GNUC__ && !defined __STRICT_ANSI__
-# define HAVE_GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__))
+#if !defined HAVE__GENERIC && defined __GNUC__ && !defined __STRICT_ANSI__
+# define HAVE__GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__))
#endif
-#ifndef HAVE_GENERIC
-# define HAVE_GENERIC (201112 <= __STDC_VERSION__)
+#ifndef HAVE__GENERIC
+# define HAVE__GENERIC (201112 <= __STDC_VERSION__)
#endif
#if !defined HAVE_GETTEXT && defined __has_include
@@ -100,10 +117,6 @@
# define HAVE_STRDUP 1
#endif
-#ifndef HAVE_STRTOLL
-# define HAVE_STRTOLL 1
-#endif
-
#ifndef HAVE_SYMLINK
# define HAVE_SYMLINK 1
#endif /* !defined HAVE_SYMLINK */
@@ -185,6 +198,9 @@
#include <stddef.h>
#include <string.h>
+#if !PORT_TO_C89
+# include <inttypes.h>
+#endif
#include <limits.h> /* for CHAR_BIT et al. */
#include <stdlib.h>
@@ -254,10 +270,12 @@
# define R_OK 4
#endif /* !defined R_OK */
+#if PORT_TO_C89
+
/*
** Define HAVE_STDINT_H's default value here, rather than at the
** start, since __GLIBC__ and INTMAX_MAX's values depend on
-** previously-included files. glibc 2.1 and Solaris 10 and later have
+** previously included files. glibc 2.1 and Solaris 10 and later have
** stdint.h, even with pre-C99 compilers.
*/
#if !defined HAVE_STDINT_H && defined __has_include
@@ -334,6 +352,9 @@ typedef int int_fast32_t;
#ifndef INTMAX_MAX
# ifdef LLONG_MAX
typedef long long intmax_t;
+# ifndef HAVE_STRTOLL
+# define HAVE_STRTOLL true
+# endif
# if HAVE_STRTOLL
# define strtoimax strtoll
# endif
@@ -379,8 +400,10 @@ typedef unsigned long long uint_fast64_t;
#ifndef UINTMAX_MAX
# ifdef ULLONG_MAX
typedef unsigned long long uintmax_t;
+# define UINTMAX_MAX ULLONG_MAX
# else
typedef unsigned long uintmax_t;
+# define UINTMAX_MAX ULONG_MAX
# endif
#endif
@@ -396,6 +419,16 @@ typedef unsigned long uintmax_t;
# define SIZE_MAX ((size_t) -1)
#endif
+#endif /* PORT_TO_C89 */
+
+/* The maximum size of any created object, as a signed integer.
+ Although the C standard does not outright prohibit larger objects,
+ behavior is undefined if the result of pointer subtraction does not
+ fit into ptrdiff_t, and the code assumes in several places that
+ pointer subtraction works. As a practical matter it's OK to not
+ support objects larger than this. */
+#define INDEX_MAX ((ptrdiff_t) min(PTRDIFF_MAX, SIZE_MAX))
+
/* Support ckd_add, ckd_sub, ckd_mul on C23 or recent-enough GCC-like
hosts, unless compiled with -DHAVE_STDCKDINT_H=0 or with pre-C23 EDG. */
#if !defined HAVE_STDCKDINT_H && defined __has_include
@@ -435,12 +468,25 @@ typedef unsigned long uintmax_t;
#if (defined __has_c_attribute \
&& (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__))
-# define HAVE_HAS_C_ATTRIBUTE true
+# define HAVE___HAS_C_ATTRIBUTE true
#else
-# define HAVE_HAS_C_ATTRIBUTE false
+# define HAVE___HAS_C_ATTRIBUTE false
+#endif
+
+#if HAVE___HAS_C_ATTRIBUTE
+# if __has_c_attribute(deprecated)
+# define ATTRIBUTE_DEPRECATED [[deprecated]]
+# endif
+#endif
+#ifndef ATTRIBUTE_DEPRECATED
+# if 3 < __GNUC__ + (2 <= __GNUC_MINOR__)
+# define ATTRIBUTE_DEPRECATED __attribute__((deprecated))
+# else
+# define ATTRIBUTE_DEPRECATED /* empty */
+# endif
#endif
-#if HAVE_HAS_C_ATTRIBUTE
+#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(fallthrough)
# define ATTRIBUTE_FALLTHROUGH [[fallthrough]]
# endif
@@ -453,7 +499,7 @@ typedef unsigned long uintmax_t;
# endif
#endif
-#if HAVE_HAS_C_ATTRIBUTE
+#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(maybe_unused)
# define ATTRIBUTE_MAYBE_UNUSED [[maybe_unused]]
# endif
@@ -466,7 +512,7 @@ typedef unsigned long uintmax_t;
# endif
#endif
-#if HAVE_HAS_C_ATTRIBUTE
+#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(noreturn)
# define ATTRIBUTE_NORETURN [[noreturn]]
# endif
@@ -481,7 +527,7 @@ typedef unsigned long uintmax_t;
# endif
#endif
-#if HAVE_HAS_C_ATTRIBUTE
+#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(reproducible)
# define ATTRIBUTE_REPRODUCIBLE [[reproducible]]
# endif
@@ -494,7 +540,7 @@ typedef unsigned long uintmax_t;
# endif
#endif
-#if HAVE_HAS_C_ATTRIBUTE
+#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(unsequenced)
# define ATTRIBUTE_UNSEQUENCED [[unsequenced]]
# endif
@@ -507,7 +553,8 @@ typedef unsigned long uintmax_t;
# endif
#endif
-#if __STDC_VERSION__ < 199901 && !defined restrict
+#if (__STDC_VERSION__ < 199901 && !defined restrict \
+ && (PORT_TO_C89 || defined _MSC_VER))
# define restrict /* empty */
#endif
@@ -579,6 +626,8 @@ typedef time_tz tz_time_t;
# define mktime_z tz_mktime_z
# undef offtime
# define offtime tz_offtime
+# undef offtime_r
+# define offtime_r tz_offtime_r
# undef posix2time
# define posix2time tz_posix2time
# undef posix2time_z
@@ -624,11 +673,16 @@ typedef time_tz tz_time_t;
# define altzone tz_altzone
# endif
-char *asctime(struct tm const *);
+# if __STDC_VERSION__ < 202311
+# define DEPRECATED_IN_C23 /* empty */
+# else
+# define DEPRECATED_IN_C23 ATTRIBUTE_DEPRECATED
+# endif
+DEPRECATED_IN_C23 char *asctime(struct tm const *);
char *asctime_r(struct tm const *restrict, char *restrict);
-char *ctime(time_t const *);
+DEPRECATED_IN_C23 char *ctime(time_t const *);
char *ctime_r(time_t const *, char *);
-double difftime(time_t, time_t) ATTRIBUTE_UNSEQUENCED;
+ATTRIBUTE_UNSEQUENCED double difftime(time_t, time_t);
size_t strftime(char *restrict, size_t, char const *restrict,
struct tm const *restrict);
# if HAVE_STRFTIME_L
@@ -691,10 +745,16 @@ extern long altzone;
** declarations if time_tz is defined.
*/
-#ifdef STD_INSPIRED
+#ifndef STD_INSPIRED
+# define STD_INSPIRED 0
+#endif
+#if STD_INSPIRED
# if TZ_TIME_T || !defined offtime
struct tm *offtime(time_t const *, long);
# endif
+# if TZ_TIME_T || !defined offtime_r
+struct tm *offtime_r(time_t const *, long, struct tm *);
+# endif
# if TZ_TIME_T || !defined timelocal
time_t timelocal(struct tm *);
# endif
@@ -738,12 +798,12 @@ struct tm *localtime_rz(timezone_t restrict, time_t const *restrict,
time_t mktime_z(timezone_t restrict, struct tm *restrict);
timezone_t tzalloc(char const *);
void tzfree(timezone_t);
-# ifdef STD_INSPIRED
+# if STD_INSPIRED
# if TZ_TIME_T || !defined posix2time_z
-time_t posix2time_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
+ATTRIBUTE_REPRODUCIBLE time_t posix2time_z(timezone_t, time_t);
# endif
# if TZ_TIME_T || !defined time2posix_z
-time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
+ATTRIBUTE_REPRODUCIBLE time_t time2posix_z(timezone_t, time_t);
# endif
# endif
#endif
@@ -752,7 +812,7 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
** Finally, some convenience items.
*/
-#define TYPE_BIT(type) (sizeof(type) * CHAR_BIT)
+#define TYPE_BIT(type) (CHAR_BIT * (ptrdiff_t) sizeof(type))
#define TYPE_SIGNED(type) (((type) -1) < 0)
#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
@@ -780,7 +840,7 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
This implementation assumes no padding if time_t is signed and
either the compiler lacks support for _Generic or time_t is not one
of the standard signed integer types. */
-#if HAVE_GENERIC
+#if HAVE__GENERIC
# define TIME_T_MIN \
_Generic((time_t) 0, \
signed char: SCHAR_MIN, short: SHRT_MIN, \
@@ -793,10 +853,23 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \
default: TIME_T_MAX_NO_PADDING) \
: (time_t) -1)
+enum { SIGNED_PADDING_CHECK_NEEDED
+ = _Generic((time_t) 0,
+ signed char: false, short: false,
+ int: false, long: false, long long: false,
+ default: true) };
#else
# define TIME_T_MIN TIME_T_MIN_NO_PADDING
# define TIME_T_MAX TIME_T_MAX_NO_PADDING
+enum { SIGNED_PADDING_CHECK_NEEDED = true };
#endif
+/* Try to check the padding assumptions. Although TIME_T_MAX and the
+ following check can both have undefined behavior on oddball
+ platforms due to shifts exceeding widths of signed integers, these
+ platforms' compilers are likely to diagnose these issues in integer
+ constant expressions, so it shouldn't hurt to check statically. */
+static_assert(! TYPE_SIGNED(time_t) || ! SIGNED_PADDING_CHECK_NEEDED
+ || TIME_T_MAX >> (TYPE_BIT(time_t) - 2) == 1);
/*
** 302 / 1000 is log10(2.0) rounded up.
@@ -863,7 +936,7 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
#if HAVE_INCOMPATIBLE_CTIME_R
#undef asctime_r
#undef ctime_r
-char *asctime_r(struct tm const *, char *);
+char *asctime_r(struct tm const *restrict, char *restrict);
char *ctime_r(time_t const *, char *);
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
diff --git a/contrib/tzcode/strftime.c b/contrib/tzcode/strftime.c
index b23b6101b150..df169830f9ef 100644
--- a/contrib/tzcode/strftime.c
+++ b/contrib/tzcode/strftime.c
@@ -116,7 +116,8 @@ static char * _yconv(int, int, bool, bool, char *, char const *);
#if HAVE_STRFTIME_L
size_t
-strftime_l(char *s, size_t maxsize, char const *format, struct tm const *t,
+strftime_l(char *restrict s, size_t maxsize, char const *restrict format,
+ struct tm const *restrict t,
ATTRIBUTE_MAYBE_UNUSED locale_t locale)
{
/* Just call strftime, as only the C locale is supported. */
@@ -125,7 +126,8 @@ strftime_l(char *s, size_t maxsize, char const *format, struct tm const *t,
#endif
size_t
-strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
+strftime(char *restrict s, size_t maxsize, char const *restrict format,
+ struct tm const *restrict t)
{
char * p;
int saved_errno = errno;
diff --git a/contrib/tzcode/theory.html b/contrib/tzcode/theory.html
index 75e347f0f9d1..369c75433ff2 100644
--- a/contrib/tzcode/theory.html
+++ b/contrib/tzcode/theory.html
@@ -23,7 +23,7 @@
<li><a href="#stability">Interface stability</a></li>
<li><a href="#leapsec">Leap seconds</a></li>
<li><a href="#calendar">Calendrical issues</a></li>
- <li><a href="#planets">Time and time zones on other planets</a></li>
+ <li><a href="#planets">Time and time zones off earth</a></li>
</ul>
</nav>
@@ -443,11 +443,11 @@ in decreasing order of importance:
CAT/CAST Central Africa,
CET/CEST/CEMT Central European,
ChST Chamorro,
- CST/CDT/CWT/CPT/CDDT Central [North America],
+ CST/CDT/CWT/CPT Central [North America],
CST/CDT China,
GMT/BST/IST/BDST Greenwich,
EAT East Africa,
- EST/EDT/EWT/EPT/EDDT Eastern [North America],
+ EST/EDT/EWT/EPT Eastern [North America],
EET/EEST Eastern European,
GST/GDT Guam,
HST/HDT/HWT/HPT Hawaii,
@@ -460,13 +460,13 @@ in decreasing order of importance:
MET/MEST Middle European (a backward-compatibility alias for
Central European),
MSK/MSD Moscow,
- MST/MDT/MWT/MPT/MDDT Mountain,
+ MST/MDT/MWT/MPT Mountain,
NST/NDT/NWT/NPT/NDDT Newfoundland,
NST/NDT/NWT/NPT Nome,
NZMT/NZST New Zealand through 1945,
NZST/NZDT New Zealand 1946&ndash;present,
PKT/PKST Pakistan,
- PST/PDT/PWT/PPT/PDDT Pacific,
+ PST/PDT/PWT/PPT Pacific,
PST/PDT Philippine,
SAST South Africa,
SST Samoa,
@@ -494,7 +494,7 @@ in decreasing order of importance:
<p>
<small>These abbreviations are:
AMT Asunción, Athens;
- BMT Baghdad, Bangkok, Batavia, Bermuda, Bern, Bogotá, Bridgetown,
+ BMT Baghdad, Bangkok, Batavia, Bermuda, Bern, Bogotá,
Brussels, Bucharest;
CMT Calamarca, Caracas, Chisinau, Colón, Córdoba;
DMT Dublin/Dunsink;
@@ -506,12 +506,13 @@ in decreasing order of importance:
IMT Irkutsk, Istanbul;
JMT Jerusalem;
KMT Kaunas, Kyiv, Kingston;
- LMT Lima, Lisbon, local, Luanda;
+ LMT Lima, Lisbon, local;
MMT Macassar, Madras, Malé, Managua, Minsk, Monrovia, Montevideo,
Moratuwa, Moscow;
PLMT Phù Liễn;
PMT Paramaribo, Paris, Perm, Pontianak, Prague;
PMMT Port Moresby;
+ PPMT Port-au-Prince;
QMT Quito;
RMT Rangoon, Riga, Rome;
SDMT Santo Domingo;
@@ -519,8 +520,7 @@ in decreasing order of importance:
SMT Santiago, Simferopol, Singapore, Stanley;
TBMT Tbilisi;
TMT Tallinn, Tehran;
- WMT Warsaw;
- ZMT Zomba.</small>
+ WMT Warsaw.</small>
</p>
<p>
@@ -791,7 +791,7 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
with days starting at midnight.
Although <abbr>UT</abbr> equals <abbr>UTC</abbr> for modern
timestamps, <abbr>UTC</abbr> was not defined until 1960, so
- commentary uses the more-general abbreviation <abbr>UT</abbr> for
+ commentary uses the more general abbreviation <abbr>UT</abbr> for
timestamps that might predate 1960.
Since <abbr>UT</abbr>, <abbr>UT1</abbr>, etc. disagree slightly,
and since pre-1972 <abbr>UTC</abbr> seconds varied in length,
@@ -818,7 +818,8 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
<li>
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 after 1972.
+ seconds</a>) and <abbr>UTC</abbr> is not agreed upon.
+ This affects time stamps during the leap second era (1972&ndash;2035).
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
@@ -877,7 +878,7 @@ an older <code>zic</code>.
is error-prone in practice.
Also, POSIX <code>TZ</code> strings cannot deal with daylight
saving time rules not based on the Gregorian calendar (as in
- Iran), or with situations where more than two time zone
+ Morocco), or with situations where more than two time zone
abbreviations or <abbr>UT</abbr> offsets are used in an area.
</p>
@@ -913,8 +914,8 @@ an older <code>zic</code>.
<dt><var>date</var>[<code>/</code><var>time</var>]<code>,</code><var>date</var>[<code>/</code><var>time</var>]</dt><dd>
specifies the beginning and end of <abbr>DST</abbr>.
If this is absent, the system supplies its own ruleset
- for <abbr>DST</abbr>, and its rules can differ from year to year;
- typically <abbr>US</abbr> <abbr>DST</abbr> rules are used.
+ for <abbr>DST</abbr>, typically current <abbr>US</abbr>
+ <abbr>DST</abbr> rules.
</dd>
<dt><var>time</var></dt><dd>
takes the form
@@ -974,10 +975,11 @@ an older <code>zic</code>.
Traditionally the current <abbr>US</abbr> <abbr>DST</abbr> rules
were used to interpret such values, but this meant that the
<abbr>US</abbr> <abbr>DST</abbr> rules were compiled into each
- program that did time conversion. This meant that when
+ time conversion package, and when
<abbr>US</abbr> time conversion rules changed (as in the United
- States in 1987), all programs that did time conversion had to be
- recompiled to ensure proper results.
+ States in 1987 and again in 2007), all packages that
+ interpreted <code>TZ</code> values had to be updated
+ to ensure proper results.
</li>
<li>
The <code>TZ</code> environment variable is process-global, which
@@ -1173,7 +1175,7 @@ The vestigial <abbr>API</abbr>s are:
</li>
<li>
The functions that are conditionally compiled
- if <code>STD_INSPIRED</code> is defined should, at this point, be
+ if <code>STD_INSPIRED</code> is nonzero should, at this point, be
looked on primarily as food for thought.
They are not in any sense "standard compatible" &ndash; some are
not, in fact, specified in <em>any</em> standard.
@@ -1240,7 +1242,7 @@ The <code><abbr>tz</abbr></code> code and data supply the following interfaces:
Interface changes in a release attempt to preserve compatibility with
recent releases.
For example, <code><abbr>tz</abbr></code> data files typically do not
-rely on recently-added <code>zic</code> features, so that users can
+rely on recently added <code>zic</code> features, so that users can
run older <code>zic</code> versions to process newer data files.
<a href="tz-link.html#download">Downloading
the <code><abbr>tz</abbr></code> database</a> describes how releases
@@ -1269,6 +1271,18 @@ between now and the future time.
<section>
<h2 id="leapsec">Leap seconds</h2>
<p>
+Leap seconds were introduced in 1972 to accommodate the
+difference between atomic time and the less regular rotation of the earth.
+Unfortunately they caused so many problems with civil
+timekeeping that they
+are <a href="https://www.bipm.org/en/cgpm-2022/resolution-4">planned
+to be discontinued by 2035</a>, with some as-yet-undetermined
+mechanism replacing them, perhaps after the year 2135.
+Despite their impending obsolescence, a record of leap seconds is still
+needed to resolve timestamps from 1972 through 2035.
+</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
@@ -1282,12 +1296,12 @@ 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
+and systems needing more precise UTC can use this package's leap
second support directly.
</p>
<p>
-The directly-supported mechanism assumes that <code>time_t</code>
+The directly supported mechanism 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>
@@ -1348,7 +1362,15 @@ They sometimes disagree.
</section>
<section>
- <h2 id="planets">Time and time zones on other planets</h2>
+ <h2 id="planets">Time and time zones off Earth</h2>
+<p>
+The European Space Agency is <a
+href='https://www.esa.int/Applications/Navigation/Telling_time_on_the_Moon'>considering</a>
+the establishment of a reference timescale for the Moon, which has
+days roughly equivalent to 29.5 Earth days, and where relativistic
+effects cause clocks to tick slightly faster than on Earth.
+</p>
+
<p>
Some people's work schedules have used
<a href="https://en.wikipedia.org/wiki/Timekeeping_on_Mars">Mars time</a>.
diff --git a/contrib/tzcode/time2posix.3 b/contrib/tzcode/time2posix.3
index 6959c890a65b..f4e4ffdc6590 100644
--- a/contrib/tzcode/time2posix.3
+++ b/contrib/tzcode/time2posix.3
@@ -1,8 +1,5 @@
.\" This file is in the public domain, so clarified as of
.\" 1996-06-05 by Arthur David Olson.
-.\"
-.\" $FreeBSD$
-.\"
.Dd December 15, 2022
.Dt TIME2POSIX 3
.Os
diff --git a/contrib/tzcode/tz-art.html b/contrib/tzcode/tz-art.html
index 567953415f63..c86c186c09f9 100644
--- a/contrib/tzcode/tz-art.html
+++ b/contrib/tzcode/tz-art.html
@@ -478,22 +478,35 @@ Supernaw.</td></tr>
<tr><td>Total Time</td><td>1:16:20</td></tr>
<tr><td><a href="https://www.allmusic.com/album/chicago-transit-authority-mw0000189364">AMG Rating</a></td><td>4 stars</td></tr>
<tr><td>Notes</td><td>Includes the song "Does Anybody Really Know What Time It Is?"</td></tr>
+<tr><td>&nbsp;</td><td></td></tr>
+<tr><td>Artist</td><td>Emanuele Arciuli</td></tr>
+<tr><td>Composer</td><td>William Duckworth</td></tr>
+<tr><td>CD</td><td><a href="https://neumarecords.org/ols/products/william-duckworth-the-time-curve-preludes">The Time Curve Preludes</a></td></tr>
+<tr><td>Copyright Date</td><td>2023</td></tr>
+<tr><td>Label</td><td>Neuma</td></tr>
+<tr><td>Total Time</td><td>44:46</td></tr>
+<tr><td>Notes</td><td>The first work of postminimal music. Unlike minimalism, it does not assume that the listener has plenty of time.</td></tr>
</table>
<h2>Comics</h2>
<ul>
<li>
-The webcomic <em>xkcd</em> has the strip
-"<a href="https://xkcd.com/673/">The Sun</a>" (2009-12-09) and the panels
+The webcomic <em>xkcd</em> has the strips
+"<a href="https://xkcd.com/673/">The Sun</a>" (2009-12-09),
+"<a href="https://xkcd.com/1655/">Doomsday Clock</a>" (2016-03-14) and
+"<a href="https://xkcd.com/2549/">Edge Cake</a>" (2021-12-01),
+along with the panels
+"<a href="https://xkcd.com/448/">Good Morning</a>" (2008-07-11),
"<a href="https://xkcd.com/1017/">Backward in Time</a>" (2012-02-14),
"<a href="https://xkcd.com/1061/">EST</a>" (2012-05-28),
"<a href="https://xkcd.com/1179/">ISO 8601</a>" (2013-02-27),
"<a href="https://xkcd.com/1335/">Now</a>" (2014-02-26),
-"<a href="https://xkcd.com/1655/">Doomsday Clock</a>" (2016-03-14),
"<a href="https://xkcd.com/1799/">Bad Map Projection: Time Zones</a>"
(2017-02-15),
"<a href="https://xkcd.com/1883/">Supervillain Plan</a>" (2017-08-30),
"<a href="https://xkcd.com/2050/">6/6 Time</a>" (2018-09-24),
-and "<a href="https://xkcd.com/2266/">Leap Smearing</a>" (2020-02-10).
+"<a href="https://xkcd.com/2092/">Consensus New Year</a>" (2018-12-31),
+"<a href="https://xkcd.com/2266/">Leap Smearing</a>" (2020-02-10),
+and "<a href="https://xkcd.com/2594/">Consensus Time</a>" (2022-03-16).
The related book <em>What If?</em> has an entry
"<a href="https://what-if.xkcd.com/26/">Leap Seconds</a>" (2012-12-31).
</li>
diff --git a/contrib/tzcode/tz-how-to.html b/contrib/tzcode/tz-how-to.html
index e1e28f2e257d..9e438f93092a 100644
--- a/contrib/tzcode/tz-how-to.html
+++ b/contrib/tzcode/tz-how-to.html
@@ -548,8 +548,8 @@ a <code>SAVE</code> of zero.
<ul>
<li>The <a href="https://en.wikipedia.org/wiki/Tz_database">tz
-database</a> gives abbreviations for time zones in <i>popular
-usage</i>, which is not necessarily &ldquo;correct&rdquo; by law. For
+database</a> gives abbreviations for time zones
+in popular English-language usage. For
example, the last line in
<code>Zone</code> <code>Pacific/Honolulu</code> (shown below) gives
&ldquo;HST&rdquo; for &ldquo;Hawaii standard time&rdquo; even though the
@@ -567,7 +567,7 @@ the abbreviations. They are intended to be the values returned through the
function in the
<a href="https://kirste.userpage.fu-berlin.de/chemnet/use/info/libc/libc_19.html#SEC324">&ldquo;C&rdquo; locale</a>.
-<li>If there is no generally-accepted abbreviation for a time zone,
+<li>If there is no generally accepted abbreviation for a time zone,
a numeric offset is used instead, e.g., <code>+07</code> for 7 hours
ahead of Greenwich. By convention, <code>-00</code> is used in a
zone while uninhabited, where the offset is zero but in some sense
diff --git a/contrib/tzcode/tz-link.html b/contrib/tzcode/tz-link.html
index d3b37664c71c..43190dd7efcd 100644
--- a/contrib/tzcode/tz-link.html
+++ b/contrib/tzcode/tz-link.html
@@ -26,6 +26,7 @@ area.
<li><a href="#tzdb">The <code><abbr>tz</abbr></code> database</a></li>
<li><a href="#download">Downloading the <code><abbr>tz</abbr></code> database</a></li>
<li><a href="#changes">Changes to the <code><abbr>tz</abbr></code> database</a></li>
+ <li><a href="#coordinating">Coordinating with governments and distributors</a></li>
<li><a href="#commentary">Commentary on the <code><abbr>tz</abbr></code> database</a></li>
</ul>
</li>
@@ -169,14 +170,14 @@ through <samp>zzz</samp>, and so on).
Since version 2022a, each release has been distributed in
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06">POSIX
ustar interchange format</a>, compressed as described above;
-older releases use a nearly-compatible format.
+older releases use a nearly compatible format.
Since version 2016h, each release has contained a text file named
"<samp>version</samp>" whose first (and currently only) line is the version.
Older releases are <a href="https://ftp.iana.org/tz/releases/">archived</a>,
and are also available in an
<a href="ftp://ftp.iana.org/tz/releases/"><abbr
title="File Transfer Protocol">FTP</abbr> directory</a> via a
-less-secure protocol.</p>
+less secure protocol.</p>
<p>Alternatively, a development repository of code and data can be
retrieved from <a href="https://github.com">GitHub</a> via the shell
command:</p>
@@ -215,23 +216,6 @@ discussions</a> and corresponding data changes can be
generated <a href="https://github.com/timparenti/tzdata-meta">automatically</a>.
</p>
<p>
-If your government plans to change its time zone boundaries or
-daylight saving rules, inform <code>tz@iana.org</code> well in
-advance, as this will coordinate updates to many cell phones,
-computers, and other devices around the world.
-The change should be officially announced at least a year before it affects
-how clocks operate; otherwise, there is a good chance that some
-clocks will operate incorrectly after the change, due
-to delays in propagating updates to software and data. The shorter
-the notice, the more likely clock problems will arise; see "<a
-href="https://codeofmatt.com/2016/04/23/on-the-timing-of-time-zone-changes/">On
-the Timing of Time Zone Changes</a>" for examples.
-The <code><abbr>tz</abbr></code> data can represent planned changes
-far into the future, and a long-planned change can easily be reverted
-or otherwise altered with a year's notice before the change would have
-affected clocks.
-</p>
-<p>
Changes to the <code><abbr>tz</abbr></code> code and data are often
propagated to clients via operating system updates, so
client <code><abbr>tz</abbr></code> data can often be corrected by
@@ -287,6 +271,55 @@ displays changes between recent <code><abbr>tzdb</abbr></code> versions.
</section>
<section>
+<h2 id="coordinating">Coordinating with governments and distributors</h2>
+<p>
+As discussed in
+"<a href="https://www.icann.org/en/blogs/details/how-time-zones-are-coordinated-13-03-2023-en">How
+Time Zones Are Coordinated</a>", the time zone database relies on
+collaboration among governments, the time zone database volunteer
+community, and data distributors downstream.
+<p>
+If your government plans to change its time zone boundaries or
+daylight saving rules, please send email to <a
+href="mailto:tz@iana.org"><code>tz@iana.org</code></a> well in advance,
+as this will lessen confusion and will coordinate updates to many cell phones,
+computers, and other devices around the world.
+In your email, please cite the legislation or regulation that specifies
+the change, so that it can be checked for details such as the exact times
+when clock transitions occur.
+It is OK if a rule change is planned to affect clocks
+far into the future, as a long-planned change can easily be reverted
+or otherwise altered with a year's notice before the change would have
+affected clocks.</p>
+<p>
+There is no fixed schedule for <code><abbr>tzdb</abbr></code> releases.
+However, typically a release occurs every few months.
+Many downstream timezone data distributors wait for
+a <code><abbr>tzdb</abbr></code> release before they produce an update
+to time zone behavior in consumer devices and software products.
+After a release, various parties must integrate, test,
+and roll out an update before <a
+href="https://en.wikipedia.org/wiki/End_user">end users</a> see changes.
+These updates can be expensive, for both the <a
+href="https://en.wikipedia.org/wiki/Quality_assurance">quality
+assurance</a> process and the overall cost of shipping and installing
+updates to each device's copy of <code><abbr>tzdb</abbr></code>.
+Updates may be batched with other updates and may take substantial
+time to reach end users after a release.
+Older devices may no longer be supported and thus may never be updated,
+which means they will continue to use out-of-date rules.</p>
+<p>
+For these reasons any rule change should be promulgated at least a
+year before it affects how clocks operate; otherwise, there is a good
+chance that many clocks will be wrong due to delays in propagating updates,
+and that residents will be confused or even actively resist the change.
+The shorter the notice, the more likely clock problems will arise; see "<a
+href="https://codeofmatt.com/2016/04/23/on-the-timing-of-time-zone-changes/">On
+the Timing of Time Zone Changes</a>" for examples.
+</p>
+</section>
+
+<section>
<h2 id="commentary">Commentary on the <code><abbr>tz</abbr></code> database</h2>
<ul>
<li>The article
@@ -384,7 +417,7 @@ running the command <code>make rearguard_tarballs</code> and compiling
from the resulting tarballs instead.</p>
<ul>
<li><a href="https://sourceforge.net/projects/vzic/">Vzic</a> is a <a
-href="https://en.wikipedia.org/wiki/C_%28programming_language%29">C</a>
+href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a>
program that compiles
<code><abbr>tz</abbr></code> source into iCalendar-compatible VTIMEZONE files.
Vzic is freely
@@ -409,7 +442,7 @@ License. DateTime::TimeZone also contains a script
transition in the <code><abbr>tz</abbr></code> database.</li>
<li>The <a href="https://howardhinnant.github.io/date/tz.html">Time Zone
Database Parser</a> is a
-<a href="https://en.wikipedia.org/wiki/C%2B%2B">C++</a> parser and
+<a href="https://en.wikipedia.org/wiki/C++">C++</a> parser and
runtime library with <a
href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0355r7.html">API</a>
adopted by
@@ -419,7 +452,7 @@ It is freely available under the
<abbr title="Massachusetts Institute of Technology">MIT</abbr> license.</li>
<li><a id="ICU" href="https://icu.unicode.org">International Components for
Unicode (<abbr>ICU</abbr>)</a> contains C/C++ and <a
-href="https://en.wikipedia.org/wiki/Java_%28programming_language%29">Java</a>
+href="https://en.wikipedia.org/wiki/Java_(programming_language)">Java</a>
libraries for internationalization that
has a compiler from <code><abbr>tz</abbr></code> source
and from <abbr title="Common Locale Data Repository">CLDR</abbr> data
@@ -903,6 +936,10 @@ covers the history of local time in the Netherlands from ancient times.</dd>
<dd>The Department of Internal Affairs maintains a brief <a
href="https://www.dia.govt.nz/Daylight-Saving-History">History of
Daylight Saving</a>.</dd>
+<dt>Palestine</dt>
+<dd>The Ministry of Telecom and IT publishes a <a
+href="https://mtit.pna.ps/Site/TimeZoon"
+hreflang="ar">history of clock changes (in Arabic)</a>.</dd>
<dt>Portugal</dt>
<dd>The Lisbon Astronomical Observatory publishes a
<a href="https://oal.ul.pt/hora-legal/" hreflang="pt">history of
@@ -978,7 +1015,7 @@ href="http://leapsecond.com/hpan/an1289.pdf">The
Science of Timekeeping</a> is a thorough introduction
to the theory and practice of precision timekeeping.</li>
<li><a href="https://doi.org/10.1007/978-3-319-59909-0">The Science of
-Time 2016</a> contains several freely-readable papers.</li>
+Time 2016</a> contains several freely readable papers.</li>
<li><a href="https://www.ntp.org"><abbr
title="Network Time Protocol">NTP</abbr>: The Network
Time Protocol</a> (Internet <abbr>RFC</abbr> 5905)
@@ -1050,7 +1087,7 @@ and to
In practice the two configurations also agree for timestamps before
1972 even though the historical situation is messy, partly because
neither <abbr>UTC</abbr> nor <abbr>TAI</abbr>
-is well-defined for sufficiently-old timestamps.</li>
+is well-defined for sufficiently old timestamps.</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
@@ -1078,8 +1115,12 @@ leap second: its history and possible future</a>.
<a href="https://www.ucolick.org/~sla/leapsecs/"><abbr>UTC</abbr>
might be redefined
without Leap Seconds</a> gives pointers on this
-contentious issue, which was active until 2015 and could become active
-again.</li>
+contentious issue.
+The General Conference on Weights and Measures
+<a href="https://www.bipm.org/en/cgpm-2022/resolution-4">voted in 2022</a>
+to discontinue the use of leap seconds by 2035, replacing them with an
+as-yet-undetermined scheme some time after the year 2135.
+</li>
</ul>
</section>
diff --git a/contrib/tzcode/tzfile.5 b/contrib/tzcode/tzfile.5
index b53abaab18d6..d0ca730f2c96 100644
--- a/contrib/tzcode/tzfile.5
+++ b/contrib/tzcode/tzfile.5
@@ -1,8 +1,5 @@
.\" This file is in the public domain, so clarified as of
.\" 1996-06-05 by Arthur David Olson.
-.\"
-.\" $FreeBSD$
-.\"
.Dd December 15, 2022
.Dt TZFILE 5
.Os
@@ -207,7 +204,7 @@ if there is no POSIX-style representation for such instants.
If nonempty, the POSIX-style TZ string must agree with the local time
type after the last transition time if present in the eight-byte data;
for example, given the string
-.Dq "WET0WEST,M3.5.0,M10.5.0/3"
+.Dq "WET0WEST,M3.5.0/1,M10.5.0"
then if a last transition time is in July, the transition's local time
type must specify a daylight-saving time abbreviated
.Dq "WEST"
diff --git a/contrib/tzcode/tzfile.h b/contrib/tzcode/tzfile.h
index e59d2ea4bb47..3764f36d4d92 100644
--- a/contrib/tzcode/tzfile.h
+++ b/contrib/tzcode/tzfile.h
@@ -105,20 +105,24 @@ struct tzhead {
*/
#ifndef TZ_MAX_TIMES
+/* This must be at least 242 for Europe/London with 'zic -b fat'. */
# define TZ_MAX_TIMES 2000
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
-/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */
+/* This must be at least 18 for Europe/Vilnius with 'zic -b fat'. */
# define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
#endif /* !defined TZ_MAX_TYPES */
#ifndef TZ_MAX_CHARS
+/* This must be at least 40 for America/Anchorage. */
# define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
/* (limited by what unsigned chars can hold) */
#endif /* !defined TZ_MAX_CHARS */
#ifndef TZ_MAX_LEAPS
+/* This 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 */
#endif /* !defined TZ_MAX_LEAPS */
diff --git a/contrib/tzcode/tzselect.8 b/contrib/tzcode/tzselect.8
index 846b867be1c0..4578090f9ea7 100644
--- a/contrib/tzcode/tzselect.8
+++ b/contrib/tzcode/tzselect.8
@@ -1,6 +1,6 @@
.\" This file is in the public domain, so clarified as of
.\" 2009-05-17 by Arthur David Olson.
-.TH TZSELECT 8
+.TH tzselect 8 "" "Time Zone Database"
.SH NAME
tzselect \- select a timezone
.SH SYNOPSIS
diff --git a/contrib/tzcode/tzselect.ksh b/contrib/tzcode/tzselect.ksh
index 28c32a2430f8..9a91acfc7412 100644
--- a/contrib/tzcode/tzselect.ksh
+++ b/contrib/tzcode/tzselect.ksh
@@ -39,7 +39,7 @@ REPORT_BUGS_TO=tz@iana.org
: ${AWK=awk}
: ${TZDIR=`pwd`}
-# Output one argument as-is to standard output.
+# Output one argument as-is to standard output, with trailing newline.
# Safer than 'echo', which can mishandle '\' or leading '-'.
say() {
printf '%s\n' "$1"
@@ -82,8 +82,8 @@ Report bugs to $REPORT_BUGS_TO."
# Ask the user to select from the function's arguments,
# and assign the selected argument to the variable 'select_result'.
-# Exit on EOF or I/O error. Use the shell's 'select' builtin if available,
-# falling back on a less-nice but portable substitute otherwise.
+# Exit on EOF or I/O error. Use the shell's nicer 'select' builtin if
+# available, falling back on a portable substitute otherwise.
if
case $BASH_VERSION in
?*) : ;;
@@ -197,16 +197,65 @@ newline='
'
IFS=$newline
+# Awk script to output a country list.
+output_country_list='
+ BEGIN { FS = "\t" }
+ /^#$/ { next }
+ /^#[^@]/ { next }
+ {
+ commentary = $0 ~ /^#@/
+ if (commentary) {
+ col1ccs = substr($1, 3)
+ conts = $2
+ } else {
+ col1ccs = $1
+ conts = $3
+ }
+ ncc = split(col1ccs, cc, /,/)
+ ncont = split(conts, cont, /,/)
+ for (i = 1; i <= ncc; i++) {
+ elsewhere = commentary
+ for (ci = 1; ci <= ncont; ci++) {
+ if (cont[ci] ~ continent_re) {
+ if (!cc_seen[cc[i]]++) cc_list[++ccs] = cc[i]
+ elsewhere = 0
+ }
+ }
+ if (elsewhere) {
+ for (i = 1; i <= ncc; i++) {
+ cc_elsewhere[cc[i]] = 1
+ }
+ }
+ }
+ }
+ END {
+ while (getline <TZ_COUNTRY_TABLE) {
+ if ($0 !~ /^#/) cc_name[$1] = $2
+ }
+ for (i = 1; i <= ccs; i++) {
+ country = cc_list[i]
+ if (cc_elsewhere[country]) continue
+ if (cc_name[country]) {
+ country = cc_name[country]
+ }
+ print country
+ }
+ }
+'
# Awk script to read a time zone table and output the same table,
-# with each column preceded by its distance from 'here'.
-output_distances='
+# with each row preceded by its distance from 'here'.
+# If output_times is set, each row is instead preceded by its local time
+# and any apostrophes are escaped for the shell.
+output_distances_or_times='
BEGIN {
FS = "\t"
- while (getline <TZ_COUNTRY_TABLE)
- if ($0 ~ /^[^#]/)
- country[$1] = $2
- country["US"] = "US" # Otherwise the strings get too long.
+ if (!output_times) {
+ while (getline <TZ_COUNTRY_TABLE)
+ if ($0 ~ /^[^#]/)
+ country[$1] = $2
+ country["US"] = "US" # Otherwise the strings get too long.
+ }
}
function abs(x) {
return x < 0 ? -x : x;
@@ -268,18 +317,35 @@ output_distances='
coord_long = convert_longitude(coord)
}
/^[^#]/ {
- here_lat = convert_latitude($2)
- here_long = convert_longitude($2)
+ inline[inlines++] = $0
+ ncc = split($1, cc, /,/)
+ for (i = 1; i <= ncc; i++)
+ cc_used[cc[i]]++
+ }
+ END {
+ for (h = 0; h < inlines; h++) {
+ $0 = inline[h]
line = $1 "\t" $2 "\t" $3
sep = "\t"
ncc = split($1, cc, /,/)
+ split("", item_seen)
+ item_seen[""] = 1
for (i = 1; i <= ncc; i++) {
- line = line sep country[cc[i]]
- sep = ", "
+ item = cc_used[cc[i]] <= 1 ? country[cc[i]] : $4
+ if (item_seen[item]++) continue
+ line = line sep item
+ sep = "; "
+ }
+ if (output_times) {
+ fmt = "TZ='\''%s'\'' date +'\''%d %%Y %%m %%d %%H:%%M %%a %%b\t%s'\''\n"
+ gsub(/'\''/, "&\\\\&&", line)
+ printf fmt, $3, h, line
+ } else {
+ here_lat = convert_latitude($2)
+ here_long = convert_longitude($2)
+ printf "%g\t%s\n", dist(coord_lat, coord_long, here_lat, here_long), line
}
- if (NF == 4)
- line = line " - " $4
- printf "%g\t%s\n", dist(coord_lat, coord_long, here_lat, here_long), line
+ }
}
'
@@ -300,7 +366,7 @@ while
# Ask the user for continent or ocean.
- echo >&2 'Please select a continent, ocean, "coord", or "TZ".'
+ echo >&2 'Please select a continent, ocean, "coord", "TZ", or "time".'
quoted_continents=`
$AWK '
@@ -331,7 +397,8 @@ while
eval '
doselect '"$quoted_continents"' \
"coord - I want to use geographical coordinates." \
- "TZ - I want to specify the timezone using the Posix TZ format."
+ "TZ - I want to specify the timezone using the Posix TZ format." \
+ "time - I know local time already."
continent=$select_result
case $continent in
Americas) continent=America;;
@@ -384,74 +451,99 @@ while
distance_table=`$AWK \
-v coord="$coord" \
-v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
- "$output_distances" <"$TZ_ZONE_TABLE" |
+ "$output_distances_or_times" <"$TZ_ZONE_TABLE" |
sort -n |
sed "${location_limit}q"
`
- regions=`say "$distance_table" | $AWK '
- BEGIN { FS = "\t" }
- { print $NF }
+ regions=`$AWK \
+ -v distance_table="$distance_table" '
+ BEGIN {
+ nlines = split(distance_table, line, /\n/)
+ for (nr = 1; nr <= nlines; nr++) {
+ nf = split(line[nr], f, /\t/)
+ print f[nf]
+ }
+ }
'`
- echo >&2 'Please select one of the following timezones,' \
+ echo >&2 'Please select one of the following timezones,'
echo >&2 'listed roughly in increasing order' \
"of distance from $coord".
doselect $regions
region=$select_result
- TZ=`say "$distance_table" | $AWK -v region="$region" '
- BEGIN { FS="\t" }
- $NF == region { print $4 }
+ TZ=`$AWK \
+ -v distance_table="$distance_table" \
+ -v region="$region" '
+ BEGIN {
+ nlines = split(distance_table, line, /\n/)
+ for (nr = 1; nr <= nlines; nr++) {
+ nf = split(line[nr], f, /\t/)
+ if (f[nf] == region) {
+ print f[4]
+ }
+ }
+ }
'`
;;
*)
- # Get list of names of countries in the continent or ocean.
- countries=`$AWK \
+ case $continent in
+ time)
+ minute_format='%a %b %d %H:%M'
+ old_minute=`TZ=UTC0 date +"$minute_format"`
+ for i in 1 2 3
+ do
+ time_table_command=`
+ $AWK -v output_times=1 \
+ "$output_distances_or_times" <"$TZ_ZONE_TABLE"
+ `
+ time_table=`eval "$time_table_command"`
+ new_minute=`TZ=UTC0 date +"$minute_format"`
+ case $old_minute in
+ "$new_minute") break;;
+ esac
+ old_minute=$new_minute
+ done
+ echo >&2 "The system says Universal Time is $new_minute."
+ echo >&2 "Assuming that's correct, what is the local time?"
+ eval doselect `
+ say "$time_table" |
+ sort -k2n -k2,5 -k1n |
+ $AWK '{
+ line = $6 " " $7 " " $4 " " $5
+ if (line == oldline) next
+ oldline = line
+ gsub(/'\''/, "&\\\\&&", line)
+ printf "'\''%s'\''\n", line
+ }'
+ `
+ time=$select_result
+ zone_table=`
+ say "$time_table" |
+ $AWK -v time="$time" '{
+ if ($6 " " $7 " " $4 " " $5 == time) {
+ sub(/[^\t]*\t/, "")
+ print
+ }
+ }'
+ `
+ countries=`
+ say "$zone_table" |
+ $AWK \
+ -v continent_re='' \
+ -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
+ "$output_country_list" |
+ sort -f
+ `
+ ;;
+ *)
+ zone_table=file
+ # Get list of names of countries in the continent or ocean.
+ countries=`$AWK \
-v continent_re="^$continent/" \
-v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
- '
- BEGIN { FS = "\t" }
- /^#$/ { next }
- /^#[^@]/ { next }
- {
- commentary = $0 ~ /^#@/
- if (commentary) {
- col1ccs = substr($1, 3)
- conts = $2
- } else {
- col1ccs = $1
- conts = $3
- }
- ncc = split(col1ccs, cc, /,/)
- ncont = split(conts, cont, /,/)
- for (i = 1; i <= ncc; i++) {
- elsewhere = commentary
- for (ci = 1; ci <= ncont; ci++) {
- if (cont[ci] ~ continent_re) {
- if (!cc_seen[cc[i]]++) cc_list[++ccs] = cc[i]
- elsewhere = 0
- }
- }
- if (elsewhere) {
- for (i = 1; i <= ncc; i++) {
- cc_elsewhere[cc[i]] = 1
- }
- }
- }
- }
- END {
- while (getline <TZ_COUNTRY_TABLE) {
- if ($0 !~ /^#/) cc_name[$1] = $2
- }
- for (i = 1; i <= ccs; i++) {
- country = cc_list[i]
- if (cc_elsewhere[country]) continue
- if (cc_name[country]) {
- country = cc_name[country]
- }
- print country
- }
- }
- ' <"$TZ_ZONE_TABLE" | sort -f`
-
+ "$output_country_list" \
+ <"$TZ_ZONE_TABLE" | sort -f
+ `;;
+ esac
# If there's more than one country, ask the user which one.
case $countries in
@@ -459,6 +551,7 @@ while
echo >&2 'Please select a country' \
'whose clocks agree with yours.'
doselect $countries
+ country_result=$select_result
country=$select_result;;
*)
country=$countries
@@ -466,10 +559,15 @@ while
# Get list of timezones in the country.
- regions=`$AWK \
+ regions=`
+ case $zone_table in
+ file) cat -- "$TZ_ZONE_TABLE";;
+ *) say "$zone_table";;
+ esac |
+ $AWK \
-v country="$country" \
-v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
- '
+ '
BEGIN {
FS = "\t"
cc = country
@@ -482,7 +580,8 @@ while
}
/^#/ { next }
$1 ~ cc { print $4 }
- ' <"$TZ_ZONE_TABLE"`
+ '
+ `
# If there's more than one region, ask the user which one.
@@ -490,17 +589,20 @@ while
*"$newline"*)
echo >&2 'Please select one of the following timezones.'
doselect $regions
- region=$select_result;;
- *)
- region=$regions
+ region=$select_result
esac
# Determine TZ from country and region.
- TZ=`$AWK \
+ TZ=`
+ case $zone_table in
+ file) cat -- "$TZ_ZONE_TABLE";;
+ *) say "$zone_table";;
+ esac |
+ $AWK \
-v country="$country" \
-v region="$region" \
-v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
- '
+ '
BEGIN {
FS = "\t"
cc = country
@@ -512,8 +614,9 @@ while
}
}
/^#/ { next }
- $1 ~ cc && $4 == region { print $3 }
- ' <"$TZ_ZONE_TABLE"`
+ $1 ~ cc && ($4 == region || !region) { print $3 }
+ '
+ `;;
esac
# Make sure the corresponding zoneinfo file exists.
@@ -549,17 +652,21 @@ Universal Time is now: $UTdate."
# Output TZ info and ask the user to confirm.
echo >&2 ""
- echo >&2 "The following information has been given:"
+ echo >&2 "Based on the following information:"
echo >&2 ""
- case $country%$region%$coord in
- ?*%?*%) say >&2 " $country$newline $region";;
- ?*%%) say >&2 " $country";;
- %?*%?*) say >&2 " coord $coord$newline $region";;
- %%?*) say >&2 " coord $coord";;
+ case $time%$country_result%$region%$coord in
+ ?*%?*%?*%)
+ say >&2 " $time$newline $country_result$newline $region";;
+ ?*%?*%%|?*%%?*%) say >&2 " $time$newline $country_result$region";;
+ ?*%%%) say >&2 " $time";;
+ %?*%?*%) say >&2 " $country_result$newline $region";;
+ %?*%%) say >&2 " $country_result";;
+ %%?*%?*) say >&2 " coord $coord$newline $region";;
+ %%%?*) say >&2 " coord $coord";;
*) say >&2 " TZ='$TZ'"
esac
say >&2 ""
- say >&2 "Therefore TZ='$TZ' will be used.$extra_info"
+ say >&2 "TZ='$TZ' will be used.$extra_info"
say >&2 "Is the above information OK?"
doselect Yes No
diff --git a/contrib/tzcode/version b/contrib/tzcode/version
index b74fa117a223..7daa77e00d99 100644
--- a/contrib/tzcode/version
+++ b/contrib/tzcode/version
@@ -1 +1 @@
-2022g
+2023c
diff --git a/contrib/tzcode/zdump.8 b/contrib/tzcode/zdump.8
index 0b9e956526cc..7a78f6b9c040 100644
--- a/contrib/tzcode/zdump.8
+++ b/contrib/tzcode/zdump.8
@@ -1,8 +1,5 @@
.\" This file is in the public domain, so clarified as of
.\" 2009-05-17 by Arthur David Olson.
-.\"
-.\" $FreeBSD$
-.\"
.Dd December 15, 2022
.Dt ZDUMP 8
.Os
diff --git a/contrib/tzcode/zdump.c b/contrib/tzcode/zdump.c
index e4ac81cc220c..74ba0639633d 100644
--- a/contrib/tzcode/zdump.c
+++ b/contrib/tzcode/zdump.c
@@ -15,7 +15,7 @@
#include <stdio.h>
#ifndef HAVE_SNPRINTF
-# define HAVE_SNPRINTF (199901 <= __STDC_VERSION__)
+# define HAVE_SNPRINTF (!PORT_TO_C89 || 199901 <= __STDC_VERSION__)
#endif
#ifndef HAVE_LOCALTIME_R
@@ -89,7 +89,7 @@ static bool warned;
static bool errout;
static char const *abbr(struct tm const *);
-static intmax_t delta(struct tm *, struct tm *) ATTRIBUTE_REPRODUCIBLE;
+ATTRIBUTE_REPRODUCIBLE static intmax_t delta(struct tm *, struct tm *);
static void dumptime(struct tm const *);
static time_t hunt(timezone_t, time_t, time_t, bool);
static void show(timezone_t, char *, time_t, bool);
@@ -97,7 +97,7 @@ static void showextrema(timezone_t, char *, time_t, struct tm *, time_t);
static void showtrans(char const *, struct tm const *, time_t, char const *,
char const *);
static const char *tformat(void);
-static time_t yeartot(intmax_t) ATTRIBUTE_REPRODUCIBLE;
+ATTRIBUTE_REPRODUCIBLE static time_t yeartot(intmax_t);
/* Is C an ASCII digit? */
static bool
@@ -125,7 +125,7 @@ is_alpha(char a)
}
}
-static ATTRIBUTE_NORETURN void
+ATTRIBUTE_NORETURN static void
size_overflow(void)
{
fprintf(stderr, _("%s: size overflow\n"), progname);
@@ -133,25 +133,37 @@ size_overflow(void)
}
/* Return A + B, exiting if the result would overflow either ptrdiff_t
- or size_t. */
-static ATTRIBUTE_REPRODUCIBLE size_t
-sumsize(size_t a, size_t b)
+ or size_t. A and B are both nonnegative. */
+ATTRIBUTE_REPRODUCIBLE static ptrdiff_t
+sumsize(ptrdiff_t a, ptrdiff_t b)
{
#ifdef ckd_add
- size_t sum;
- if (!ckd_add(&sum, a, b))
+ ptrdiff_t sum;
+ if (!ckd_add(&sum, a, b) && sum <= INDEX_MAX)
return sum;
#else
- if (a <= SIZE_MAX && b <= SIZE_MAX - a)
+ if (a <= INDEX_MAX && b <= INDEX_MAX - a)
return a + b;
#endif
size_overflow();
}
+/* Return the size of of the string STR, including its trailing NUL.
+ Report an error and exit if this would exceed INDEX_MAX which means
+ pointer subtraction wouldn't work. */
+static ptrdiff_t
+xstrsize(char const *str)
+{
+ size_t len = strlen(str);
+ if (len < INDEX_MAX)
+ return len + 1;
+ size_overflow();
+}
+
/* Return a pointer to a newly allocated buffer of size SIZE, exiting
- on failure. SIZE should be nonzero. */
-static void * ATTRIBUTE_MALLOC
-xmalloc(size_t size)
+ on failure. SIZE should be positive. */
+ATTRIBUTE_MALLOC static void *
+xmalloc(ptrdiff_t size)
{
void *p = malloc(size);
if (!p) {
@@ -216,7 +228,7 @@ localtime_r(time_t *tp, struct tm *tmp)
# undef localtime_rz
# define localtime_rz zdump_localtime_rz
static struct tm *
-localtime_rz(timezone_t rz __unused, time_t *tp, struct tm *tmp)
+localtime_rz(ATTRIBUTE_MAYBE_UNUSED timezone_t rz, time_t *tp, struct tm *tmp)
{
return localtime_r(tp, tmp);
}
@@ -241,7 +253,8 @@ tzalloc(char const *val)
{
# if HAVE_SETENV
if (setenv("TZ", val, 1) != 0) {
- perror("setenv");
+ char const *e = strerror(errno);
+ fprintf(stderr, _("%s: setenv: %s\n"), progname, e);
exit(EXIT_FAILURE);
}
tzset();
@@ -253,18 +266,18 @@ tzalloc(char const *val)
static ptrdiff_t fakeenv0size;
void *freeable = NULL;
char **env = fakeenv, **initial_environ;
- size_t valsize = strlen(val) + 1;
+ ptrdiff_t valsize = xstrsize(val);
if (fakeenv0size < valsize) {
char **e = environ, **to;
ptrdiff_t initial_nenvptrs = 1; /* Counting the trailing NULL pointer. */
while (*e++) {
# ifdef ckd_add
- if (ckd_add(&initial_nenvptrs, initial_envptrs, 1)
- || SIZE_MAX < initial_envptrs)
+ if (ckd_add(&initial_nenvptrs, initial_nenvptrs, 1)
+ || INDEX_MAX < initial_nenvptrs)
size_overflow();
# else
- if (initial_nenvptrs == min(PTRDIFF_MAX, SIZE_MAX) / sizeof *environ)
+ if (initial_nenvptrs == INDEX_MAX / sizeof *environ)
size_overflow();
initial_nenvptrs++;
# endif
@@ -291,7 +304,7 @@ tzalloc(char const *val)
}
static void
-tzfree(timezone_t initial_environ)
+tzfree(ATTRIBUTE_MAYBE_UNUSED timezone_t initial_environ)
{
# if !HAVE_SETENV
environ = initial_environ;
@@ -315,14 +328,16 @@ gmtzinit(void)
"Link GMT GMT0" line in the "backward" file, and which
should work on all POSIX platforms. The rest of zdump does not
use the "GMT" abbreviation that comes from this setting, so it
- is OK to use "GMT" here rather than the more-modern "UTC" which
+ is OK to use "GMT" here rather than the modern "UTC" which
would not work on platforms that omit the "backward" file. */
gmtz = tzalloc("GMT");
if (!gmtz) {
static char const gmt0[] = "GMT0";
gmtz = tzalloc(gmt0);
if (!gmtz) {
- perror(gmt0);
+ char const *e = strerror(errno);
+ fprintf(stderr, _("%s: unknown timezone '%s': %s\n"),
+ progname, gmt0, e);
exit(EXIT_FAILURE);
}
}
@@ -402,7 +417,7 @@ abbrok(const char *const abbrp, const char *const zone)
/* Return a time zone abbreviation. If the abbreviation needs to be
saved, use *BUF (of size *BUFALLOC) to save it, and return the
- abbreviation in the possibly-reallocated *BUF. Otherwise, just
+ abbreviation in the possibly reallocated *BUF. Otherwise, just
return the abbreviation. Get the abbreviation from TMP.
Exit on memory allocation failure. */
static char const *
@@ -412,13 +427,13 @@ saveabbr(char **buf, ptrdiff_t *bufalloc, struct tm const *tmp)
if (HAVE_LOCALTIME_RZ)
return ab;
else {
- size_t ablen = strlen(ab);
- if ((size_t)*bufalloc <= ablen) {
+ ptrdiff_t absize = xstrsize(ab);
+ if (*bufalloc < absize) {
free(*buf);
/* Make the new buffer at least twice as long as the old,
to avoid O(N**2) behavior on repeated calls. */
- *bufalloc = sumsize(*bufalloc, ablen + 1);
+ *bufalloc = sumsize(*bufalloc, absize);
*buf = xmalloc(*bufalloc);
}
@@ -587,7 +602,9 @@ main(int argc, char *argv[])
struct tm tm, newtm;
bool tm_ok;
if (!tz) {
- perror(argv[i]);
+ char const *e = strerror(errno);
+ fprintf(stderr, _("%s: unknown timezone '%s': %s\n"),
+ progname, argv[1], e);
return EXIT_FAILURE;
}
if (now) {
@@ -733,13 +750,9 @@ hunt(timezone_t tz, time_t lot, time_t hit, bool only_ok)
for ( ; ; ) {
/* T = average of LOT and HIT, rounding down.
- Avoid overflow, even on oddball C89 platforms
- where / rounds down and TIME_T_MIN == -TIME_T_MAX
- so lot / 2 + hit / 2 might overflow. */
- time_t t = (lot / 2
- - ((lot % 2 + hit % 2) < 0)
- + ((lot % 2 + hit % 2) == 2)
- + hit / 2);
+ Avoid overflow. */
+ int rem_sum = lot % 2 + hit % 2;
+ time_t t = (rem_sum == 2) - (rem_sum < 0) + lot / 2 + hit / 2;
if (t == lot)
break;
tm_ok = my_localtime_rz(tz, &t, &tm) != NULL;
@@ -921,7 +934,7 @@ showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi)
# include <stdarg.h>
/* A substitute for snprintf that is good enough for zdump. */
-static int ATTRIBUTE_FORMAT((printf, 3, 4))
+ATTRIBUTE_FORMAT((printf, 3, 4)) static int
my_snprintf(char *s, size_t size, char const *format, ...)
{
int n;
@@ -1174,7 +1187,7 @@ abbr(struct tm const *tmp)
static const char *
tformat(void)
{
-#if HAVE_GENERIC
+#if HAVE__GENERIC
/* C11-style _Generic is more likely to return the correct
format when distinct types have the same size. */
char const *fmt =
diff --git a/contrib/tzcode/zic.8 b/contrib/tzcode/zic.8
index 37d9a3abd418..d6ded3563ee1 100644
--- a/contrib/tzcode/zic.8
+++ b/contrib/tzcode/zic.8
@@ -1,8 +1,5 @@
.\" This file is in the public domain, so clarified as of
.\" 2009-05-17 by Arthur David Olson.
-.\"
-.\" $FreeBSD$
-.\"
.Dd January 21, 2023
.Dt ZIC 8
.Os
@@ -112,7 +109,11 @@ will act as if the input contained a link line of the form
Link \fItimezone\fP posixrules
.Ed
.Pp
-This feature is obsolete and poorly supported.
+Unless
+.Ar timezone
+is
+.Dq "\*-" ,
+this option is obsolete and poorly supported.
Among other things it should not be used for timestamps after the year 2037,
and it should not be combined with
.Fl b Cm slim
@@ -135,7 +136,7 @@ to timestamps in the range from
.Ar lo
and
.Ar hi
-are possibly-signed decimal counts of seconds since the Epoch
+are possibly signed decimal counts of seconds since the Epoch
(1970-01-01 00:00:00 UTC).
Omitted counts default to extreme values.
The output files use UT offset 0 and abbreviation
@@ -227,10 +228,10 @@ for
The output file does not contain all the information about the
long-term future of a timezone, because the future cannot be summarized as
an extended POSIX TZ string.
-For example, as of 2019 this problem
-occurs for Iran's daylight-saving rules for the predicted future, as
-these rules are based on the Iranian calendar, which cannot be
-represented.
+For example, as of 2023 this problem
+occurs for Morocco's daylight-saving rules, as these rules are based
+on predictions for when Ramadan will be observed, something that
+an extended POSIX TZ string cannot represent.
.It
The output contains data that may not be handled properly by client
code designed for older
diff --git a/contrib/tzcode/zic.c b/contrib/tzcode/zic.c
index c65282d46d27..55ce60315ffd 100644
--- a/contrib/tzcode/zic.c
+++ b/contrib/tzcode/zic.c
@@ -66,8 +66,10 @@ enum { FORMAT_LEN_GROWTH_BOUND = 5 };
# define MKDIR_UMASK 0755
#endif
-/* The minimum alignment of a type, for pre-C23 platforms. */
-#if __STDC_VERSION__ < 201112
+/* The minimum alignment of a type, for pre-C23 platforms.
+ The __SUNPRO_C test is because Oracle Developer Studio 12.6 lacks
+ <stdalign.h> even though __STDC_VERSION__ == 201112. */
+#if __STDC_VERSION__ < 201112 || defined __SUNPRO_C
# define alignof(type) offsetof(struct { char a; type b; }, b)
#elif __STDC_VERSION__ < 202311
# include <stdalign.h>
@@ -461,49 +463,50 @@ static char roll[TZ_MAX_LEAPS];
** Memory allocation.
*/
-static ATTRIBUTE_NORETURN void
+ATTRIBUTE_NORETURN static void
memory_exhausted(const char *msg)
{
fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
exit(EXIT_FAILURE);
}
-static ATTRIBUTE_NORETURN void
+ATTRIBUTE_NORETURN static void
size_overflow(void)
{
memory_exhausted(_("size overflow"));
}
-static ATTRIBUTE_REPRODUCIBLE size_t
+ATTRIBUTE_REPRODUCIBLE static ptrdiff_t
size_sum(size_t a, size_t b)
{
#ifdef ckd_add
- size_t sum;
- if (!ckd_add(&sum, a, b))
+ ptrdiff_t sum;
+ if (!ckd_add(&sum, a, b) && sum <= INDEX_MAX)
return sum;
#else
- if (b <= SIZE_MAX - a)
+ if (a <= INDEX_MAX && b <= INDEX_MAX - a)
return a + b;
#endif
size_overflow();
}
-static ATTRIBUTE_REPRODUCIBLE size_t
-size_product(size_t nitems, size_t itemsize)
+ATTRIBUTE_REPRODUCIBLE static ptrdiff_t
+size_product(ptrdiff_t nitems, ptrdiff_t itemsize)
{
#ifdef ckd_mul
- size_t product;
- if (!ckd_mul(&product, nitems, itemsize))
+ ptrdiff_t product;
+ if (!ckd_mul(&product, nitems, itemsize) && product <= INDEX_MAX)
return product;
#else
- if (nitems <= SIZE_MAX / itemsize)
+ ptrdiff_t nitems_max = INDEX_MAX / itemsize;
+ if (nitems <= nitems_max)
return nitems * itemsize;
#endif
size_overflow();
}
-static ATTRIBUTE_REPRODUCIBLE size_t
-align_to(size_t size, size_t alignment)
+ATTRIBUTE_REPRODUCIBLE static ptrdiff_t
+align_to(ptrdiff_t size, ptrdiff_t alignment)
{
size_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits);
return sum & ~lo_bits;
@@ -526,7 +529,7 @@ memcheck(void *ptr)
return ptr;
}
-static void * ATTRIBUTE_MALLOC
+ATTRIBUTE_MALLOC static void *
emalloc(size_t size)
{
return memcheck(malloc(size));
@@ -538,7 +541,7 @@ erealloc(void *ptr, size_t size)
return memcheck(realloc(ptr, size));
}
-static char * ATTRIBUTE_MALLOC
+ATTRIBUTE_MALLOC static char *
estrdup(char const *str)
{
return memcheck(strdup(str));
@@ -551,11 +554,10 @@ grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize)
#if defined ckd_add && defined ckd_mul
ptrdiff_t product;
if (!ckd_add(nitems_alloc, *nitems_alloc, addend)
- && !ckd_mul(&product, *nitems_alloc, itemsize) /* && product <= SIZE_MAX */)
+ && !ckd_mul(&product, *nitems_alloc, itemsize) && product <= INDEX_MAX)
return product;
#else
- ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX);
- if (*nitems_alloc <= ((amax - 1) / 3 * 2) / itemsize) {
+ if (*nitems_alloc <= ((INDEX_MAX - 1) / 3 * 2) / itemsize) {
*nitems_alloc += addend;
return *nitems_alloc * itemsize;
}
@@ -608,7 +610,7 @@ eat(int fnum, lineno num)
eats(fnum, num, 0, -1);
}
-static void ATTRIBUTE_FORMAT((printf, 1, 0))
+ATTRIBUTE_FORMAT((printf, 1, 0)) static void
verror(const char *const string, va_list args)
{
/*
@@ -626,7 +628,7 @@ verror(const char *const string, va_list args)
fprintf(stderr, "\n");
}
-static void ATTRIBUTE_FORMAT((printf, 1, 2))
+ATTRIBUTE_FORMAT((printf, 1, 2)) static void
error(const char *const string, ...)
{
va_list args;
@@ -636,7 +638,7 @@ error(const char *const string, ...)
errors = true;
}
-static void ATTRIBUTE_FORMAT((printf, 1, 2))
+ATTRIBUTE_FORMAT((printf, 1, 2)) static void
warning(const char *const string, ...)
{
va_list args;
@@ -666,7 +668,7 @@ close_file(FILE *stream, char const *dir, char const *name,
}
}
-static ATTRIBUTE_NORETURN void
+ATTRIBUTE_NORETURN static void
usage(FILE *stream, int status)
{
fprintf(stream,
@@ -1435,7 +1437,7 @@ static char *
relname(char const *target, char const *linkname)
{
size_t i, taillen, dir_len = 0, dotdots = 0;
- ptrdiff_t dotdotetcsize, linksize = min(PTRDIFF_MAX, SIZE_MAX);
+ ptrdiff_t dotdotetcsize, linksize = INDEX_MAX;
char const *f = target;
char *result = NULL;
if (*linkname == '/') {
@@ -1710,8 +1712,7 @@ infile(int fnum, char const *name)
wantcont = false;
for (num = 1; ; ++num) {
enum { bufsize_bound
- = (min(INT_MAX, min(PTRDIFF_MAX, SIZE_MAX))
- / FORMAT_LEN_GROWTH_BOUND) };
+ = (min(INT_MAX, INDEX_MAX) / FORMAT_LEN_GROWTH_BOUND) };
char buf[min(_POSIX2_LINE_MAX, bufsize_bound)];
int nfields;
char *fields[MAX_FIELDS];
@@ -3647,7 +3648,7 @@ lowerit(char a)
}
/* case-insensitive equality */
-static ATTRIBUTE_REPRODUCIBLE bool
+ATTRIBUTE_REPRODUCIBLE static bool
ciequal(register const char *ap, register const char *bp)
{
while (lowerit(*ap) == lowerit(*bp++))
@@ -3656,7 +3657,7 @@ ciequal(register const char *ap, register const char *bp)
return false;
}
-static ATTRIBUTE_REPRODUCIBLE bool
+ATTRIBUTE_REPRODUCIBLE static bool
itsabbr(register const char *abbr, register const char *word)
{
if (lowerit(*abbr) != lowerit(*word))
@@ -3672,7 +3673,7 @@ itsabbr(register const char *abbr, register const char *word)
/* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
-static ATTRIBUTE_REPRODUCIBLE bool
+ATTRIBUTE_REPRODUCIBLE static bool
ciprefix(char const *abbr, char const *word)
{
do
@@ -3775,14 +3776,14 @@ getfields(char *cp, char **array, int arrayelts)
return nsubs;
}
-static ATTRIBUTE_NORETURN void
+ATTRIBUTE_NORETURN static void
time_overflow(void)
{
error(_("time overflow"));
exit(EXIT_FAILURE);
}
-static ATTRIBUTE_REPRODUCIBLE zic_t
+ATTRIBUTE_REPRODUCIBLE static zic_t
oadd(zic_t t1, zic_t t2)
{
#ifdef ckd_add
@@ -3796,7 +3797,7 @@ oadd(zic_t t1, zic_t t2)
time_overflow();
}
-static ATTRIBUTE_REPRODUCIBLE zic_t
+ATTRIBUTE_REPRODUCIBLE static zic_t
tadd(zic_t t1, zic_t t2)
{
#ifdef ckd_add