aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2026-03-11 03:47:31 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2026-03-11 03:48:58 +0000
commitff2c98b30b57b9763e2a6575f729bab676e6c025 (patch)
treef530f0393271fa7c3cc62037a2476a50909f99db
parent67728a18b9c18e55cc60e063380825b80f25b1b9 (diff)
parentcd59570c180e34a6716c2d61a3047ac2f9407795 (diff)
tzcode: Update to 2026a
Many thanks to Paul Eggert for adopting most of our adaptations as optional features upstream in the previous release (2025c). MFC after: 1 week Reviewed by: philip Differential Revision: https://reviews.freebsd.org/D55741
-rw-r--r--contrib/tzcode/CONTRIBUTING36
-rw-r--r--contrib/tzcode/Makefile236
-rw-r--r--contrib/tzcode/NEWS232
-rw-r--r--contrib/tzcode/README14
-rw-r--r--contrib/tzcode/SECURITY2
-rw-r--r--contrib/tzcode/calendars27
-rw-r--r--contrib/tzcode/date.14
-rw-r--r--contrib/tzcode/date.c7
-rw-r--r--contrib/tzcode/localtime.c1747
-rw-r--r--contrib/tzcode/newctime.328
-rw-r--r--contrib/tzcode/newstrftime.32
-rw-r--r--contrib/tzcode/newtzset.347
-rw-r--r--contrib/tzcode/private.h372
-rw-r--r--contrib/tzcode/strftime.c5
-rw-r--r--contrib/tzcode/theory.html383
-rw-r--r--contrib/tzcode/time2posix.3118
-rw-r--r--contrib/tzcode/tz-art.html423
-rw-r--r--contrib/tzcode/tz-how-to.html250
-rw-r--r--contrib/tzcode/tz-link.html398
-rw-r--r--contrib/tzcode/tzconfig.h36
-rw-r--r--contrib/tzcode/tzfile.530
-rw-r--r--contrib/tzcode/tzfile.h30
-rw-r--r--contrib/tzcode/tzselect.ksh15
-rw-r--r--contrib/tzcode/version2
-rw-r--r--contrib/tzcode/workman.sh36
-rw-r--r--contrib/tzcode/zdump.c21
-rw-r--r--contrib/tzcode/zic.885
-rw-r--r--contrib/tzcode/zic.c783
28 files changed, 3146 insertions, 2223 deletions
diff --git a/contrib/tzcode/CONTRIBUTING b/contrib/tzcode/CONTRIBUTING
index f6edbd3be7d3..c5fa803f7275 100644
--- a/contrib/tzcode/CONTRIBUTING
+++ b/contrib/tzcode/CONTRIBUTING
@@ -10,26 +10,27 @@ warning, the data entries do not cover all of civil time before
1970, and undoubtedly errors remain in the code and data. Feel
free to fill gaps or fix mistakes, and please email improvements
to <tz@iana.org> for use in the future. In your email, please give
-reliable sources that reviewers can check.
+reliable sources that reviewers can check. The mailing list and its
+archives are public, so please do not send confidential information.
## Contributing technical changes
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.
+‘diff -u old/europe new/europe >myfix.patch’, and attach
+‘myfix.patch’ to the email.
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"
+“Theory and pragmatics of the tz code and data”
<https://www.iana.org/time-zones/repository/theory.html>.
It is also good to browse the mailing list archives
<https://lists.iana.org/hyperkitty/list/tz@iana.org/>
for examples of patches that tend to work well.
Changes should contain commentary citing reliable sources.
-Citations should use "https:" URLs if available.
+Citations should use ‘https:’ URLs if available.
For changes that fix sensitive security-related bugs, please see the
-distribution's 'SECURITY' file.
+distribution’s SECURITY file.
Please submit changes against either the latest release
<https://www.iana.org/time-zones> or the main branch of the development
@@ -54,11 +55,11 @@ If you use Git the following workflow may be helpful:
git checkout -b mybranch
- * Sleuth by using 'git blame'. For example, when fixing data for
- Africa/Sao_Tome, if the command 'git blame africa' outputs a line
- '2951fa3b (Paul Eggert 2018-01-08 09:03:13 -0800 1068) Zone
- Africa/Sao_Tome 0:26:56 - LMT 1884', commit 2951fa3b should
- provide some justification for the 'Zone Africa/Sao_Tome' line.
+ * Sleuth by using ‘git blame’. For example, when fixing data for
+ Africa/Sao_Tome, if the command ‘git blame africa’ outputs a line
+ ‘2951fa3b (Paul Eggert 2018-01-08 09:03:13 -0800 1068) Zone
+ Africa/Sao_Tome 0:26:56 - LMT 1884’, commit 2951fa3b should
+ provide some justification for the ‘Zone Africa/Sao_Tome’ line.
* Edit source files. Include commentary that justifies the
changes by citing reliable sources.
@@ -69,28 +70,31 @@ If you use Git the following workflow may be helpful:
./zdump -v America/Los_Angeles
Although builds assume only basic POSIX, they use extra features
- if available. 'make check' accesses validator.w3.org unless you
- lack 'curl' or use 'make CURL=:'. If you have the latest GCC,
- "make CFLAGS='$(GCC_DEBUG_FLAGS)'" does extra checking.
+ if available. ‘make check’ accesses validator.w3.org unless you
+ lack ‘curl’ or use ‘make CURL=:’. If you have the latest GCC,
+ ‘make CFLAGS='$(GCC_DEBUG_FLAGS)'’ does extra checking.
* For each separable change, commit it in the new branch, e.g.:
git add northamerica
git commit
- See recent 'git log' output for the commit-message style.
+ See recent ‘git log’ output for the commit-message style.
* Create patch files 0001-..., 0002-..., ...
git format-patch main
+ * Check that the patch files and your email setup contain only
+ information that you want to make public.
+
* After reviewing the patch files, send the patches to <tz@iana.org>
for others to review.
git send-email main
For an archived example of such an email, see
- "[PROPOSED] Fix off-by-1 error for Jamaica and T&C before 1913"
+ “[PROPOSED] Fix off-by-1 error for Jamaica and T&C before 1913”
<https://mm.icann.org/pipermail/tz/2018-February/026122.html>.
* Start anew by getting current with the main branch again
diff --git a/contrib/tzcode/Makefile b/contrib/tzcode/Makefile
index 2130582c2deb..1e0a5903534d 100644
--- a/contrib/tzcode/Makefile
+++ b/contrib/tzcode/Makefile
@@ -3,17 +3,30 @@
# 2009-05-17 by Arthur David Olson.
# Request POSIX conformance; this must be the first non-comment line.
.POSIX:
+# By default, builds of code and data assume POSIX.1-2001 or later;
+# this assumption can be relaxed by tailoring the build as described below.
# On older platforms you may need to scrounge for POSIX conformance.
# For example, on Solaris 10 (2005) with Sun Studio 12 aka Sun C 5.9 (2007),
# use 'PATH=/usr/xpg4/bin:$PATH make CC=c99'.
+# Reproducible builds of distribution tarballs also need a copy of the
+# Git repository, and assume the behavior of the following programs
+# (or later versions):
+# Git 2.7.0 (2016)
+# GNU Coreutils 6.3 (2006)
+# GNU Tar 1.14 (2004)
+# GnuPG 1.4 (2004)
+# Although tzdb does not come with a software bill of materials,
+# you should be able to construct one based on the above information,
+# your platform, and the way you use this Makefile.
# To affect how this Makefile works, you can run a shell script like this:
#
# #!/bin/sh
-# make CC='gcc -std=gnu23' "$@"
+# make CFLAGS='-O2 -DHAVE_GETTEXT=0' "$@"
#
-# This example script is appropriate for a circa 2024 GNU/Linux system
-# where a non-default setting enables this package's optional use of C23.
+# This example script is appropriate for a GNU/Linux system
+# which needs more optimization than default, and which does not want
+# gettext's internationalization of diagnostics.
#
# Alternatively, you can simply edit this Makefile to tailor the following
# macro definitions.
@@ -53,28 +66,6 @@ DATAFORM= main
LOCALTIME= Factory
-# 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.
-# 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).
-# Alternatively, if you discover you've got the wrong timezone, you can just
-# 'zic -p -' to remove it, or 'zic -p rightzone' to change it.
-# Use the command
-# make zonenames
-# to get a list of the values you can use for POSIXRULES.
-
-POSIXRULES= -
-
-# Also see TZDEFRULESTRING below, which takes effect only
-# if POSIXRULES is '-' or if the template file cannot be accessed.
-
# Installation locations.
#
@@ -150,13 +141,14 @@ TIME_T_ALTERNATIVES_TAIL = int_least32_t.ck uint_least32_t.ck \
# below. If you want both sets of data available, with leap seconds counted
# normally, use
# REDO= right_posix
-# below. POSIX mandates that leap seconds not be counted; for compatibility
-# with it, use "posix_only" or "posix_right". Use POSIX time on systems with
+# below. POSIX mandates that leap seconds not be counted, and a
+# nonnegative TZ_CHANGE_INTERVAL also assumes this, so to be compatible with
+# these, use "posix_only" or "posix_right". Use POSIX time on systems with
# leap smearing; this can work better than unsmeared "right" time with
# applications that are not leap second aware, and is closer to unsmeared
# "right" time than unsmeared POSIX time is (e.g., 0.5 vs 1.0 s max error).
-REDO= posix_right
+REDO= posix_only
# Whether to put an "Expires" line in the leapseconds file.
# Use EXPIRES_LINE=1 to put the line in, 0 to omit it.
@@ -206,6 +198,12 @@ PACKRATLIST=
UTF8_LOCALE= en_US.utf8
+# Extra flags for producing man page files like tzfile.5.txt.
+# These flags are used only if groff (or mandoc) is present.
+# Each option should begin with "-" and should lack shell metacharacters.
+# Plausible options include -Tascii and -Tutf8.
+MANFLAGS= -Tutf8
+
# Non-default libraries needed to link.
# On some hosts, this should have -lintl unless CFLAGS has -DHAVE_GETTEXT=0.
LDLIBS=
@@ -219,14 +217,19 @@ LDLIBS=
# -DEPOCH_OFFSET=N if the 'time' function returns a value N greater
# than what POSIX specifies, assuming local time is UT.
# For example, N is 252460800 on AmigaOS.
+# -DFREE_PRESERVES_ERRNO=[01] if the 'free' function munges or preserves errno
+# (default is guessed)
# -DHAVE_DECL_ASCTIME_R=0 if <time.h> does not declare asctime_r
# on POSIX platforms predating POSIX.1-2024
# -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_FCHMOD=0 if your system lacks the fchmod function
# -DHAVE__GENERIC=0 if _Generic does not work*
+# -DHAVE_GETEUID=0 if gete?[ug]id do not work
# -DHAVE_GETRANDOM if getrandom works (e.g., GNU/Linux),
# -DHAVE_GETRANDOM=0 to avoid using getrandom
+# -DHAVE_GETRESUID=0 if getres[ug]id do not work
# -DHAVE_GETTEXT if gettext works (e.g., GNU/Linux, FreeBSD, Solaris),
# where LDLIBS also needs to contain -lintl on some hosts;
# -DHAVE_GETTEXT=0 to avoid using gettext
@@ -234,28 +237,46 @@ LDLIBS=
# ctime_r and asctime_r incompatibly with POSIX.1-2017 and earlier
# (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined).
# -DHAVE_INTTYPES_H=0 if <inttypes.h> does not work*+
+# -DHAVE_ISSETUGID=1 if issetugid works, 0 otherwise (default is guessed)
+# If 0, you may also use -DHAVE_SYS_AUXV_H=1 if <sys/auxv.h> works,
+# 0 otherwise (default is guessed).
# -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
# localtime_rz can make zdump significantly faster, but is nonstandard.
# -DHAVE_MALLOC_ERRNO=0 if malloc etc. do not set errno on failure.
+# -DHAVE_MEMPCPY=1 if your system has mempcpy, 0 if not (default is guessed)
# -DHAVE_POSIX_DECLS=0 if your system's include files do not declare
-# functions like 'link' or variables like 'tzname' required by POSIX
+# variables like 'tzname' required by POSIX
+# -DHAVE_PWD_H=0 if your system lacks pwd.h, grp.h and corresponding functions
+# If 0, you may also need -Dgid_t=G -Duid_t=U
+# to define gid_t and uid_t to be types G and U.
# -DHAVE_SETENV=0 if your system lacks the setenv function
+# -DHAVE_SETMODE=[01] if your system lacks or has the setmode and getmode
+# functions (default is guessed)
# -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_STRFTIME_L if <time.h> declares locale_t and strftime_l
# -DHAVE_STRDUP=0 if your system lacks the strdup function
+# -DHAVE_STRNLEN=0 if your system lacks the strnlen function+
# -DHAVE_STRTOLL=0 if your system lacks the strtoll function+
+# -DHAVE_STRUCT_STAT_ST_CTIM=0 if struct stat lacks a status-change member
+# of type struct timespec, so code should use st_ctime instead;
+# but if the status-change member name is st_ctimespec,
+# use -Dst_ctim=st_ctimespec instead (default is guessed)+
+# -DHAVE_STRUCT_TIMESPEC=0 if your system lacks struct timespec+
# -DHAVE_SYMLINK=0 if your system lacks the symlink function
# -DHAVE_SYS_STAT_H=0 if <sys/stat.h> does not work*
+# If 0, you may also need -Dmode_t=M to define mode_t to be type M.
# -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
# -DMKTIME_MIGHT_OVERFLOW if mktime might fail due to time_t overflow
+# -DOPENAT_TZDIR if tzset should use openat on TZDIR then a relative open.
+# See localtime.c for details.
# -DPORT_TO_C89 if tzcode should also run on mostly-C89 platforms+
# Typically it is better to use a later standard. For example,
# with GCC 4.9.4 (2016), prefer '-std=gnu11' to '-DPORT_TO_C89'.
@@ -274,15 +295,46 @@ LDLIBS=
# -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires;
# not needed by the main-program tz code, which is single-threaded.
# Append other compiler flags as needed, e.g., -pthread on GNU/Linux.
+# The following options can also be used:
+# -DTHREAD_PREFER_SINGLE to prefer speed in single-threaded apps,
+# at some cost in CPU time and energy in multi-threaded apps.
+# The following options can also be used:
+# -DHAVE___ISTHREADED=1 if there is an extern int __isthreaded
+# variable, 0 otherwise (default is guessed)
+# -DHAVE_SYS_SINGLE_THREADED_H=0 if <sys/single_threaded.h> works,
+# 0 otherwise (default is guessed)
+# -DTHREAD_RWLOCK to use read-write locks instead of mutexes.
+# This can improve parallelism and thus save real time
+# if many threads call tzcode functions simultaneously.
+# It also costs CPU time and thus energy.
+# -DTHREAD_TM_MULTI to have gmtime, localtime, and offtime
+# return different struct tm * addresses in different threads.
+# This supports nonportable programs that call
+# gmtime/localtime/offtime when they should call
+# gmtime_r/localtime_r/offtime_r to avoid races.
+# Because the corresponding storage is freed on thread exit,
+# this option is incompatible with POSIX.1-2024 and earlier.
+# It also costs CPU time and memory.
# -Dtime_tz=\"T\" to use T as the time_t type, rather than the system time_t
# This is intended for internal use only; it mangles external names.
+# -DTZ_CHANGE_INTERVAL=N if functions depending on TZ should check
+# no more often than every N seconds for TZif file changes.
+# If N is negative (the default), no such checking is done.
+# This option is intended for platforms that want localtime etc.
+# to respond to changes to a file selected by TZ, including to
+# TZDEFAULT (normally /etc/localtime) if TZ is unset.
+# On these platforms, REDO should be "posix_only" or "posix_right".
+# This option does not affect tzalloc-allocated objects.
# -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is "tz"
# -DTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory;
# the default is system-supplied, typically "/usr/lib/locale"
+# -DTZ_RUNTIME_LEAPS=0 to disable runtime support for leap seconds.
+# This conforms to POSIX, shrinks tzcode's attack surface,
+# and is more efficient. However, it fails to support Internet
+# RFC 9636's leap seconds.
# -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified
-# DST transitions for proleptic format TZ strings lacking them,
-# in the usual case where POSIXRULES is '-'. If not specified,
-# TZDEFRULESTRING defaults to US rules for future DST transitions.
+# DST transitions for proleptic format TZ strings lacking them.
+# If not specified, it 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.
@@ -314,7 +366,7 @@ LDLIBS=
# Select instrumentation via "make GCC_INSTRUMENT='whatever'".
GCC_INSTRUMENT = \
-fsanitize=undefined -fsanitize-address-use-after-scope \
- -fsanitize-undefined-trap-on-error -fstack-protector
+ -fsanitize-trap=all -fstack-protector
# Omit -fanalyzer from GCC_DEBUG_FLAGS, as it makes GCC too slow.
GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \
$(GCC_INSTRUMENT) \
@@ -332,12 +384,13 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \
-Wold-style-definition -Woverlength-strings -Wpointer-arith \
-Wshadow -Wshift-overflow=2 -Wstrict-overflow \
-Wstrict-prototypes -Wstringop-overflow=4 \
- -Wstringop-truncation -Wsuggest-attribute=cold \
+ -Wsuggest-attribute=cold \
-Wsuggest-attribute=const -Wsuggest-attribute=format \
-Wsuggest-attribute=malloc \
-Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \
-Wtrampolines -Wundef -Wunused-macros -Wuse-after-free=3 \
-Wvariadic-macros -Wvla -Wwrite-strings \
+ -Wzero-as-null-pointer-constant \
-Wno-format-nonliteral -Wno-sign-compare -Wno-type-limits
#
# If your system has a "GMT offset" field in its "struct tm"s
@@ -393,7 +446,9 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \
# 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.
-# I.e., "offtime" is like calling "localtime_rz" with a fixed-offset zone.
+# "offtime_r" is to "offtime" what "gmtime_r" is to "gmtime".
+# I.e., "offtime" and "offtime_r" are like calling "localtime_rz"
+# with a fixed-offset zone.
# "timelocal" is nearly 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.
@@ -451,6 +506,11 @@ leaplist_URI = \
https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list
# The file is generated by the IERS Earth Orientation Centre, in Paris.
leaplist_TZ = Europe/Paris
+#
+# To fetch leap-seconds.list from NIST via a less-secure protocol
+# and with less-volatile metadata, use these settings:
+#leaplist_URI = ftp://ftp.boulder.nist.gov/pub/time/leap-seconds.list
+#leaplist_TZ = America/Denver
# The zic command and its arguments.
@@ -510,13 +570,10 @@ SAFE_CHARSET3= 'abcdefghijklmnopqrstuvwxyz{|}~'
SAFE_CHARSET= $(SAFE_CHARSET1)$(SAFE_CHARSET2)$(SAFE_CHARSET3)
SAFE_CHAR= '[]'$(SAFE_CHARSET)'-]'
-# 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)
+# These non-alphabetic, non-ASCII printable characters are
+# used in commentary or in generated *.txt files
+# and are not likely to cause confusion.
+UNUSUAL_OK_CHARSET= §«°±»½¾×–‘’“”•→−≤★⟨⟩⯪
# Put this in a bracket expression to match spaces.
s = [:space:]
@@ -525,9 +582,6 @@ s = [:space:]
# This is the same as SAFE_CHAR, except that UNUSUAL_OK_CHARSET and
# multibyte letters are also allowed so that commentary can contain a
# few safe symbols and people's names and can quote non-English sources.
-# Other non-letters are limited to ASCII renderings for the
-# convenience of maintainers using XEmacs 21.5.34, which by default
-# mishandles Unicode characters U+0100 and greater.
OK_CHAR= '[][:alpha:]$(UNUSUAL_OK_CHARSET)'$(SAFE_CHARSET)'-]'
# SAFE_LINE matches a line of safe characters.
@@ -654,7 +708,6 @@ install: all $(DATA) $(REDO) $(MANS)
'$(DESTDIR)$(MANDIR)/man3' '$(DESTDIR)$(MANDIR)/man5' \
'$(DESTDIR)$(MANDIR)/man8'
$(ZIC_INSTALL) -l $(LOCALTIME) \
- -p $(POSIXRULES) \
-t '$(DESTDIR)$(TZDEFAULT)'
cp -f $(TABDATA) '$(DESTDIR)$(TZDIR)/.'
cp tzselect '$(DESTDIR)$(BINDIR)/.'
@@ -874,9 +927,9 @@ UTF8_LOCALE_MISSING = \
character-set.ck: $(ENCHILADA)
$(UTF8_LOCALE_MISSING) || { \
sharp='#' && \
- ! grep -Env $(SAFE_LINE) $(MANS) date.1 $(MANTXTS) \
- $(MISC) $(SOURCES) $(WEB_PAGES) \
- CONTRIBUTING LICENSE README SECURITY \
+ ! grep -Env $(SAFE_LINE) $(MANS) date.1 \
+ $(MISC) $(SOURCES) \
+ LICENSE \
version tzdata.zi && \
! grep -Env $(SAFE_LINE)'|^UNUSUAL_OK_'$(OK_CHAR)'*$$' \
Makefile && \
@@ -888,11 +941,9 @@ character-set.ck: $(ENCHILADA)
white-space.ck: $(ENCHILADA)
$(UTF8_LOCALE_MISSING) || { \
- enchilada='$(ENCHILADA)' && \
patfmt=' \t|[\f\r\v]' && pat=$$(printf "$$patfmt\\n") && \
! grep -En "$$pat|[$s]\$$" \
- $${enchilada%leap-seconds.list*} \
- $${enchilada#*leap-seconds.list}; \
+ $(ENCHILADA:leap-seconds.list=); \
}
touch $@
@@ -959,8 +1010,10 @@ now.ck: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab
./zdump -i -t 0,$$future \
$$(find "$$PWD/$@d" -name Etc -prune \
-o -type f ! -name '*.tab' -print) \
- >$@d/zdump-1970.tab
+ >$@d/zdump-1970.tab && \
$(AWK) \
+ -v now=$$now \
+ -v now_out=$@.out \
-v zdump_table=$@d/zdump-now.tab \
-f checknow.awk zonenow.tab
$(AWK) \
@@ -970,7 +1023,8 @@ now.ck: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab
-v zdump_table=$@d/zdump-1970.tab \
-f checknow.awk
rm -fr $@d
- touch $@
+ touch $@.out
+ mv $@.out $@
tables.ck: checktab.awk $(YDATA) backward zone.tab zone1970.tab
for tab in $(ZONETABLES); do \
@@ -1031,7 +1085,7 @@ zishrink-posix.ck zishrink-right.ck: \
clean_misc:
rm -fr *.ckd *.dir
- rm -f *.ck *.core *.o *.out core core.* \
+ rm -f *.ck *.core *.o *.out *.t core core.* \
date tzdir.h tzselect version.h zdump zic libtz.a
clean: clean_misc
rm -fr tzdb-*/
@@ -1059,7 +1113,7 @@ zdump.8.txt: zdump.8
zic.8.txt: zic.8
$(MANTXTS): workman.sh
- LC_ALL=C sh workman.sh $(@:.txt=) >$@.out
+ LC_ALL=C sh workman.sh $(MANFLAGS) $(@:.txt=) >$@.out
mv $@.out $@
# Set file timestamps deterministically if possible,
@@ -1108,7 +1162,7 @@ set-timestamps.out: $(EIGHT_YARDS)
if git diff --quiet HEAD $$file; then \
time=$$(TZ=UTC0 git log -1 \
--format='tformat:%cd' \
- --date='format:%Y-%m-%dT%H:%M:%SZ' \
+ --date='format-local:%Y-%m-%dT%H:%M:%SZ' \
$$file) && \
echo "+ touch -md $$time $$file" && \
touch -md $$time $$file; \
@@ -1207,12 +1261,12 @@ $(TIME_T_ALTERNATIVES): $(VERSION_DEPS)
touch $@
TRADITIONAL_ASC = \
- tzcode$(VERSION).tar.gz.asc \
- tzdata$(VERSION).tar.gz.asc
+ tzcode$(VERSION).tar.gz.asc.t \
+ tzdata$(VERSION).tar.gz.asc.t
REARGUARD_ASC = \
- tzdata$(VERSION)-rearguard.tar.gz.asc
+ tzdata$(VERSION)-rearguard.tar.gz.asc.t
ALL_ASC = $(TRADITIONAL_ASC) $(REARGUARD_ASC) \
- tzdb-$(VERSION).tar.lz.asc
+ tzdb-$(VERSION).tar.lz.asc.t
tarballs rearguard_tarballs tailored_tarballs traditional_tarballs \
signatures rearguard_signatures traditional_signatures: \
@@ -1224,29 +1278,31 @@ signatures rearguard_signatures traditional_signatures: \
# other means. Ordinarily these rules are used only by the above
# non-_version rules, which set VERSION on the 'make' command line.
tarballs_version: traditional_tarballs_version rearguard_tarballs_version \
- tzdb-$(VERSION).tar.lz
+ tzdb-$(VERSION).tar.lz.t
rearguard_tarballs_version: \
- tzdata$(VERSION)-rearguard.tar.gz
+ tzdata$(VERSION)-rearguard.tar.gz.t
traditional_tarballs_version: \
- tzcode$(VERSION).tar.gz tzdata$(VERSION).tar.gz
+ tzcode$(VERSION).tar.gz.t tzdata$(VERSION).tar.gz.t
tailored_tarballs_version: \
- tzdata$(VERSION)-tailored.tar.gz
+ tzdata$(VERSION)-tailored.tar.gz.t
signatures_version: $(ALL_ASC)
rearguard_signatures_version: $(REARGUARD_ASC)
traditional_signatures_version: $(TRADITIONAL_ASC)
-tzcode$(VERSION).tar.gz: set-timestamps.out
+tzcode$(VERSION).tar.gz.t: set-timestamps.out
$(SETUP_TAR) && \
$$TAR -cf - \
$(COMMON) $(DOCS) $(SOURCES) | \
- gzip $(GZIPFLAGS) >$@.out
- mv $@.out $@
+ gzip $(GZIPFLAGS) >$(@:.t=)
+ $(SET_TIMESTAMP) $(@:.t=) $(COMMON) $(DOCS) $(SOURCES)
+ touch $@
-tzdata$(VERSION).tar.gz: set-timestamps.out
+tzdata$(VERSION).tar.gz.t: set-timestamps.out
$(SETUP_TAR) && \
$$TAR -cf - $(TZDATA_DIST) | \
- gzip $(GZIPFLAGS) >$@.out
- mv $@.out $@
+ gzip $(GZIPFLAGS) >$(@:.t=)
+ $(SET_TIMESTAMP) $(@:.t=) $(TZDATA_DIST)
+ touch $@
# Create empty files with a reproducible timestamp.
CREATE_EMPTY = TZ=UTC0 touch -mt 202010122253.00
@@ -1255,7 +1311,7 @@ CREATE_EMPTY = TZ=UTC0 touch -mt 202010122253.00
# for backwards compatibility with tz releases 2018e through 2022a.
# They should go away eventually. To build rearguard tarballs you
# can instead use 'make DATAFORM=rearguard tailored_tarballs'.
-tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out
+tzdata$(VERSION)-rearguard.tar.gz.t: rearguard.zi set-timestamps.out
rm -fr $@.dir
mkdir $@.dir
ln $(TZDATA_DIST) $@.dir
@@ -1273,8 +1329,11 @@ tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out
(cd $@.dir && \
$$TAR -cf - \
$(TZDATA_DIST) pacificnew | \
- gzip $(GZIPFLAGS)) >$@.out
- mv $@.out $@
+ gzip $(GZIPFLAGS)) >$(@:.t=)
+ $(SET_TIMESTAMP) $(@:.t=) \
+ $$(cd $@.dir && \
+ ls $(TZDATA_DIST) pacificnew | sed 's,^,$@.dir/,')
+ touch $@
# Create a tailored tarball suitable for TZUpdater and compatible tools.
# For example, 'make DATAFORM=vanguard tailored_tarballs' makes a tarball
@@ -1283,7 +1342,7 @@ tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out
# traditional tarball, as data entries are put into 'etcetera' even if they
# came from some other source file. However, the effect should be the same
# for ordinary use, which reads all the source files.
-tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out
+tzdata$(VERSION)-tailored.tar.gz.t: set-timestamps.out
rm -fr $@.dir
mkdir $@.dir
: The dummy pacificnew pacifies TZUpdater 2.3.1 and earlier.
@@ -1295,7 +1354,7 @@ tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out
cd $@.dir && \
$(CREATE_EMPTY) $(PRIMARY_YDATA) $(NDATA) backward \
$$pacificnew
- (grep '^#' tzdata.zi && echo && cat $(DATAFORM).zi) \
+ (sed '/^#/!d' tzdata.zi && echo && cat $(DATAFORM).zi) \
>$@.dir/etcetera
touch -mr tzdata.zi $@.dir/etcetera
sed -n \
@@ -1316,24 +1375,29 @@ tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out
ln $$links $@.dir
$(SETUP_TAR) && \
(cd $@.dir && \
- $$TAR -cf - * | gzip $(GZIPFLAGS)) >$@.out
- mv $@.out $@
+ $$TAR -cf - *) | gzip $(GZIPFLAGS) >$(@:.t=)
+ $(SET_TIMESTAMP) $(@:.t=) \
+ $$(cd $@.dir && ls * | sed 's,^,$@.dir/,')
+ touch $@
-tzdb-$(VERSION).tar.lz: set-timestamps.out set-tzs-timestamp.out
+tzdb-$(VERSION).tar.lz.t: set-timestamps.out set-tzs-timestamp.out
rm -fr tzdb-$(VERSION)
mkdir tzdb-$(VERSION)
ln $(ENCHILADA) tzdb-$(VERSION)
$(SET_TIMESTAMP) tzdb-$(VERSION) tzdb-$(VERSION)/*
$(SETUP_TAR) && \
- $$TAR -cf - tzdb-$(VERSION) | lzip -9 >$@.out
- mv $@.out $@
+ $$TAR -cf - tzdb-$(VERSION) | lzip -9 >$(@:.t=)
+ $(SET_TIMESTAMP) $(@:.t=) tzdb-$(VERSION)
+ touch $@
-tzcode$(VERSION).tar.gz.asc: tzcode$(VERSION).tar.gz
-tzdata$(VERSION).tar.gz.asc: tzdata$(VERSION).tar.gz
-tzdata$(VERSION)-rearguard.tar.gz.asc: tzdata$(VERSION)-rearguard.tar.gz
-tzdb-$(VERSION).tar.lz.asc: tzdb-$(VERSION).tar.lz
+tzcode$(VERSION).tar.gz.asc.t: tzcode$(VERSION).tar.gz.t
+tzdata$(VERSION).tar.gz.asc.t: tzdata$(VERSION).tar.gz.t
+tzdata$(VERSION)-rearguard.tar.gz.asc.t: tzdata$(VERSION)-rearguard.tar.gz.t
+tzdb-$(VERSION).tar.lz.asc.t: tzdb-$(VERSION).tar.lz.t
$(ALL_ASC):
- $(GPG) --armor --detach-sign $?
+ $(GPG) --armor --detach-sign $(?:.t=)
+ $(SET_TIMESTAMP) $(@:.t=) $(?:.t=)
+ touch $@
TYPECHECK_CFLAGS = $(CFLAGS) -DTYPECHECK -D__time_t_defined -D_TIME_T
typecheck: long-long.ck unsigned.ck
diff --git a/contrib/tzcode/NEWS b/contrib/tzcode/NEWS
index 8c0771641ef0..acd22280cb3a 100644
--- a/contrib/tzcode/NEWS
+++ b/contrib/tzcode/NEWS
@@ -1,5 +1,237 @@
News for the tz database
+Release 2026a - 2026-03-01 22:59:49 -0800
+
+ Briefly:
+ Moldova has used EU transition times since 2022.
+ The "right" TZif files are no longer installed by default.
+ -DTZ_RUNTIME_LEAPS=0 disables runtime support for leap seconds.
+ TZif files are no longer limited to 50 bytes of abbreviations.
+ zic is no longer limited to 50 leap seconds.
+ Several integer overflow bugs have been fixed.
+
+ Changes to past and future timestamps
+
+ Since 2022 Moldova has observed EU transition times, that is, it
+ has sprung forward at 03:00, not 02:00, and has fallen back at
+ 04:00, not 03:00. (Thanks to Heitor David Pinto.)
+
+ Changes to data
+
+ Remove Europe/Chisinau from zonenow.tab, as it now agrees with
+ Europe/Athens for future timestamps.
+
+ Changes to build procedure
+
+ The Makefile no longer by default installs an alternate set
+ of TZif files for system clocks that count leap seconds.
+ Install with 'make REDO=posix_right' to get the old default,
+ which is rarely used in major downstream distributions.
+ If your system clock counts leap seconds (contrary to POSIX),
+ it is better to install with 'make REDO=right_only'.
+ This change does not affect the leapseconds file, which is still
+ installed as before.
+
+ The Makefile's POSIXRULES option, which was declared obsolete in
+ release 2019b, has been removed. The Makefile's build procedure
+ thus no longer optionally installs the obsolete posixrules file.
+
+ Changes to code
+
+ Compiling with the new option -DTZ_RUNTIME_LEAPS=0 disables
+ runtime support for leap seconds. Although this conforms to
+ POSIX, shrinks tzcode's attack surface, and is more efficient,
+ it fails to support Internet RFC 9636's leap seconds.
+
+ zic now can generate, and localtime.c can now use, TZif files that
+ hold up to 256 bytes of abbreviations, counting trailing NULs.
+ The previous limit was 50 bytes, and some tzdata TZif files were
+ already consuming 40 bytes. zic -v warns if it generates a file
+ that exceeds the old 50-byte limit.
+
+ zic -L can now generate TZif files with more than 50 leap seconds.
+ This helps test TZif readers not limited to 50 leap seconds, as
+ tzcode's localtime.c is; it has little immediate need for
+ practical timekeeping as there have been only 27 leap seconds and
+ possibly there will be no more, due to planned changes to UTC.
+ zic -v warns if its output exceeds the old 50-second limit.
+
+ localtime.c no longer accesses the posixrules file generated by
+ zic -p. Hence for obsolete and nonconforming settings like
+ TZ="AST4ADT" it now typically falls back on US DST rules, rather
+ than attempting to override this fallback with the contents of the
+ posixrules file. This removes library support that was declared
+ obsolete in release 2019b, and fixes some undefined behavior.
+ (Undefined behavior reported by GitHub user Naveed8951.)
+
+ The posix2time, posix2time_z, time2posix, and time2posix_z
+ functions now set errno=EOVERFLOW and return ((time_t) -1) if the
+ result is not representable. Formerly they had undefined behavior
+ that could in practice result in crashing, looping indefinitely,
+ or returning an incorrect result. As before, these functions are
+ defined only when localtime.c is compiled with the -DSTD_INSPIRED
+ option.
+
+ Some other undefined behavior, triggered by TZif files containing
+ outlandish but conforming UT offsets or leap second corrections,
+ has also been fixed. (Some of these bugs reported by Naveed8951.)
+
+ localtime.c no longer rejects TZif files that exactly fit in its
+ internal structures, fixing off-by-one typos introduced in 2014g.
+
+ zic no longer generates a no-op transition when
+ simultaneous Rule and Zone changes cancel each other out.
+ This occurs in tzdata only in Asia/Tbilisi on 1997-03-30.
+ (Thanks to Renchunhui for a test case showing the bug.)
+
+ zic no longer assumes you can fflush a read-only stream.
+ (Problem reported by Christos Zoulas.)
+
+ zic no longer generates UT offsets equal to -2**31 and localtime.c
+ no longer accepts them, as they can cause trouble in both
+ localtime.c and its callers. RFC 9636 prohibits such offsets.
+
+ zic -p now warns that the -p option is obsolete and likely
+ ineffective.
+
+
+Release 2025c - 2025-12-10 14:42:37 -0800
+
+ Briefly:
+ Several code changes for compatibility with FreeBSD.
+
+ Changes to past timestamps
+
+ Baja California agreed with California’s DST rules in 1953 and in
+ 1961 through 1975, instead of observing standard time all year.
+ (Thanks to Alois Treindl.)
+
+ Changes to build procedure
+
+ Files in distributed tarballs now have correct commit times.
+ Formerly, the committer’s time zone was incorrectly ignored.
+
+ Distribution products (*.asc, *.gz, and *.lz) now have
+ reproducible timestamps. Formerly, only the contents of the
+ compressed tarballs had reproducible timestamps.
+
+ By default, distributed formatted man pages (*.txt) now use UTF-8
+ and are left-adjusted more consistently. A new Makefile macro
+ MANFLAGS can override these defaults. (Thanks to G. Branden
+ Robinson for inspiring these changes.)
+
+ Changes to code
+
+ An unset TZ is no longer invalid when /etc/localtime is missing,
+ and is abbreviated "UTC" not "-00". This reverts to 2024b behavior.
+ (Problem and patch reported by Dag-Erling Smørgrav.)
+
+ New function offtime_r, short for fixed-offset localtime_rz.
+ It is defined if STD_INSPIRED is defined.
+ (Patch from Dag-Erling Smørgrav.)
+
+ tzset etc. are now more cautious about questionable TZ settings.
+ Privileged programs now reject TZ settings that start with '/',
+ unless they are TZDEFAULT (default "/etc/localtime") or
+ start with TZDIR then '/' (default "/usr/share/zoneinfo/").
+ Unprivileged programs now require files to be regular files
+ and reject relative names containing ".." directory components;
+ formerly, only privileged programs did those two things.
+ These changes were inspired by similar behavior in FreeBSD.
+ On NetBSD, unprivileged programs now use O_REGULAR to check
+ whether a TZ setting starting with '/' names a regular file,
+ avoiding a minor security race still present elsewhere.
+ TZ strings taken from tzalloc arguments are now treated with
+ no less caution than TZ strings taken from the environment, as
+ the old undocumented behavior would have been hard to explain.
+ tzset etc. no longer use the ‘access’ system call to check access;
+ instead they now use the system calls issetugid, getauxval,
+ getresuid/getresgid, and geteuid/getegid/getuid/getgid (whichever
+ first works) to test whether a program is privileged.
+ Compile with -DHAVE_SYS_AUXV_H=[01] to enable or disable
+ <sys/auxv.h> which (if it defines AT_SECURE) enables getauxval,
+ and compile with -DHAVE_ISSETUGID=[01], -DHAVE_GETRESUID=[01], and
+ -DHAVE_GETEUID=[01] to enable or disable the other calls’ use.
+
+ The new CFLAGS option -DTZ_CHANGE_INTERVAL=N makes tzset etc.
+ check for TZif file changes if the in-memory data are N seconds
+ old or more, and are derived from the TZ environment variable.
+ This is intended for platforms that want tzset etc. to reflect
+ changes to whatever file TZ selects (including changes to
+ /etc/localtime if TZ is unset). If N is negative (the default)
+ these checks are omitted; this is the traditional behavior.
+
+ The new CFLAGS options -DHAVE_STRUCT_STAT_ST_CTIM=0 and
+ -DHAVE_STRUCT_TIMESPEC=0 port to non-POSIX.1-2008 platforms
+ that lack st_ctim and struct timespec, respectively.
+ On these platforms, the code falls back on st_ctime to
+ implement -DTZ_CHANGE_INTERVAL=N.
+
+ tzset etc. now treat ' ' like '_' in time zone abbreviations,
+ just as they treat other invalid bytes. This continues the
+ transition begun in release 96k, which removed spaces in tzdata
+ because the spaces break time string parsers.
+
+ The new CFLAGS option -DTHREAD_PREFER_SINGLE causes tzcode
+ in single-threaded processes to avoid locks, as FreeBSD does.
+ This can save time in single-threaded apps. The threadedness
+ testing costs CPU time and energy in multi-threaded apps.
+ New options -DHAVE___ISTHREADED and -DHAVE_SYS_SINGLE_THREADED_H
+ can help configure how to test for single-threadedness.
+
+ The new CFLAGS option -DTHREAD_RWLOCK uses read-write locks, as
+ macOS does, instead of mutexes. This saves real time when TZ is
+ rarely changing and many threads call tzcode simultaneously.
+ It costs more CPU time and energy.
+
+ The new CFLAGS option -TTHREAD_TM_MULTI causes localtime to return
+ a pointer to thread-specific memory, as FreeBSD does, instead of
+ to the same memory in all threads. This supports nonportable
+ programs that incorrectly use localtime instead of localtime_r.
+ This option affects gmtime and offtime similarly to localtime.
+ Because the corresponding storage is freed on thread exit, this
+ option is incompatible with POSIX.1-2024 and earlier. It also
+ costs CPU time and memory.
+
+ tzfree now preserves errno, consistently with POSIX.1-2024 ‘free’.
+
+ tzcode now uses mempcpy if available, guessing its availability.
+ Compile with -DHAVE_MEMPCPY=1 or 0 to override the guess.
+
+ tzcode now uses strnlen to improve asymptotic performance a bit.
+ Compile with -DHAVE_STRNLEN=0 if your platform lacks it.
+
+ tzcode now hand-declares unistd.h-provided symbols like getopt
+ if HAVE_UNISTD_H=0, not if HAVE_POSIX_DECLS=0.
+
+ tzset etc. now have an experimental OPENAT_TZDIR option;
+ see Makefile and localtime.c for details.
+
+ On platforms like GNU/Hurd that do not define PATH_MAX,
+ exceedingly long TZ strings no longer fail merely because they
+ exceed an arbitrary file name length limit imposed by tzcode.
+
+ zic has new options inspired by FreeBSD. ‘-D’ skips creation of
+ output ancestor directories, ‘-m MODE’ sets output files’ mode,
+ and ‘-u OWNER[:GROUP]’ sets output files’ owner and group.
+
+ zic now uses the fdopen function, which was standardized by
+ POSIX.1-1988 and is now safe to use in portable code.
+ This replaces its use of the older umask function, which
+ complicated maintenance.
+
+ Changes to commentary
+
+ The leapseconds file contains commentary about the IERS and NIST
+ last-modified and expiration timestamps for leap second data.
+ (Thanks to Judah Levine.)
+
+ Commentary now also uses characters from the set –‘’“”•≤ as this
+ can be useful and should work with current applications. This
+ also affects data in iso3166.tab and zone1970.tab, which now
+ contain strings like “Côte d’Ivoire” instead of “Côte d'Ivoire”.
+
+
Release 2025b - 2025-03-22 13:40:46 -0700
Briefly:
diff --git a/contrib/tzcode/README b/contrib/tzcode/README
index edabd2e0690f..f22ec5492d09 100644
--- a/contrib/tzcode/README
+++ b/contrib/tzcode/README
@@ -1,8 +1,8 @@
README for the tz distribution
-"Where do I set the hands of the clock?" -- Les Tremayne as The King
-"Oh that--you can set them any place you want." -- Frank Baxter as The Scientist
- (from the Bell System film "About Time")
+“Where do I set the hands of the clock?” – Les Tremayne as The King
+“Oh that – you can set them any place you want.” – Frank Baxter as The Scientist
+ (from the Bell System film “About Time”)
The Time Zone Database (called tz, tzdb or zoneinfo) contains code and
data that represent the history of local time for many representative
@@ -13,12 +13,12 @@ and daylight-saving rules.
See <https://www.iana.org/time-zones/repository/tz-link.html> or the
file tz-link.html for how to acquire the code and data.
-Once acquired, read the leading comments in the file "Makefile"
+Once acquired, read the leading comments in the file ‘Makefile’
and make any changes needed to make things right for your system,
especially when using a platform other than current GNU/Linux.
Then run the following commands, substituting your desired
-installation directory for "$HOME/tzdir":
+installation directory for ‘$HOME/tzdir’:
make TOPDIR="$HOME/tzdir" install
"$HOME/tzdir/usr/bin/zdump" -v America/Los_Angeles
@@ -39,12 +39,12 @@ The information in the time zone data files is by no means authoritative;
fixes and enhancements are welcome. Please see the file CONTRIBUTING
for details.
-Thanks to these Time Zone Caballeros who've made major contributions to the
+Thanks to these Time Zone Caballeros who’ve made major contributions to the
time conversion package: Keith Bostic; Bob Devine; Paul Eggert; Robert Elz;
Guy Harris; Mark Horton; John Mackin; and Bradley White. Thanks also to
Michael Bloom, Art Neilson, Stephen Prince, John Sovereign, and Frank Wales
for testing work, and to Gwillim Law for checking local mean time data.
-Thanks in particular to Arthur David Olson, the project's founder and first
+Thanks in particular to Arthur David Olson, the project’s founder and first
maintainer, to whom the time zone community owes the greatest debt of all.
None of them are responsible for remaining errors.
diff --git a/contrib/tzcode/SECURITY b/contrib/tzcode/SECURITY
index 40128bc86dd2..dbce8bbd5d2d 100644
--- a/contrib/tzcode/SECURITY
+++ b/contrib/tzcode/SECURITY
@@ -1,7 +1,7 @@
Please report any sensitive security-related bugs via email to the
tzdb designated coordinators, currently Paul Eggert
<eggert@cs.ucla.edu> and Tim Parenti <tim@timtimeonline.com>.
-Put "tzdb security" at the start of your email's subject line.
+Put “tzdb security” at the start of your email’s subject line.
We prefer communications to be in English.
You should receive a response within a week. If not, please follow up
diff --git a/contrib/tzcode/calendars b/contrib/tzcode/calendars
index f4ed9e434e50..699de85cbffa 100644
--- a/contrib/tzcode/calendars
+++ b/contrib/tzcode/calendars
@@ -16,30 +16,9 @@ and (in Paris only) 1871-05-06 through 1871-05-23.
Russia
-From Chris Carrier (1996-12-02):
-On 1929-10-01 the Soviet Union instituted an "Eternal Calendar"
-with 30-day months plus 5 holidays, with a 5-day week.
-On 1931-12-01 it changed to a 6-day week; in 1934 it reverted to the
-Gregorian calendar while retaining the 6-day week; on 1940-06-27 it
-reverted to the 7-day week. With the 6-day week the usual days
-off were the 6th, 12th, 18th, 24th and 30th of the month.
-(Source: Evitiar Zerubavel, _The Seven Day Circle_)
-
-
-Mark Brader reported a similar story in "The Book of Calendars", edited
-by Frank Parise (1982, Facts on File, ISBN 0-8719-6467-8), page 377. But:
-
-From: Petteri Sulonen (via Usenet)
-Date: 14 Jan 1999 00:00:00 GMT
-...
-
-If your source is correct, how come documents between 1929 and 1940 were
-still dated using the conventional, Gregorian calendar?
-
-I can post a scan of a document dated December 1, 1934, signed by
-Yenukidze, the secretary, on behalf of Kalinin, the President of the
-Executive Committee of the Supreme Soviet, if you like.
-
+Soviet Russia adopted the Gregorian calendar on 1918-02-14.
+It also used 5- and 6-day work weeks at times, in parallel with the
+Gregorian calendar; see <https://en.wikipedia.org/wiki/Soviet_calendar>.
Sweden (and Finland)
diff --git a/contrib/tzcode/date.1 b/contrib/tzcode/date.1
index 3a02e7c2e08a..8f2c212b2cf3 100644
--- a/contrib/tzcode/date.1
+++ b/contrib/tzcode/date.1
@@ -4,8 +4,6 @@
.SH NAME
date \- show and set date and time
.SH SYNOPSIS
-.if n .nh
-.if n .na
.B date
[
.B \-u
@@ -79,6 +77,6 @@ hexadecimal (leading 0x), preceded by an optional sign.
.br
/usr/share/zoneinfo timezone directory
.br
-/usr/share/zoneinfo/Etc/UTC for UTC leap seconds
+/usr/share/zoneinfo/Etc/UTC for UTC leap seconds, if supported
.SH SEE ALSO
.BR strftime (3).
diff --git a/contrib/tzcode/date.c b/contrib/tzcode/date.c
index b62f04d768bc..4e483678686e 100644
--- a/contrib/tzcode/date.c
+++ b/contrib/tzcode/date.c
@@ -31,11 +31,6 @@
#include <locale.h>
#include <stdio.h>
-#if !HAVE_POSIX_DECLS
-extern char * optarg;
-extern int optind;
-#endif
-
static int retval = EXIT_SUCCESS;
static void display(const char *, time_t);
@@ -64,7 +59,7 @@ main(const int argc, char *argv[])
textdomain(TZ_DOMAIN);
#endif /* HAVE_GETTEXT */
t = time(NULL);
- while ((ch = getopt(argc, argv, "ucr:")) != EOF && ch != -1) {
+ while ((ch = getopt(argc, argv, "ucr:")) != -1) {
switch (ch) {
default:
usage();
diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c
index 58099d234e2b..459d818f0d7b 100644
--- a/contrib/tzcode/localtime.c
+++ b/contrib/tzcode/localtime.c
@@ -13,45 +13,174 @@
/*LINTLIBRARY*/
#define LOCALTIME_IMPLEMENTATION
-#ifdef __FreeBSD__
-#include <pthread.h>
-#endif /* __FreeBSD__ */
-#ifdef DETECT_TZ_CHANGES
-# ifndef DETECT_TZ_CHANGES_INTERVAL
-# define DETECT_TZ_CHANGES_INTERVAL 61
-# endif
-int __tz_change_interval = DETECT_TZ_CHANGES_INTERVAL;
-# include <sys/stat.h>
-#endif /* DETECT_TZ_CHANGES */
#include "private.h"
#include "tzdir.h"
#include "tzfile.h"
#include <fcntl.h>
-#ifdef __FreeBSD__
-#include "libc_private.h"
-#endif /* __FreeBSD__ */
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
+# ifndef S_ISREG
+# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) /* Ancient UNIX. */
+# endif
+#else
+struct stat { char st_ctime, st_dev, st_ino; };
+# define dev_t char
+# define ino_t char
+# define fstat(fd, st) (memset(st, 0, sizeof *(st)), 0)
+# define stat(name, st) fstat(0, st)
+# define S_ISREG(mode) 1
+#endif
+
+#ifndef HAVE_STRUCT_STAT_ST_CTIM
+# define HAVE_STRUCT_STAT_ST_CTIM 1
+#endif
+#if !defined st_ctim && defined __APPLE__ && defined __MACH__
+# define st_ctim st_ctimespec
+#endif
+
+#ifndef THREAD_SAFE
+# define THREAD_SAFE 0
+#endif
+
+#ifndef THREAD_RWLOCK
+# define THREAD_RWLOCK 0
#endif
-#if !defined S_ISREG && defined S_IFREG
-/* Ancient UNIX or recent MS-Windows. */
-# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+
+#ifndef THREAD_TM_MULTI
+# define THREAD_TM_MULTI 0
#endif
-#if defined THREAD_SAFE && THREAD_SAFE
+#ifndef USE_TIMEX_T
+# define USE_TIMEX_T false
+#endif
+
+#if THREAD_SAFE
# include <pthread.h>
-#ifdef __FreeBSD__
-# define pthread_mutex_lock(l) (__isthreaded ? pthread_mutex_lock(l) : 0)
-# define pthread_mutex_unlock(l) (__isthreaded ? pthread_mutex_unlock(l) : 0)
-#endif /* __FreeBSD__ */
+
+# ifndef THREAD_PREFER_SINGLE
+# define THREAD_PREFER_SINGLE 0
+# endif
+# if THREAD_PREFER_SINGLE
+# ifndef HAVE___ISTHREADED
+# if defined __FreeBSD__ || defined __OpenBSD__
+# define HAVE___ISTHREADED 1
+# else
+# define HAVE___ISTHREADED 0
+# endif
+# endif
+# if HAVE___ISTHREADED
+extern int __isthreaded;
+# else
+# if !defined HAVE_SYS_SINGLE_THREADED_H && defined __has_include
+# if __has_include(<sys/single_threaded.h>)
+# define HAVE_SYS_SINGLE_THREADED_H 1
+# else
+# define HAVE_SYS_SINGLE_THREADED_H 0
+# endif
+# endif
+# ifndef HAVE_SYS_SINGLE_THREADED_H
+# if defined __GLIBC__ && 2 < __GLIBC__ + (32 <= __GLIBC_MINOR__)
+# define HAVE_SYS_SINGLE_THREADED_H 1
+# else
+# define HAVE_SYS_SINGLE_THREADED_H 0
+# endif
+# endif
+# if HAVE_SYS_SINGLE_THREADED_H
+# include <sys/single_threaded.h>
+# endif
+# endif
+# endif
+#endif
+
+#if !defined TM_GMTOFF || !USE_TIMEX_T
+# if THREAD_SAFE
+
+/* True if the current process might be multi-threaded,
+ false if it is definitely single-threaded.
+ If false, it will be false the next time it is called
+ unless the caller creates a thread in the meantime.
+ If true, it might become false the next time it is called
+ if all other threads exit in the meantime. */
+static bool
+is_threaded(void)
+{
+# if THREAD_PREFER_SINGLE && HAVE___ISTHREADED
+ return !!__isthreaded;
+# elif THREAD_PREFER_SINGLE && HAVE_SYS_SINGLE_THREADED_H
+ return !__libc_single_threaded;
+# else
+ return true;
+# endif
+}
+
+# if THREAD_RWLOCK
+static pthread_rwlock_t locallock = PTHREAD_RWLOCK_INITIALIZER;
+static int dolock(void) { return pthread_rwlock_rdlock(&locallock); }
+static void dounlock(void) { pthread_rwlock_unlock(&locallock); }
+# else
static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
-static int lock(void) { return pthread_mutex_lock(&locallock); }
-static void unlock(void) { pthread_mutex_unlock(&locallock); }
+static int dolock(void) { return pthread_mutex_lock(&locallock); }
+static void dounlock(void) { pthread_mutex_unlock(&locallock); }
+# endif
+
+/* Get a lock. Return 0 on success, a positive errno value on failure,
+ negative if known to be single-threaded so no lock is needed. */
+static int
+lock(void)
+{
+ if (!is_threaded())
+ return -1;
+ return dolock();
+}
+static void
+unlock(bool threaded)
+{
+ if (threaded)
+ dounlock();
+}
+# else
+static int lock(void) { return -1; }
+static void unlock(ATTRIBUTE_MAYBE_UNUSED bool threaded) { }
+# endif
+#endif
+
+#if THREAD_SAFE
+typedef pthread_once_t once_t;
+# define ONCE_INIT PTHREAD_ONCE_INIT
+#else
+typedef bool once_t;
+# define ONCE_INIT false
+#endif
+
+static void
+once(once_t *once_control, void init_routine(void))
+{
+#if THREAD_SAFE
+ pthread_once(once_control, init_routine);
#else
-static int lock(void) { return 0; }
-static void unlock(void) { }
+ if (!*once_control) {
+ *once_control = true;
+ init_routine();
+ }
+#endif
+}
+
+enum tm_multi { LOCALTIME_TM_MULTI, GMTIME_TM_MULTI, OFFTIME_TM_MULTI };
+
+#if THREAD_SAFE && THREAD_TM_MULTI
+
+enum { N_TM_MULTI = OFFTIME_TM_MULTI + 1 };
+static pthread_key_t tm_multi_key;
+static int tm_multi_key_err;
+
+static void
+tm_multi_key_init(void)
+{
+ tm_multi_key_err = pthread_key_create(&tm_multi_key, free);
+}
+
#endif
/* Unless intptr_t is missing, pacify gcc -Wcast-qual on char const * exprs.
@@ -81,6 +210,47 @@ typedef intmax_t iinntt;
#endif
static_assert(IINNTT_MIN < INT_MIN && INT_MAX < IINNTT_MAX);
+#ifndef HAVE_STRUCT_TIMESPEC
+# define HAVE_STRUCT_TIMESPEC 1
+#endif
+#if !HAVE_STRUCT_TIMESPEC
+struct timespec { time_t tv_sec; long tv_nsec; };
+#endif
+
+#if !defined CLOCK_MONOTONIC_COARSE && defined CLOCK_MONOTONIC
+# define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
+#endif
+#ifndef CLOCK_MONOTONIC_COARSE
+# undef clock_gettime
+# define clock_gettime(id, t) ((t)->tv_sec = time(NULL), (t)->tv_nsec = 0, 0)
+#endif
+
+/* How many seconds to wait before checking the default TZif file again.
+ Negative means no checking. Default to 61 if DETECT_TZ_CHANGES
+ (as circa 2025 FreeBSD builds its localtime.c with -DDETECT_TZ_CHANGES),
+ and to -1 otherwise. */
+#ifndef TZ_CHANGE_INTERVAL
+# ifdef DETECT_TZ_CHANGES
+# define TZ_CHANGE_INTERVAL 61
+# else
+# define TZ_CHANGE_INTERVAL (-1)
+# endif
+#endif
+static_assert(TZ_CHANGE_INTERVAL < 0 || HAVE_SYS_STAT_H);
+
+/* The change detection interval. */
+#if TZ_CHANGE_INTERVAL < 0 || !defined __FreeBSD__
+enum { tz_change_interval = TZ_CHANGE_INTERVAL };
+#else
+/* FreeBSD uses this private-but-extern var in its internal test suite. */
+int __tz_change_interval = TZ_CHANGE_INTERVAL;
+# define tz_change_interval __tz_change_interval
+#endif
+
+/* The type of monotonic times.
+ This is the system time_t, even if USE_TIMEX_T #defines time_t below. */
+typedef time_t monotime_t;
+
/* On platforms where offtime or mktime might overflow,
strftime.c defines USE_TIMEX_T to be true and includes us.
This tells us to #define time_t to an internal type timex_t that is
@@ -89,9 +259,6 @@ static_assert(IINNTT_MIN < INT_MIN && INT_MAX < IINNTT_MAX);
to a static function that returns the redefined time_t.
It also tells us to define only data and code needed
to support the offtime or mktime variant. */
-#ifndef USE_TIMEX_T
-# define USE_TIMEX_T false
-#endif
#if USE_TIMEX_T
# undef TIME_T_MIN
# undef TIME_T_MAX
@@ -99,16 +266,16 @@ static_assert(IINNTT_MIN < INT_MIN && INT_MAX < IINNTT_MAX);
# define time_t timex_t
# if MKTIME_FITS_IN(LONG_MIN, LONG_MAX)
typedef long timex_t;
-# define TIME_T_MIN LONG_MIN
-# define TIME_T_MAX LONG_MAX
+# define TIME_T_MIN LONG_MIN
+# define TIME_T_MAX LONG_MAX
# elif MKTIME_FITS_IN(LLONG_MIN, LLONG_MAX)
typedef long long timex_t;
-# define TIME_T_MIN LLONG_MIN
-# define TIME_T_MAX LLONG_MAX
+# define TIME_T_MIN LLONG_MIN
+# define TIME_T_MAX LLONG_MAX
# else
typedef intmax_t timex_t;
-# define TIME_T_MIN INTMAX_MIN
-# define TIME_T_MAX INTMAX_MAX
+# define TIME_T_MIN INTMAX_MIN
+# define TIME_T_MAX INTMAX_MAX
# endif
# ifdef TM_GMTOFF
@@ -121,14 +288,11 @@ typedef intmax_t timex_t;
# endif
#endif
-#ifndef TZ_ABBR_CHAR_SET
-# define TZ_ABBR_CHAR_SET \
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
-#endif /* !defined TZ_ABBR_CHAR_SET */
-
-#ifndef TZ_ABBR_ERR_CHAR
-# define TZ_ABBR_ERR_CHAR '_'
-#endif /* !defined TZ_ABBR_ERR_CHAR */
+/* Placeholders for platforms lacking openat. */
+#ifndef AT_FDCWD
+# define AT_FDCWD (-1) /* any negative value will do */
+static int openat(int dd, char const *path, int oflag) { unreachable (); }
+#endif
/* Port to platforms that lack some O_* flags. Unless otherwise
specified, the flags are standardized by POSIX. */
@@ -142,12 +306,76 @@ typedef intmax_t timex_t;
#ifndef O_CLOFORK
# define O_CLOFORK 0
#endif
+#ifndef O_DIRECTORY
+# define O_DIRECTORY 0
+#endif
#ifndef O_IGNORE_CTTY
# define O_IGNORE_CTTY 0 /* GNU/Hurd */
#endif
#ifndef O_NOCTTY
# define O_NOCTTY 0
#endif
+#ifndef O_PATH
+# define O_PATH 0
+#endif
+#ifndef O_REGULAR
+# define O_REGULAR 0
+#endif
+#ifndef O_RESOLVE_BENEATH
+# define O_RESOLVE_BENEATH 0
+#endif
+#ifndef O_SEARCH
+# define O_SEARCH 0
+#endif
+
+#if !HAVE_ISSETUGID
+
+# if !defined HAVE_SYS_AUXV_H && defined __has_include
+# if __has_include(<sys/auxv.h>)
+# define HAVE_SYS_AUXV_H 1
+# endif
+# endif
+# ifndef HAVE_SYS_AUXV_H
+# if defined __GLIBC__ && 2 < __GLIBC__ + (19 <= __GLIBC_MINOR__)
+# define HAVE_SYS_AUXV_H 1
+# else
+# define HAVE_SYS_AUXV_H 0
+# endif
+# endif
+# if HAVE_SYS_AUXV_H
+# include <sys/auxv.h>
+# endif
+
+/* Return 1 if the process is privileged, 0 otherwise. */
+static int
+issetugid(void)
+{
+# if HAVE_SYS_AUXV_H && defined AT_SECURE
+ unsigned long val;
+ errno = 0;
+ val = getauxval(AT_SECURE);
+ if (val || errno != ENOENT)
+ return !!val;
+# endif
+# if HAVE_GETRESUID
+ {
+ uid_t ruid, euid, suid;
+ gid_t rgid, egid, sgid;
+ if (0 <= getresuid (&ruid, &euid, &suid)) {
+ if ((ruid ^ euid) | (ruid ^ suid))
+ return 1;
+ if (0 <= getresgid (&rgid, &egid, &sgid))
+ return !!((rgid ^ egid) | (rgid ^ sgid));
+ }
+ }
+# endif
+# if HAVE_GETEUID
+ return geteuid() != getuid() || getegid() != getgid();
+# else
+ return 0;
+# endif
+}
+#endif
#ifndef WILDABBR
/*
@@ -181,7 +409,7 @@ static char const *utc = etc_utc + sizeof "Etc/" - 1;
#endif
/*
-** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
+** The DST rules to use if TZ has no rules.
** Default to US rules as of 2017-05-07.
** POSIX does not specify the default DST rules;
** for historical reasons, US rules are a common default.
@@ -190,6 +418,26 @@ static char const *utc = etc_utc + sizeof "Etc/" - 1;
# define TZDEFRULESTRING ",M3.2.0,M11.1.0"
#endif
+/* If compiled with -DOPENAT_TZDIR, then when accessing a relative
+ name like "America/Los_Angeles", first open TZDIR (default
+ "/usr/share/zoneinfo") as a directory and then use the result in
+ openat with "America/Los_Angeles", rather than the traditional
+ approach of opening "/usr/share/zoneinfo/America/Los_Angeles".
+ Although the OPENAT_TZDIR approach is less efficient, suffers from
+ spurious EMFILE and ENFILE failures, and is no more secure in practice,
+ it is how bleeding edge FreeBSD did things from August 2025
+ through at least September 2025. */
+#ifndef OPENAT_TZDIR
+# define OPENAT_TZDIR 0
+#endif
+
+/* If compiled with -DSUPPRESS_TZDIR, do not prepend TZDIR to relative TZ.
+ This is intended for specialized applications only, due to its
+ security implications. */
+#ifndef SUPPRESS_TZDIR
+# define SUPPRESS_TZDIR 0
+#endif
+
/* Limit to time zone abbreviation length in proleptic TZ strings.
This is distinct from TZ_MAX_CHARS, which limits TZif file contents.
It defaults to 254, not 255, so that desigidx_type can be an unsigned char.
@@ -211,8 +459,19 @@ typedef ptrdiff_t desigidx_type;
# error "TZNAME_MAXIMUM too large"
#endif
+/* A type that can represent any 32-bit two's complement integer,
+ i.e., any integer in the range -2**31 .. 2**31 - 1.
+ Ordinarily this is int_fast32_t, but on non-C23 hosts
+ that are not two's complement it is int_fast64_t. */
+#if INT_FAST32_MIN < -TWO_31_MINUS_1
+typedef int_fast32_t int_fast32_2s;
+#else
+typedef int_fast64_t int_fast32_2s;
+#endif
+
struct ttinfo { /* time type information */
- int_least32_t tt_utoff; /* UT offset in seconds */
+ int_least32_t tt_utoff; /* UT offset in seconds; in the range
+ -2**31 + 1 .. 2**31 - 1 */
desigidx_type tt_desigidx; /* abbreviation list index */
bool tt_isdst; /* used to set tm_isdst */
bool tt_ttisstd; /* transition is std time */
@@ -220,8 +479,8 @@ struct ttinfo { /* time type information */
};
struct lsinfo { /* leap second information */
- time_t ls_trans; /* transition time */
- int_fast32_t ls_corr; /* correction to apply */
+ time_t ls_trans; /* transition time (positive) */
+ int_fast32_2s ls_corr; /* correction to apply */
};
/* This abbreviation means local time is unspecified. */
@@ -239,7 +498,9 @@ enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 };
are put on the stack and stacks are relatively small on some platforms.
See tzfile.h for more about the sizes. */
struct state {
+#if TZ_RUNTIME_LEAPS
int leapcnt;
+#endif
int timecnt;
int typecnt;
int charcnt;
@@ -250,9 +511,48 @@ struct state {
struct ttinfo ttis[TZ_MAX_TYPES];
char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"),
2 * (TZNAME_MAXIMUM + 1))];
+#if TZ_RUNTIME_LEAPS
struct lsinfo lsis[TZ_MAX_LEAPS];
+#endif
};
+static int
+leapcount(ATTRIBUTE_MAYBE_UNUSED struct state const *sp)
+{
+#if TZ_RUNTIME_LEAPS
+ return sp->leapcnt;
+#else
+ return 0;
+#endif
+}
+static void
+set_leapcount(ATTRIBUTE_MAYBE_UNUSED struct state *sp,
+ ATTRIBUTE_MAYBE_UNUSED int leapcnt)
+{
+#if TZ_RUNTIME_LEAPS
+ sp->leapcnt = leapcnt;
+#endif
+}
+static struct lsinfo
+lsinfo(ATTRIBUTE_MAYBE_UNUSED struct state const *sp,
+ ATTRIBUTE_MAYBE_UNUSED int i)
+{
+#if TZ_RUNTIME_LEAPS
+ return sp->lsis[i];
+#else
+ unreachable();
+#endif
+}
+static void
+set_lsinfo(ATTRIBUTE_MAYBE_UNUSED struct state *sp,
+ ATTRIBUTE_MAYBE_UNUSED int i,
+ ATTRIBUTE_MAYBE_UNUSED struct lsinfo lsinfo)
+{
+#if TZ_RUNTIME_LEAPS
+ sp->lsis[i] = lsinfo;
+#endif
+}
+
enum r_type {
JULIAN_DAY, /* Jn = Julian day */
DAY_OF_YEAR, /* n = day of year */
@@ -267,30 +567,31 @@ struct rule {
int_fast32_t r_time; /* transition time of rule */
};
-#ifdef __FreeBSD__
-static void tzset_unlocked_name(char const *);
-#endif /* __FreeBSD__ */
static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
struct tm *);
static bool increment_overflow(int *, int);
-static bool increment_overflow_time(time_t *, int_fast32_t);
-static int_fast32_t leapcorr(struct state const *, time_t);
+static bool increment_overflow_time(time_t *, int_fast32_2s);
+static int_fast32_2s leapcorr(struct state const *, time_t);
static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
struct tm *);
static bool tzparse(char const *, struct state *, struct state const *);
-#ifdef ALL_STATE
+#ifndef ALL_STATE
+# define ALL_STATE 0
+#endif
+
+#if ALL_STATE
static struct state * lclptr;
static struct state * gmtptr;
-#endif /* defined ALL_STATE */
-
-#ifndef ALL_STATE
+#else
static struct state lclmem;
static struct state gmtmem;
static struct state *const lclptr = &lclmem;
static struct state *const gmtptr = &gmtmem;
#endif /* State Farm */
+/* Maximum number of bytes in an efficiently-handled TZ string.
+ Longer strings work, albeit less efficiently. */
#ifndef TZ_STRLEN_MAX
# define TZ_STRLEN_MAX 255
#endif /* !defined TZ_STRLEN_MAX */
@@ -299,18 +600,6 @@ static struct state *const gmtptr = &gmtmem;
static char lcl_TZname[TZ_STRLEN_MAX + 1];
static int lcl_is_set;
#endif
-#ifdef __FreeBSD__
-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;
-#endif /* __FreeBSD__ */
/*
** Section 4.12.3 of X3.159-1989 requires that
@@ -328,7 +617,7 @@ static int localtime_key_error;
# if SUPPORT_C89
static struct tm tm;
-#endif
+# endif
# if 2 <= HAVE_TZNAME + TZ_TIME_T
char *tzname[2] = { UNCONST(wildabbr), UNCONST(wildabbr) };
@@ -364,15 +653,14 @@ ttunspecified(struct state const *sp, int i)
return memcmp(abbr, UNSPEC, sizeof UNSPEC) == 0;
}
-static int_fast32_t
+static int_fast32_2s
detzcode(const char *const codep)
{
- register int_fast32_t result;
register int i;
- int_fast32_t one = 1;
- int_fast32_t halfmaxval = one << (32 - 2);
- int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
- int_fast32_t minval = -1 - maxval;
+ int_fast32_2s
+ maxval = TWO_31_MINUS_1,
+ minval = -1 - maxval,
+ result;
result = codep[0] & 0x7f;
for (i = 1; i < 4; ++i)
@@ -380,8 +668,7 @@ detzcode(const char *const codep)
if (codep[0] & 0x80) {
/* Do two's-complement negation even on non-two's-complement machines.
- If the result would be minval - 1, return minval. */
- result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
+ This cannot overflow, as int_fast32_2s is wide enough. */
result += minval;
}
return result;
@@ -492,7 +779,7 @@ scrub_abbrs(struct state *sp)
/* Reject overlong abbreviations. */
for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) {
- int len = strlen(&sp->chars[i]);
+ int len = strnlen(&sp->chars[i], TZNAME_MAXIMUM + 1);
if (TZNAME_MAXIMUM < len)
return EOVERFLOW;
i += len + 1;
@@ -500,49 +787,74 @@ scrub_abbrs(struct state *sp)
/* 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;
+ switch (sp->chars[i]) {
+ case '\0':
+ case '+': case '-': case '.':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case ':':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+ case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+ case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+ case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+ case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
+ case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
+ case 'v': case 'w': case 'x': case 'y': case 'z':
+ break;
+
+ default:
+ sp->chars[i] = '_';
+ break;
+ }
return 0;
}
#endif
-#ifdef DETECT_TZ_CHANGES
-/*
- * Check whether either the time zone name or the file it refers to has
- * changed since the last time we checked.
- * Returns: -1 on error
- * 0 if the time zone has not changed
- * 1 if the time zone has changed
- */
-static int
-tzfile_changed(const char *name, int fd)
+/* Return true if the TZif file with descriptor FD changed,
+ or may have changed, since the last time we were called.
+ Return false if it did not change.
+ If *ST is valid it is the file's current status;
+ otherwise, update *ST to the status if possible. */
+static bool
+tzfile_changed(int fd, struct stat *st)
{
- static char old_name[PATH_MAX];
- static struct stat old_sb;
- struct stat sb;
-
- if (fstat(fd, &sb) != 0)
- return -1;
+ /* If old_ctim.tv_sec, these variables hold the corresponding part
+ of the file's metadata the last time this function was called. */
+ static struct timespec old_ctim;
+ static dev_t old_dev;
+ static ino_t old_ino;
- if (strcmp(name, old_name) != 0) {
- strlcpy(old_name, name, sizeof(old_name));
- old_sb = sb;
- return 1;
- }
+ if (!st->st_ctime && fstat(fd, st) < 0) {
+ /* We do not know the file's state, so reset. */
+ old_ctim.tv_sec = 0;
+ return true;
+ } else {
+ /* Use the change time, as it changes more reliably; mod time can
+ be set back with futimens etc. Use subsecond timestamp
+ resolution if available, as this can help distinguish files on
+ non-POSIX platforms where st_dev and st_ino are unreliable. */
+ struct timespec ctim;
+#if HAVE_STRUCT_STAT_ST_CTIM
+ ctim = st->st_ctim;
+#else
+ ctim.tv_sec = st->st_ctime;
+ ctim.tv_nsec = 0;
+#endif
- if (sb.st_dev != old_sb.st_dev ||
- sb.st_ino != old_sb.st_ino ||
- sb.st_ctime != old_sb.st_ctime ||
- sb.st_mtime != old_sb.st_mtime) {
- old_sb = sb;
- return 1;
- }
+ if ((ctim.tv_sec ^ old_ctim.tv_sec) | (ctim.tv_nsec ^ old_ctim.tv_nsec)
+ | (st->st_dev ^ old_dev) | (st->st_ino ^ old_ino)) {
+ old_ctim = ctim;
+ old_dev = st->st_dev;
+ old_ino = st->st_ino;
+ return true;
+ }
- return 0;
+ return false;
+ }
}
-#endif /* DETECT_TZ_CHANGES */
/* Input buffer for data read from a compiled tz file. */
union input_buffer {
@@ -555,10 +867,15 @@ union input_buffer {
+ 4 * TZ_MAX_TIMES];
};
-#ifndef __FreeBSD__
-/* TZDIR with a trailing '/' rather than a trailing '\0'. */
-static char const tzdirslash[sizeof TZDIR] = TZDIR "/";
-#endif /* !__FreeBSD__ */
+/* TZDIR with a trailing '/'. It is null-terminated if OPENAT_TZDIR. */
+#if !OPENAT_TZDIR
+ATTRIBUTE_NONSTRING
+#endif
+static char const tzdirslash[sizeof TZDIR + OPENAT_TZDIR] = TZDIR "/";
+enum { tzdirslashlen = sizeof TZDIR };
+#ifdef PATH_MAX
+static_assert(tzdirslashlen <= PATH_MAX); /* Sanity check; assumed below. */
+#endif
/* Local storage needed for 'tzloadbody'. */
union local_storage {
@@ -571,41 +888,38 @@ union local_storage {
struct state st;
} u;
-#ifndef __FreeBSD__
- /* The name of the file to be opened. Ideally this would have no
- size limits, to support arbitrarily long Zone names.
- Limiting Zone names to 1024 bytes should suffice for practical use.
- However, there is no need for this to be smaller than struct
- file_analysis as that struct is allocated anyway, as the other
- union member. */
- char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)];
-#endif /* !__FreeBSD__ */
+#if defined PATH_MAX && !OPENAT_TZDIR && !SUPPRESS_TZDIR
+ /* The name of the file to be opened. */
+ char fullname[PATH_MAX];
+#endif
};
/* These tzload flags can be ORed together, and fit into 'char'. */
enum { TZLOAD_FROMENV = 1 }; /* The TZ string came from the environment. */
enum { TZLOAD_TZSTRING = 2 }; /* Read any newline-surrounded TZ string. */
+enum { TZLOAD_TZDIR_SUB = 4 }; /* TZ should be a file under TZDIR. */
/* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS.
- Use *LSP for temporary storage. Return 0 on
+ Use **LSPP for temporary storage. Return 0 on
success, an errno value on failure. */
static int
tzloadbody(char const *name, struct state *sp, char tzloadflags,
- union local_storage *lsp)
+ union local_storage **lspp)
{
register int i;
register int fid;
register int stored;
register ssize_t nread;
-#ifdef __FreeBSD__
- struct stat sb;
- const char *relname;
- int dd, serrno;
-#else /* !__FreeBSD__ */
- register bool doaccess;
-#endif /* !__FreeBSD__ */
- register union input_buffer *up = &lsp->u.u;
+ char const *relname;
+ union local_storage *lsp = *lspp;
+ union input_buffer *up;
register int tzheadsize = sizeof(struct tzhead);
+ int dd = AT_FDCWD;
+ int oflags = (O_RDONLY | O_BINARY | O_CLOEXEC | O_CLOFORK
+ | O_IGNORE_CTTY | O_NOCTTY | O_REGULAR);
+ int err;
+ struct stat st;
+ st.st_ctime = 0;
sp->goback = sp->goahead = false;
@@ -613,148 +927,149 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
name = TZDEFAULT;
if (! name)
return EINVAL;
+#ifdef __FreeBSD__
tzloadflags &= ~TZLOAD_FROMENV;
+#endif /* __FreeBSD__ */
}
if (name[0] == ':')
++name;
-#ifndef __FreeBSD__
-#ifdef SUPPRESS_TZDIR
- /* Do not prepend TZDIR. This is intended for specialized
- applications only, due to its security implications. */
- doaccess = true;
-#else
- doaccess = name[0] == '/';
-#endif
- if (!doaccess) {
- char const *dot;
- if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
- return ENAMETOOLONG;
- /* Create a string "TZDIR/NAME". Using sprintf here
- would pull in stdio (and would fail if the
- resulting string length exceeded INT_MAX!). */
- memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
- strcpy(lsp->fullname + sizeof tzdirslash, name);
-
- /* Set doaccess if NAME contains a ".." file name
- component, as such a name could read a file outside
- the TZDIR virtual subtree. */
- for (dot = name; (dot = strchr(dot, '.')); dot++)
- if ((dot == name || dot[-1] == '/') && dot[1] == '.'
- && (dot[2] == '/' || !dot[2])) {
- doaccess = true;
- break;
- }
+ relname = name;
- name = lsp->fullname;
- }
- if (doaccess && (tzloadflags & TZLOAD_FROMENV)) {
- /* Check for security violations and for devices whose mere
- opening could have unwanted side effects. Although these
- checks are racy, they're better than nothing and there is
- no portable way to fix the races. */
- if (access(name, R_OK) < 0)
- return errno;
-#ifdef S_ISREG
- {
- struct stat st;
+ /* If the program is privileged, NAME is TZDEFAULT or
+ subsidiary to TZDIR. Also, NAME is not a device. */
+ if (name[0] == '/' && strcmp(name, TZDEFAULT) != 0) {
+ if (!SUPPRESS_TZDIR
+ && strncmp(relname, tzdirslash, tzdirslashlen) == 0)
+ for (relname += tzdirslashlen; *relname == '/'; relname++)
+ continue;
+ else if (issetugid())
+ return ENOTCAPABLE;
+ else if (!O_REGULAR) {
+ /* Check for devices, as their mere opening could have
+ unwanted side effects. Though racy, there is no
+ portable way to fix the races. This check is needed
+ only for files not otherwise known to be non-devices. */
if (stat(name, &st) < 0)
return errno;
if (!S_ISREG(st.st_mode))
return EINVAL;
}
-#endif
}
- fid = open(name, (O_RDONLY | O_BINARY | O_CLOEXEC | O_CLOFORK
- | O_IGNORE_CTTY | O_NOCTTY));
-#else /* __FreeBSD__ */
- if ((tzloadflags & TZLOAD_FROMENV) && strcmp(name, TZDEFAULT) == 0)
- tzloadflags &= ~TZLOAD_FROMENV;
- relname = name;
- if (strncmp(relname, TZDIR "/", strlen(TZDIR) + 1) == 0) {
- relname += strlen(TZDIR) + 1;
- while (*relname == '/')
- relname++;
- }
- dd = open(TZDIR, O_DIRECTORY | O_SEARCH | O_CLOEXEC);
- if ((tzloadflags & TZLOAD_FROMENV) && issetugid()) {
- if (dd < 0)
- return errno;
- if (fstatat(dd, relname, &sb, AT_RESOLVE_BENEATH) < 0) {
- fid = -1;
- } else if (!S_ISREG(sb.st_mode)) {
- fid = -1;
- errno = EINVAL;
- } else {
- fid = openat(dd, relname, O_RDONLY | O_CLOEXEC | O_RESOLVE_BENEATH);
+
+ if (relname[0] != '/') {
+ if (!OPENAT_TZDIR || !O_RESOLVE_BENEATH) {
+ /* Fail if a relative name contains a non-terminal ".." component,
+ as such a name could read a non-directory outside TZDIR
+ when AT_FDCWD and O_RESOLVE_BENEATH are not available. */
+ char const *component;
+ for (component = relname; component[0]; component++)
+ if (component[0] == '.' && component[1] == '.'
+ && component[2] == '/'
+ && (component == relname || component[-1] == '/'))
+ return ENOTCAPABLE;
}
- } else {
- if (dd < 0) {
- relname = name;
- dd = AT_FDCWD;
+
+ if (OPENAT_TZDIR && !SUPPRESS_TZDIR) {
+ /* Prefer O_SEARCH or O_PATH if available;
+ O_RDONLY should be OK too, as TZDIR is invariably readable.
+ O_DIRECTORY should be redundant but might help
+ on old platforms that mishandle trailing '/'. */
+ dd = open(tzdirslash,
+ ((O_SEARCH ? O_SEARCH : O_PATH ? O_PATH : O_RDONLY)
+ | O_BINARY | O_CLOEXEC | O_CLOFORK | O_DIRECTORY));
+ if (dd < 0)
+ return errno;
+#ifdef __FreeBSD__
+ if (issetugid())
+#endif /* __FreeBSD__ */
+ oflags |= O_RESOLVE_BENEATH;
}
- fid = openat(dd, relname, O_RDONLY | O_CLOEXEC);
}
- if (dd != AT_FDCWD && dd >= 0) {
- serrno = errno;
- close(dd);
- errno = serrno;
+
+ if (!OPENAT_TZDIR && !SUPPRESS_TZDIR && name[0] != '/') {
+ char *cp;
+ size_t fullnamesize;
+#ifdef PATH_MAX
+ size_t namesizemax = PATH_MAX - tzdirslashlen;
+ size_t namelen = strnlen (name, namesizemax);
+ if (namesizemax <= namelen)
+ return ENAMETOOLONG;
+#else
+ size_t namelen = strlen (name);
+#endif
+ fullnamesize = tzdirslashlen + namelen + 1;
+
+ /* Create a string "TZDIR/NAME". Using sprintf here
+ would pull in stdio (and would fail if the
+ resulting string length exceeded INT_MAX!). */
+ if (ALL_STATE || sizeof *lsp < fullnamesize) {
+ lsp = malloc(max(sizeof *lsp, fullnamesize));
+ if (!lsp)
+ return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
+ *lspp = lsp;
+ }
+ cp = mempcpy(lsp, tzdirslash, tzdirslashlen);
+ cp = mempcpy(cp, name, namelen);
+ *cp = '\0';
+#if defined PATH_MAX && !OPENAT_TZDIR && !SUPPRESS_TZDIR
+ name = lsp->fullname;
+#else
+ name = (char *) lsp;
+#endif
}
-#endif /* __FreeBSD__ */
+
+ fid = OPENAT_TZDIR ? openat(dd, relname, oflags) : open(name, oflags);
+ err = errno;
+ if (0 <= dd)
+ close(dd);
if (fid < 0)
- return errno;
-
-#ifdef DETECT_TZ_CHANGES
- if (tzloadflags) {
- /*
- * Detect if the timezone file has changed. Check tzloadflags
- * to ignore TZDEFRULES; the tzfile_changed() function can only
- * keep state for a single file.
- */
- switch (tzfile_changed(name, fid)) {
- case -1:
- serrno = errno;
- close(fid);
- return serrno;
- case 0:
- close(fid);
- return 0;
- case 1:
- break;
- }
- }
-#endif /* DETECT_TZ_CHANGES */
- nread = read(fid, up->buf, sizeof up->buf);
- if (nread < tzheadsize) {
- int err = nread < 0 ? errno : EINVAL;
- close(fid);
return err;
+
+ /* If detecting changes to the the primary TZif file's state and
+ the file's status is unchanged, save time by returning now.
+ Otherwise read the file's contents. Close the file either way. */
+ if (0 <= tz_change_interval && (tzloadflags & TZLOAD_FROMENV)
+ && !tzfile_changed(fid, &st))
+ err = -1;
+ else {
+ if (ALL_STATE && !lsp) {
+ lsp = malloc(sizeof *lsp);
+ if (!lsp)
+ return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
+ *lspp = lsp;
+ }
+ up = &lsp->u.u;
+ nread = read(fid, up->buf, sizeof up->buf);
+ err = tzheadsize <= nread ? 0 : nread < 0 ? errno : EINVAL;
}
- if (close(fid) < 0)
- return errno;
+ close(fid);
+ if (err)
+ return err < 0 ? 0 : err;
+
for (stored = 4; stored <= 8; stored *= 2) {
char version = up->tzhead.tzh_version[0];
bool skip_datablock = stored == 4 && version;
int_fast32_t datablock_size;
- int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
- int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
- int_fast64_t prevtr = -1;
- int_fast32_t prevcorr;
- int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
- int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
- int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
- int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
+ int_fast32_2s
+ ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt),
+ ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt),
+ leapcnt = detzcode(up->tzhead.tzh_leapcnt),
+ timecnt = detzcode(up->tzhead.tzh_timecnt),
+ typecnt = detzcode(up->tzhead.tzh_typecnt),
+ charcnt = detzcode(up->tzhead.tzh_charcnt);
char const *p = up->buf + tzheadsize;
/* Although tzfile(5) currently requires typecnt to be nonzero,
support future formats that may allow zero typecnt
in files that have a TZ string and no transitions. */
- if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
- && 0 <= typecnt && typecnt < TZ_MAX_TYPES
- && 0 <= timecnt && timecnt < TZ_MAX_TIMES
- && 0 <= charcnt && charcnt < TZ_MAX_CHARS
- && 0 <= ttisstdcnt && ttisstdcnt < TZ_MAX_TYPES
- && 0 <= ttisutcnt && ttisutcnt < TZ_MAX_TYPES))
+ if (! (0 <= leapcnt
+ && leapcnt <= (TZ_RUNTIME_LEAPS ? TZ_MAX_LEAPS : 0)
+ && 0 <= typecnt && typecnt <= TZ_MAX_TYPES
+ && 0 <= timecnt && timecnt <= TZ_MAX_TIMES
+ && 0 <= charcnt && charcnt <= TZ_MAX_CHARS
+ && 0 <= ttisstdcnt && ttisstdcnt <= TZ_MAX_TYPES
+ && 0 <= ttisutcnt && ttisutcnt <= TZ_MAX_TYPES))
return EINVAL;
datablock_size
= (timecnt * stored /* ats */
@@ -768,12 +1083,13 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
return EINVAL;
if (skip_datablock)
p += datablock_size;
+ else if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0)
+ && (ttisutcnt == typecnt || ttisutcnt == 0)))
+ return EINVAL;
else {
- if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0)
- && (ttisutcnt == typecnt || ttisutcnt == 0)))
- return EINVAL;
-
- sp->leapcnt = leapcnt;
+ int_fast64_t prevtr = -1;
+ int_fast32_2s prevcorr;
+ set_leapcount(sp, leapcnt);
sp->timecnt = timecnt;
sp->typecnt = typecnt;
sp->charcnt = charcnt;
@@ -813,9 +1129,16 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
for (i = 0; i < sp->typecnt; ++i) {
register struct ttinfo * ttisp;
unsigned char isdst, desigidx;
+ int_fast32_2s utoff = detzcode(p);
+
+ /* Reject a UT offset equal to -2**31, as it might
+ cause trouble both in this file and in callers.
+ Also, it violates RFC 9636 section 3.2. */
+ if (utoff < -TWO_31_MINUS_1)
+ return EINVAL;
ttisp = &sp->ttis[i];
- ttisp->tt_utoff = detzcode(p);
+ ttisp->tt_utoff = utoff;
p += 4;
isdst = *p++;
if (! (isdst < 2))
@@ -834,9 +1157,9 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
/* Read leap seconds, discarding those out of time_t range. */
leapcnt = 0;
- for (i = 0; i < sp->leapcnt; ++i) {
+ for (i = 0; i < leapcount(sp); i++) {
int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
- int_fast32_t corr = detzcode(p + stored);
+ int_fast32_2s corr = detzcode(p + stored);
p += stored + 4;
/* Leap seconds cannot occur before the Epoch,
@@ -859,12 +1182,14 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
prevcorr = corr;
if (tr <= TIME_T_MAX) {
- sp->lsis[leapcnt].ls_trans = tr;
- sp->lsis[leapcnt].ls_corr = corr;
+ struct lsinfo ls;
+ ls.ls_trans = tr;
+ ls.ls_corr = corr;
+ set_lsinfo(sp, leapcnt, ls);
leapcnt++;
}
}
- sp->leapcnt = leapcnt;
+ set_leapcount(sp, leapcnt);
for (i = 0; i < sp->typecnt; ++i) {
register struct ttinfo * ttisp;
@@ -908,8 +1233,8 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
if (tzparse(&up->buf[1], ts, sp)) {
/* Attempt to reuse existing abbreviations.
- Without this, America/Anchorage would be right on
- the edge after 2037 when TZ_MAX_CHARS is 50, as
+ Without this, America/Anchorage would
+ consume 50 bytes for abbreviations, as
sp->charcnt equals 40 (for LMT AST AWT APT AHST
AHDT YST AKDT AKST) and ts->charcnt equals 10
(for AKST AKDT). Reusing means sp->charcnt can
@@ -926,9 +1251,11 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
break;
}
if (! (j < charcnt)) {
- int tsabbrlen = strlen(tsabbr);
+ int tsabbrlen = strnlen(tsabbr, TZ_MAX_CHARS - j);
if (j + tsabbrlen < TZ_MAX_CHARS) {
- strcpy(sp->chars + j, tsabbr);
+ char *cp = sp->chars + j;
+ cp = mempcpy(cp, tsabbr, tsabbrlen);
+ *cp = '\0';
charcnt = j + tsabbrlen + 1;
ts->ttis[i].tt_desigidx = j;
gotabbr++;
@@ -979,19 +1306,20 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
static int
tzload(char const *name, struct state *sp, char tzloadflags)
{
-#ifdef ALL_STATE
- union local_storage *lsp = malloc(sizeof *lsp);
- if (!lsp) {
- return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
- } else {
- int err = tzloadbody(name, sp, tzloadflags, lsp);
- free(lsp);
- return err;
- }
+ int r;
+ union local_storage *lsp0;
+ union local_storage *lsp;
+#if ALL_STATE
+ lsp = NULL;
#else
union local_storage ls;
- return tzloadbody(name, sp, tzloadflags, &ls);
+ lsp = &ls;
#endif
+ lsp0 = lsp;
+ r = tzloadbody(name, sp, tzloadflags, &lsp);
+ if (lsp != lsp0)
+ free(lsp);
+ return r;
}
static const int mon_lengths[2][MONSPERYEAR] = {
@@ -1301,7 +1629,6 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
int_fast32_t stdoffset;
int_fast32_t dstoffset;
register char * cp;
- register bool load_ok;
ptrdiff_t stdlen, dstlen, charcnt;
time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
@@ -1327,18 +1654,22 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
if (basep) {
if (0 < basep->timecnt)
atlo = basep->ats[basep->timecnt - 1];
- load_ok = false;
- sp->leapcnt = basep->leapcnt;
- memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis);
- } else {
- load_ok = tzload(TZDEFRULES, sp, 0) == 0;
- if (!load_ok)
- sp->leapcnt = 0; /* So, we're off a little. */
- }
- if (0 < sp->leapcnt)
- leaplo = sp->lsis[sp->leapcnt - 1].ls_trans;
+ set_leapcount(sp, leapcount(basep));
+ if (0 < leapcount(sp)) {
+ int i;
+ for (i = 0; i < leapcount(sp); i++)
+ set_lsinfo(sp, i, lsinfo(basep, i));
+ leaplo = lsinfo(sp, leapcount(sp) - 1).ls_trans;
+ }
+ } else
+ set_leapcount(sp, 0); /* So, we're off a little. */
sp->goback = sp->goahead = false;
if (*name != '\0') {
+ struct rule start, end;
+ int year, yearbeg, yearlim, timecnt;
+ time_t janfirst;
+ int_fast32_t janoffset = 0;
+
if (*name == '<') {
dstname = ++name;
name = getqzname(name, '>');
@@ -1359,194 +1690,102 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
if (name == NULL)
return false;
} else dstoffset = stdoffset - SECSPERHOUR;
- if (*name == '\0' && !load_ok)
+
+ if (*name == '\0')
name = TZDEFRULESTRING;
- if (*name == ',' || *name == ';') {
- struct rule start;
- struct rule end;
- register int year;
- register int timecnt;
- time_t janfirst;
- int_fast32_t janoffset = 0;
- int yearbeg, yearlim;
-
- ++name;
- if ((name = getrule(name, &start)) == NULL)
- return false;
- if (*name++ != ',')
- return false;
- if ((name = getrule(name, &end)) == NULL)
- return false;
- if (*name != '\0')
- return false;
- sp->typecnt = 2; /* standard time and DST */
- /*
- ** Two transitions per year, from EPOCH_YEAR forward.
- */
- init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
- init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
- timecnt = 0;
- janfirst = 0;
- yearbeg = EPOCH_YEAR;
-
- do {
- int_fast32_t yearsecs
- = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
- time_t janfirst1 = janfirst;
- yearbeg--;
- if (increment_overflow_time(&janfirst1, -yearsecs)) {
- janoffset = -yearsecs;
- break;
- }
- janfirst = janfirst1;
- } while (atlo < janfirst
- && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
-
- while (true) {
- int_fast32_t yearsecs
- = year_lengths[isleap(yearbeg)] * SECSPERDAY;
- int yearbeg1 = yearbeg;
- time_t janfirst1 = janfirst;
- if (increment_overflow_time(&janfirst1, yearsecs)
- || increment_overflow(&yearbeg1, 1)
- || atlo <= janfirst1)
- break;
- yearbeg = yearbeg1;
- janfirst = janfirst1;
- }
+ if (! (*name == ',' || *name == ';'))
+ return false;
- yearlim = yearbeg;
- if (increment_overflow(&yearlim, years_of_observations))
- yearlim = INT_MAX;
- for (year = yearbeg; year < yearlim; year++) {
- int_fast32_t
- starttime = transtime(year, &start, stdoffset),
- endtime = transtime(year, &end, dstoffset);
- int_fast32_t
- yearsecs = (year_lengths[isleap(year)]
- * SECSPERDAY);
- bool reversed = endtime < starttime;
- if (reversed) {
- int_fast32_t swap = starttime;
- starttime = endtime;
- endtime = swap;
- }
- if (reversed
- || (starttime < endtime
- && endtime - starttime < yearsecs)) {
- if (TZ_MAX_TIMES - 2 < timecnt)
- break;
- sp->ats[timecnt] = janfirst;
- if (! increment_overflow_time
- (&sp->ats[timecnt],
- janoffset + starttime)
- && atlo <= sp->ats[timecnt])
- sp->types[timecnt++] = !reversed;
- sp->ats[timecnt] = janfirst;
- if (! increment_overflow_time
- (&sp->ats[timecnt],
- janoffset + endtime)
- && atlo <= sp->ats[timecnt]) {
- sp->types[timecnt++] = reversed;
- }
- }
- if (endtime < leaplo) {
- yearlim = year;
- if (increment_overflow(&yearlim,
- years_of_observations))
- yearlim = INT_MAX;
- }
- if (increment_overflow_time
- (&janfirst, janoffset + yearsecs))
- break;
- janoffset = 0;
- }
- sp->timecnt = timecnt;
- if (! timecnt) {
- sp->ttis[0] = sp->ttis[1];
- sp->typecnt = 1; /* Perpetual DST. */
- } else if (years_of_observations <= year - yearbeg)
- sp->goback = sp->goahead = true;
- } else {
- register int_fast32_t theirstdoffset;
- register int_fast32_t theirdstoffset;
- register int_fast32_t theiroffset;
- register bool isdst;
- register int i;
- register int j;
-
- if (*name != '\0')
- return false;
- /*
- ** Initial values of theirstdoffset and theirdstoffset.
- */
- theirstdoffset = 0;
- for (i = 0; i < sp->timecnt; ++i) {
- j = sp->types[i];
- if (!sp->ttis[j].tt_isdst) {
- theirstdoffset =
- - sp->ttis[j].tt_utoff;
- break;
- }
- }
- theirdstoffset = 0;
- for (i = 0; i < sp->timecnt; ++i) {
- j = sp->types[i];
- if (sp->ttis[j].tt_isdst) {
- theirdstoffset =
- - sp->ttis[j].tt_utoff;
- break;
- }
- }
- /*
- ** Initially we're assumed to be in standard time.
- */
- isdst = false;
- /*
- ** Now juggle transition times and types
- ** tracking offsets as you do.
- */
- for (i = 0; i < sp->timecnt; ++i) {
- j = sp->types[i];
- sp->types[i] = sp->ttis[j].tt_isdst;
- if (sp->ttis[j].tt_ttisut) {
- /* No adjustment to transition time */
- } else {
- /*
- ** If daylight saving time is in
- ** effect, and the transition time was
- ** not specified as standard time, add
- ** the daylight saving time offset to
- ** the transition time; otherwise, add
- ** the standard time offset to the
- ** transition time.
- */
- /*
- ** Transitions from DST to DDST
- ** will effectively disappear since
- ** proleptic TZ strings have only one
- ** DST offset.
- */
- if (isdst && !sp->ttis[j].tt_ttisstd) {
- sp->ats[i] += dstoffset -
- theirdstoffset;
- } else {
- sp->ats[i] += stdoffset -
- theirstdoffset;
- }
- }
- theiroffset = -sp->ttis[j].tt_utoff;
- if (sp->ttis[j].tt_isdst)
- theirdstoffset = theiroffset;
- else theirstdoffset = theiroffset;
- }
- /*
- ** Finally, fill in ttis.
- */
- init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
- init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
- sp->typecnt = 2;
+ name = getrule(name + 1, &start);
+ if (!name)
+ return false;
+ if (*name++ != ',')
+ return false;
+ name = getrule(name, &end);
+ if (!name || *name)
+ return false;
+ sp->typecnt = 2; /* standard time and DST */
+ /*
+ ** Two transitions per year, from EPOCH_YEAR forward.
+ */
+ init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
+ init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
+ timecnt = 0;
+ janfirst = 0;
+ yearbeg = EPOCH_YEAR;
+
+ do {
+ int_fast32_t yearsecs
+ = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
+ time_t janfirst1 = janfirst;
+ yearbeg--;
+ if (increment_overflow_time(&janfirst1, -yearsecs)) {
+ janoffset = -yearsecs;
+ break;
+ }
+ janfirst = janfirst1;
+ } while (atlo < janfirst
+ && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
+
+ while (true) {
+ int_fast32_t yearsecs
+ = year_lengths[isleap(yearbeg)] * SECSPERDAY;
+ int yearbeg1 = yearbeg;
+ time_t janfirst1 = janfirst;
+ if (increment_overflow_time(&janfirst1, yearsecs)
+ || increment_overflow(&yearbeg1, 1)
+ || atlo <= janfirst1)
+ break;
+ yearbeg = yearbeg1;
+ janfirst = janfirst1;
+ }
+
+ yearlim = yearbeg;
+ if (increment_overflow(&yearlim, years_of_observations))
+ yearlim = INT_MAX;
+ for (year = yearbeg; year < yearlim; year++) {
+ int_fast32_t
+ starttime = transtime(year, &start, stdoffset),
+ endtime = transtime(year, &end, dstoffset),
+ yearsecs = year_lengths[isleap(year)] * SECSPERDAY;
+ bool reversed = endtime < starttime;
+ if (reversed) {
+ int_fast32_t swap = starttime;
+ starttime = endtime;
+ endtime = swap;
+ }
+ if (reversed
+ || (starttime < endtime
+ && endtime - starttime < yearsecs)) {
+ if (TZ_MAX_TIMES - 2 < timecnt)
+ break;
+ sp->ats[timecnt] = janfirst;
+ if (! increment_overflow_time(&sp->ats[timecnt],
+ janoffset + starttime)
+ && atlo <= sp->ats[timecnt])
+ sp->types[timecnt++] = !reversed;
+ sp->ats[timecnt] = janfirst;
+ if (! increment_overflow_time(&sp->ats[timecnt],
+ janoffset + endtime)
+ && atlo <= sp->ats[timecnt]) {
+ sp->types[timecnt++] = reversed;
+ }
+ }
+ if (endtime < leaplo) {
+ yearlim = year;
+ if (increment_overflow(&yearlim, years_of_observations))
+ yearlim = INT_MAX;
+ }
+ if (increment_overflow_time(&janfirst, janoffset + yearsecs))
+ break;
+ janoffset = 0;
}
+ sp->timecnt = timecnt;
+ if (! timecnt) {
+ sp->ttis[0] = sp->ttis[1];
+ sp->typecnt = 1; /* Perpetual DST. */
+ } else if (years_of_observations <= year - yearbeg)
+ sp->goback = sp->goahead = true;
} else {
dstlen = 0;
sp->typecnt = 1; /* only standard time */
@@ -1555,12 +1794,11 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
}
sp->charcnt = charcnt;
cp = sp->chars;
- memcpy(cp, stdname, stdlen);
- cp += stdlen;
+ cp = mempcpy(cp, stdname, stdlen);
*cp++ = '\0';
if (dstlen != 0) {
- memcpy(cp, dstname, dstlen);
- *(cp + dstlen) = '\0';
+ cp = mempcpy(cp, dstname, dstlen);
+ *cp = '\0';
}
return true;
}
@@ -1568,34 +1806,27 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
static void
gmtload(struct state *const sp)
{
- if (tzload(etc_utc, sp, TZLOAD_TZSTRING) != 0)
+ if (!TZ_RUNTIME_LEAPS || tzload(etc_utc, sp, TZLOAD_TZSTRING) != 0)
tzparse("UTC0", sp, NULL);
}
-#ifdef DETECT_TZ_CHANGES
-/*
- * Check if the time zone data we have is still fresh.
- */
-static int
-tzdata_is_fresh(void)
-{
- static time_t last_checked;
- struct timespec now;
-
- if (clock_gettime(CLOCK_MONOTONIC, &now) < 0)
- return 1;
+#if !USE_TIMEX_T || !defined TM_GMTOFF
- if (last_checked == 0 || last_checked > now.tv_sec ||
- now.tv_sec - last_checked >= __tz_change_interval) {
- last_checked = now.tv_sec;
- return 0;
- }
+/* Return true if primary cached time zone data are fresh,
+ i.e., if this function is known to have recently returned false.
+ A call is recent if it occurred less than tz_change_interval seconds ago.
+ NOW should be the current time. */
+static bool
+fresh_tzdata(monotime_t now)
+{
+ /* If nonzero, the time of the last false return. */
+ static monotime_t last_checked;
- return 1;
+ if (last_checked && now - last_checked < tz_change_interval)
+ return true;
+ last_checked = now;
+ return false;
}
-#endif /* DETECT_TZ_CHANGES */
-
-#if !USE_TIMEX_T || !defined TM_GMTOFF
/* Initialize *SP to a value appropriate for the TZ setting NAME.
Respect TZLOADFLAGS.
@@ -1607,7 +1838,7 @@ zoneinit(struct state *sp, char const *name, char tzloadflags)
/*
** User wants it fast rather than right.
*/
- sp->leapcnt = 0; /* so, we're off a little */
+ set_leapcount(sp, 0); /* so, we're off a little */
sp->timecnt = 0;
sp->typecnt = 0;
sp->charcnt = 0;
@@ -1617,7 +1848,8 @@ zoneinit(struct state *sp, char const *name, char tzloadflags)
return 0;
} else {
int err = tzload(name, sp, tzloadflags);
- if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL))
+ if (err != 0 && name && name[0] != ':' && !(tzloadflags & TZLOAD_TZDIR_SUB)
+ && tzparse(name, sp, NULL))
err = 0;
if (err == 0)
err = scrub_abbrs(sp);
@@ -1625,32 +1857,78 @@ zoneinit(struct state *sp, char const *name, char tzloadflags)
}
}
-static void
-tzset_unlocked(void)
+/* If THREADED, upgrade a read lock to a write lock.
+ Return 0 on success, a positive errno value otherwise. */
+static int
+rd2wrlock(ATTRIBUTE_MAYBE_UNUSED bool threaded)
{
- char const *name = getenv("TZ");
-#ifdef __FreeBSD__
- tzset_unlocked_name(name);
+# if THREAD_RWLOCK
+ if (threaded) {
+ dounlock();
+ return pthread_rwlock_wrlock(&locallock);
+ }
+# endif
+ return 0;
}
+
+/* Like tzset(), but in a critical section.
+ If THREADED && THREAD_RWLOCK the caller has a read lock,
+ and this function might upgrade it to a write lock.
+ If WALL, act as if TZ is unset; although always false in this file,
+ a wrapper .c file's obsolete and ineffective tzsetwall function can use it.
+ If tz_change_interval is positive the time is NOW; otherwise ignore NOW. */
static void
-tzset_unlocked_name(char const *name)
-{
-#endif
- struct state *sp = lclptr;
- int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
- if (lcl < 0
- ? lcl_is_set < 0
- : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
-#ifdef DETECT_TZ_CHANGES
- if (tzdata_is_fresh())
-#endif /* DETECT_TZ_CHANGES */
- return;
-# ifdef ALL_STATE
+tzset_unlocked(bool threaded, bool wall, monotime_t now)
+{
+ char const *name;
+ struct state *sp;
+ char tzloadflags;
+ size_t namelen;
+ bool writing = false;
+
+ for (;;) {
+ name = wall ? NULL : getenv("TZ");
+ sp = lclptr;
+ tzloadflags = TZLOAD_FROMENV | TZLOAD_TZSTRING;
+ namelen = sizeof lcl_TZname + 1; /* placeholder for no name */
+
+ if (name) {
+ namelen = strnlen(name, sizeof lcl_TZname);
+
+ /* Abbreviate a string like "/usr/share/zoneinfo/America/Los_Angeles"
+ to its shorter equivalent "America/Los_Angeles". */
+ if (!SUPPRESS_TZDIR && tzdirslashlen < namelen
+ && memcmp(name, tzdirslash, tzdirslashlen) == 0) {
+ char const *p = name + tzdirslashlen;
+ while (*p == '/')
+ p++;
+ if (*p && *p != ':') {
+ name = p;
+ namelen = strnlen(name, sizeof lcl_TZname);
+ tzloadflags |= TZLOAD_TZDIR_SUB;
+ }
+ }
+ }
+
+ if ((tz_change_interval <= 0 ? tz_change_interval < 0 : fresh_tzdata(now))
+ && (name
+ ? 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0
+ : lcl_is_set < 0))
+ return;
+
+ if (!THREAD_RWLOCK || writing)
+ break;
+ if (rd2wrlock(threaded) != 0)
+ return;
+ writing = true;
+ }
+
+# if ALL_STATE
if (! sp)
lclptr = sp = malloc(sizeof *lclptr);
# endif
if (sp) {
- int err = zoneinit(sp, name, TZLOAD_FROMENV | TZLOAD_TZSTRING);
+ int err = zoneinit(sp, name, tzloadflags);
if (err != 0) {
zoneinit(sp, "", 0);
/* Abbreviate with "-00" if there was an error.
@@ -1658,23 +1936,47 @@ tzset_unlocked_name(char const *name)
if (name || err != ENOENT)
strcpy(sp->chars, UNSPEC);
}
- if (0 < lcl)
- strcpy(lcl_TZname, name);
+ if (namelen < sizeof lcl_TZname) {
+ char *cp = lcl_TZname;
+ cp = mempcpy(cp, name, namelen);
+ *cp = '\0';
+ }
}
settzname();
- lcl_is_set = lcl;
+ lcl_is_set = (sizeof lcl_TZname > namelen) - (sizeof lcl_TZname < namelen);
}
#endif
+#if !defined TM_GMTOFF || !USE_TIMEX_T
+
+/* If tz_change_interval is positive,
+ return the current time as a monotonically nondecreasing value.
+ Otherwise the return value does not matter. */
+static monotime_t
+get_monotonic_time(void)
+{
+ struct timespec now;
+ now.tv_sec = 0;
+ if (0 < tz_change_interval)
+ clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
+ return now.tv_sec;
+}
+#endif
+
#if !USE_TIMEX_T
+
void
tzset(void)
{
- if (lock() != 0)
+ monotime_t now = get_monotonic_time();
+ int err = lock();
+ if (0 < err) {
+ errno = err;
return;
- tzset_unlocked();
- unlock();
+ }
+ tzset_unlocked(!err, false, now);
+ unlock(!err);
}
#endif
@@ -1682,34 +1984,35 @@ tzset(void)
void
freebsd13_tzsetwall(void)
{
- if (lock() != 0)
+ monotime_t now = get_monotonic_time();
+ int err = lock();
+ if (0 < err) {
+ errno = err;
return;
- tzset_unlocked_name(NULL);
- unlock();
+ }
+ tzset_unlocked(!err, true, now);
+ unlock(!err);
}
__sym_compat(tzsetwall, freebsd13_tzsetwall, FBSD_1.0);
__warn_references(tzsetwall,
"warning: tzsetwall() is deprecated, use tzset() instead.");
#endif /* __FreeBSD__ */
static void
-gmtcheck(void)
+gmtcheck1(void)
{
- static bool gmt_is_set;
- if (lock() != 0)
- return;
- if (! gmt_is_set) {
-#ifdef ALL_STATE
- gmtptr = malloc(sizeof *gmtptr);
+#if ALL_STATE
+ gmtptr = malloc(sizeof *gmtptr);
#endif
- if (gmtptr)
- gmtload(gmtptr);
- gmt_is_set = true;
- }
- unlock();
+ if (gmtptr)
+ gmtload(gmtptr);
+}
+
+static void
+gmtcheck(void)
+{
+ static once_t gmt_once = ONCE_INIT;
+ once(&gmt_once, gmtcheck1);
}
-#ifdef __FreeBSD__
-#define gmtcheck() _once(&gmt_once, gmtcheck)
-#endif
#if NETBSD_INSPIRED && !USE_TIMEX_T
@@ -1729,10 +2032,25 @@ tzalloc(char const *name)
return sp;
}
+#ifndef FREE_PRESERVES_ERRNO
+# if ((defined _POSIX_VERSION && 202405 <= _POSIX_VERSION) \
+ || (defined __GLIBC__ && 2 < __GLIBC__ + (33 <= __GLIBC_MINOR__)) \
+ || defined __OpenBSD__ || defined __sun)
+# define FREE_PRESERVES_ERRNO 1
+# else
+# define FREE_PRESERVES_ERRNO 0
+# endif
+#endif
+
void
tzfree(timezone_t sp)
{
+ int err;
+ if (!FREE_PRESERVES_ERRNO)
+ err = errno;
free(sp);
+ if (!FREE_PRESERVES_ERRNO)
+ errno = err;
}
/*
@@ -1844,7 +2162,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
** To get (wrong) behavior that's compatible with System V Release 2.0
** you'd replace the statement below with
** t += ttisp->tt_utoff;
- ** timesub(&t, 0L, sp, tmp);
+ ** timesub(&t, 0, sp, tmp);
*/
result = timesub(&t, ttisp->tt_utoff, sp, tmp);
if (result) {
@@ -1861,6 +2179,36 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
#if !USE_TIMEX_T
+/* Return TMP, or a thread-specific struct tm * selected by WHICH. */
+static struct tm *
+tm_multi(struct tm *tmp, ATTRIBUTE_MAYBE_UNUSED enum tm_multi which)
+{
+# if THREAD_SAFE && THREAD_TM_MULTI
+ /* It is OK to check is_threaded() separately here; even if it
+ returns a different value in other places in the caller,
+ this function's behavior is still valid. */
+ if (is_threaded()) {
+ /* Try to get a thread-specific struct tm *.
+ Fall back on TMP if this fails. */
+ static pthread_once_t tm_multi_once = PTHREAD_ONCE_INIT;
+ pthread_once(&tm_multi_once, tm_multi_key_init);
+ if (!tm_multi_key_err) {
+ struct tm *p = pthread_getspecific(tm_multi_key);
+ if (!p) {
+ p = malloc(N_TM_MULTI * sizeof *p);
+ if (p && pthread_setspecific(tm_multi_key, p) != 0) {
+ free(p);
+ p = NULL;
+ }
+ }
+ if (p)
+ return &p[which];
+ }
+ }
+# endif
+ return tmp;
+}
+
# if NETBSD_INSPIRED
struct tm *
localtime_rz(struct state *restrict sp, time_t const *restrict timep,
@@ -1873,54 +2221,26 @@ localtime_rz(struct state *restrict sp, time_t const *restrict timep,
static struct tm *
localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
{
+ monotime_t now = get_monotonic_time();
int err = lock();
- if (err) {
+ if (0 < err) {
errno = err;
return NULL;
}
-#ifndef DETECT_TZ_CHANGES
- if (setname || !lcl_is_set)
-#endif /* DETECT_TZ_CHANGES */
- tzset_unlocked();
+ if (0 <= tz_change_interval || setname || !lcl_is_set)
+ tzset_unlocked(!err, false, now);
tmp = localsub(lclptr, timep, setname, tmp);
- unlock();
+ unlock(!err);
return tmp;
}
-#ifdef __FreeBSD__
-static void
-localtime_key_init(void)
-{
- localtime_key_error = pthread_key_create(&localtime_key, free);
-}
-#endif /* __FreeBSD__ */
struct tm *
localtime(const time_t *timep)
{
# if !SUPPORT_C89
static struct tm tm;
# endif
-#ifdef __FreeBSD__
- struct tm *p_tm = &tm;
-
- if (__isthreaded != 0) {
- pthread_once(&localtime_once, localtime_key_init);
- if (localtime_key_error != 0) {
- errno = localtime_key_error;
- return (NULL);
- }
- if ((p_tm = pthread_getspecific(localtime_key)) == NULL) {
- if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
- return (NULL);
- }
- if (pthread_setspecific(localtime_key, p_tm) != 0) {
- free(p_tm);
- return (NULL);
- }
- }
- }
-#endif /* __FreeBSD__ */
- return localtime_tzset(timep, p_tm, true);
+ return localtime_tzset(timep, tm_multi(&tm, LOCALTIME_TM_MULTI), true);
}
struct tm *
@@ -1966,40 +2286,13 @@ gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
return gmtsub(gmtptr, timep, 0, tmp);
}
-#ifdef __FreeBSD__
-static void
-gmtime_key_init(void)
-{
- gmtime_key_error = pthread_key_create(&gmtime_key, free);
-}
-#endif /* __FreeBSD__ */
struct tm *
gmtime(const time_t *timep)
{
# if !SUPPORT_C89
static struct tm tm;
# endif
-#ifdef __FreeBSD__
- struct tm *p_tm = &tm;
-
- if (__isthreaded != 0) {
- pthread_once(&gmtime_once, gmtime_key_init);
- if (gmtime_key_error != 0) {
- errno = gmtime_key_error;
- return (NULL);
- }
- if ((p_tm = pthread_getspecific(gmtime_key)) == NULL) {
- if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
- return (NULL);
- }
- if (pthread_setspecific(gmtime_key, p_tm) != 0) {
- free(p_tm);
- return (NULL);
- }
- }
- }
-#endif /* __FreeBSD__ */
- return gmtime_r(timep, p_tm);
+ return gmtime_r(timep, tm_multi(&tm, GMTIME_TM_MULTI));
}
# if STD_INSPIRED
@@ -2014,40 +2307,13 @@ offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp)
return gmtsub(gmtptr, timep, offset, tmp);
}
-#ifdef __FreeBSD__
-static void
-offtime_key_init(void)
-{
- offtime_key_error = pthread_key_create(&offtime_key, free);
-}
-#endif /* __FreeBSD__ */
struct tm *
offtime(time_t const *timep, long offset)
{
# if !SUPPORT_C89
static struct tm tm;
# endif
-#ifdef __FreeBSD__
- 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);
- }
- }
- }
-#endif
- return offtime_r(timep, offset, p_tm);
+ return offtime_r(timep, offset, tm_multi(&tm, OFFTIME_TM_MULTI));
}
# endif
@@ -2076,10 +2342,9 @@ static struct tm *
timesub(const time_t *timep, int_fast32_t offset,
const struct state *sp, struct tm *tmp)
{
- register const struct lsinfo * lp;
register time_t tdays;
register const int * ip;
- register int_fast32_t corr;
+ int_fast32_2s corr;
register int i;
int_fast32_t idays, rem, dayoff, dayrem;
time_t y;
@@ -2090,13 +2355,13 @@ timesub(const time_t *timep, int_fast32_t offset,
time_t secs_since_posleap = SECSPERMIN;
corr = 0;
- i = (sp == NULL) ? 0 : sp->leapcnt;
+ i = sp ? leapcount(sp) : 0;
while (--i >= 0) {
- lp = &sp->lsis[i];
- if (*timep >= lp->ls_trans) {
- corr = lp->ls_corr;
- if ((i == 0 ? 0 : lp[-1].ls_corr) < corr)
- secs_since_posleap = *timep - lp->ls_trans;
+ struct lsinfo ls = lsinfo(sp, i);
+ if (ls.ls_trans <= *timep) {
+ corr = ls.ls_corr;
+ if ((i == 0 ? 0 : lsinfo(sp, i - 1).ls_corr) < corr)
+ secs_since_posleap = *timep - ls.ls_trans;
break;
}
}
@@ -2226,6 +2491,19 @@ increment_overflow(int *ip, int j)
}
static bool
+increment_overflow_64(int *ip, int_fast64_t j)
+{
+#ifdef ckd_add
+ return ckd_add(ip, *ip, j);
+#else
+ if (j < 0 ? *ip < INT_MIN - j : INT_MAX - j < *ip)
+ return true;
+ *ip += j;
+ return false;
+#endif
+}
+
+static bool
increment_overflow_time_iinntt(time_t *tp, iinntt j)
{
#ifdef ckd_add
@@ -2241,7 +2519,22 @@ increment_overflow_time_iinntt(time_t *tp, iinntt j)
}
static bool
-increment_overflow_time(time_t *tp, int_fast32_t j)
+increment_overflow_time_64(time_t *tp, int_fast64_t j)
+{
+#ifdef ckd_add
+ return ckd_add(tp, *tp, j);
+#else
+ if (j < 0
+ ? (TYPE_SIGNED(time_t) ? *tp < TIME_T_MIN - j : *tp <= -1 - j)
+ : TIME_T_MAX - j < *tp)
+ return true;
+ *tp += j;
+ return false;
+#endif
+}
+
+static bool
+increment_overflow_time(time_t *tp, int_fast32_2s j)
{
#ifdef ckd_add
return ckd_add(tp, *tp, j);
@@ -2260,6 +2553,15 @@ increment_overflow_time(time_t *tp, int_fast32_t j)
#endif
}
+/* Return A - B, where both are in the range -2**31 + 1 .. 2**31 - 1.
+ The result cannot overflow. */
+static int_fast64_t
+utoff_diff (int_fast32_t a, int_fast32_t b)
+{
+ int_fast64_t aa = a;
+ return aa - b;
+}
+
static int
tmcomp(register const struct tm *const atmp,
register const struct tm *const btmp)
@@ -2295,8 +2597,8 @@ mktmcpy(struct tm *dest, struct tm const *src)
static time_t
time2sub(struct tm *const tmp,
- struct tm *(*funcp)(struct state const *, time_t const *,
- int_fast32_t, struct tm *),
+ struct tm *funcp(struct state const *, time_t const *,
+ int_fast32_t, struct tm *),
struct state const *sp,
const int_fast32_t offset,
bool *okayp,
@@ -2456,8 +2758,18 @@ time2sub(struct tm *const tmp,
It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
since the guess gets checked. */
time_t altt = t;
- int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
- if (!increment_overflow_time(&altt, diff)) {
+ int_fast64_t offdiff;
+ bool v;
+# ifdef ckd_sub
+ v = ckd_sub(&offdiff, mytm.TM_GMTOFF, yourtm.TM_GMTOFF);
+# else
+ /* A ckd_sub approximation that is good enough here. */
+ v = !(-TWO_31_MINUS_1 <= yourtm.TM_GMTOFF
+ && yourtm.TM_GMTOFF <= TWO_31_MINUS_1);
+ if (!v)
+ offdiff = utoff_diff(mytm.TM_GMTOFF, yourtm.TM_GMTOFF);
+# endif
+ if (!v && !increment_overflow_time_64(&altt, offdiff)) {
struct tm alttm;
if (funcp(sp, &altt, offset, &alttm)
&& alttm.tm_isdst == mytm.tm_isdst
@@ -2487,8 +2799,12 @@ time2sub(struct tm *const tmp,
continue;
if (ttunspecified(sp, j))
continue;
- newt = (t + sp->ttis[j].tt_utoff
- - sp->ttis[i].tt_utoff);
+ newt = t;
+ if (increment_overflow_time_64
+ (&newt,
+ utoff_diff(sp->ttis[j].tt_utoff,
+ sp->ttis[i].tt_utoff)))
+ continue;
if (! funcp(sp, &newt, offset, &mytm))
continue;
if (tmcomp(&mytm, &yourtm) != 0)
@@ -2514,8 +2830,8 @@ label:
static time_t
time2(struct tm * const tmp,
- struct tm *(*funcp)(struct state const *, time_t const *,
- int_fast32_t, struct tm *),
+ struct tm *funcp(struct state const *, time_t const *,
+ int_fast32_t, struct tm *),
struct state const *sp,
const int_fast32_t offset,
bool *okayp)
@@ -2533,8 +2849,8 @@ time2(struct tm * const tmp,
static time_t
time1(struct tm *const tmp,
- struct tm *(*funcp)(struct state const *, time_t const *,
- int_fast32_t, struct tm *),
+ struct tm *funcp(struct state const *, time_t const *,
+ int_fast32_t, struct tm *),
struct state const *sp,
const int_fast32_t offset)
{
@@ -2587,17 +2903,20 @@ time1(struct tm *const tmp,
continue;
for (otherind = 0; otherind < nseen; ++otherind) {
otheri = types[otherind];
- if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
- continue;
- tmp->tm_sec += (sp->ttis[otheri].tt_utoff
- - sp->ttis[samei].tt_utoff);
- tmp->tm_isdst = !tmp->tm_isdst;
- t = time2(tmp, funcp, sp, offset, &okay);
- if (okay)
- return t;
- tmp->tm_sec -= (sp->ttis[otheri].tt_utoff
- - sp->ttis[samei].tt_utoff);
- tmp->tm_isdst = !tmp->tm_isdst;
+ if (sp->ttis[otheri].tt_isdst != tmp->tm_isdst) {
+ int sec = tmp->tm_sec;
+ if (!increment_overflow_64
+ (&tmp->tm_sec,
+ utoff_diff(sp->ttis[otheri].tt_utoff,
+ sp->ttis[samei].tt_utoff))) {
+ tmp->tm_isdst = !tmp->tm_isdst;
+ t = time2(tmp, funcp, sp, offset, &okay);
+ if (okay)
+ return t;
+ tmp->tm_isdst = !tmp->tm_isdst;
+ }
+ tmp->tm_sec = sec;
+ }
}
}
return WRONG;
@@ -2622,15 +2941,16 @@ static
time_t
mktime(struct tm *tmp)
{
+ monotime_t now = get_monotonic_time();
time_t t;
int err = lock();
- if (err) {
+ if (0 < err) {
errno = err;
return -1;
}
- tzset_unlocked();
+ tzset_unlocked(!err, false, now);
t = mktime_tzname(lclptr, tmp, true);
- unlock();
+ unlock(!err);
return t;
}
@@ -2692,17 +3012,16 @@ timegm(struct tm *tmp)
}
#endif
-static int_fast32_t
+static int_fast32_2s
leapcorr(struct state const *sp, time_t t)
{
- register struct lsinfo const * lp;
register int i;
- i = sp->leapcnt;
+ i = leapcount(sp);
while (--i >= 0) {
- lp = &sp->lsis[i];
- if (t >= lp->ls_trans)
- return lp->ls_corr;
+ struct lsinfo ls = lsinfo(sp, i);
+ if (ls.ls_trans <= t)
+ return ls.ls_corr;
}
return 0;
}
@@ -2714,6 +3033,21 @@ leapcorr(struct state const *sp, time_t t)
#if !USE_TIMEX_T
# if STD_INSPIRED
+static bool
+decrement_overflow_time(time_t *tp, int_fast32_2s j)
+{
+#ifdef ckd_sub
+ return ckd_sub(tp, *tp, j);
+#else
+ if (! (j < 0
+ ? *tp <= TIME_T_MAX + j
+ : (TYPE_SIGNED(time_t) ? TIME_T_MIN + j <= *tp : j <= *tp)))
+ return true;
+ *tp -= j;
+ return false;
+#endif
+}
+
/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
NETBSD_INSPIRED is defined, and are private otherwise. */
# if NETBSD_INSPIRED
@@ -2733,71 +3067,72 @@ leapcorr(struct state const *sp, time_t t)
NETBSD_INSPIRED_EXTERN time_t
time2posix_z(struct state *sp, time_t t)
{
- return t - leapcorr(sp, t);
+ if (decrement_overflow_time(&t, leapcorr(sp, t))) {
+ /* Overflow near maximum time_t value with negative correction.
+ This can happen with unrealistic-but-valid TZif files. */
+ errno = EOVERFLOW;
+ return -1;
+ }
+ return t;
}
time_t
time2posix(time_t t)
{
+ monotime_t now = get_monotonic_time();
int err = lock();
- if (err) {
+ if (0 < err) {
errno = err;
return -1;
}
-#ifndef DETECT_TZ_CHANGES
- if (!lcl_is_set)
-#endif /* DETECT_TZ_CHANGES */
- tzset_unlocked();
+ if (0 <= tz_change_interval || !lcl_is_set)
+ tzset_unlocked(!err, false, now);
if (lclptr)
t = time2posix_z(lclptr, t);
- unlock();
+ unlock(!err);
return t;
}
NETBSD_INSPIRED_EXTERN time_t
posix2time_z(struct state *sp, time_t t)
{
- time_t x;
- time_t y;
- /*
- ** For a positive leap second hit, the result
- ** is not unique. For a negative leap second
- ** hit, the corresponding time doesn't exist,
- ** so we return an adjacent second.
- */
- x = t + leapcorr(sp, t);
- y = x - leapcorr(sp, x);
- if (y < t) {
- do {
- x++;
- y = x - leapcorr(sp, x);
- } while (y < t);
- x -= y != t;
- } else if (y > t) {
- do {
- --x;
- y = x - leapcorr(sp, x);
- } while (y > t);
- x += y != t;
- }
- return x;
+ int i;
+ for (i = leapcount(sp); 0 <= --i; ) {
+ struct lsinfo ls = lsinfo(sp, i);
+ time_t t_corr = t;
+
+ if (increment_overflow_time(&t_corr, ls.ls_corr)) {
+ if (0 <= ls.ls_corr) {
+ /* Overflow near maximum time_t value with positive correction.
+ This can happen with ordinary TZif files with leap seconds. */
+ errno = EOVERFLOW;
+ return -1;
+ } else {
+ /* A negative correction overflowed, so keep going.
+ This can happen with unrealistic-but-valid TZif files. */
+ }
+ } else if (ls.ls_trans <= t_corr)
+ return (t_corr
+ - (ls.ls_trans == t_corr
+ && (i == 0 ? 0 : lsinfo(sp, i - 1).ls_corr) < ls.ls_corr));
+ }
+ return t;
}
time_t
posix2time(time_t t)
{
+ monotime_t now = get_monotonic_time();
int err = lock();
- if (err) {
+ if (0 < err) {
errno = err;
return -1;
}
-#ifndef DETECT_TZ_CHANGES
- if (!lcl_is_set)
-#endif /* DETECT_TZ_CHANGES */
- tzset_unlocked();
+ if (0 <= tz_change_interval || !lcl_is_set)
+ tzset_unlocked(!err, false, now);
if (lclptr)
t = posix2time_z(lclptr, t);
- unlock();
+ unlock(!err);
return t;
}
@@ -2823,7 +3158,7 @@ posix2time(time_t t)
time_t
time(time_t *p)
{
- time_t r = sys_time(0);
+ time_t r = sys_time(NULL);
if (r != (time_t) -1) {
iinntt offset = EPOCH_LOCAL ? timezone : 0;
if (offset < IINNTT_MIN + EPOCH_OFFSET
diff --git a/contrib/tzcode/newctime.3 b/contrib/tzcode/newctime.3
index 9d09e5a55bd9..a8779e6a7c25 100644
--- a/contrib/tzcode/newctime.3
+++ b/contrib/tzcode/newctime.3
@@ -181,7 +181,7 @@ instead.
.PP
The
.B ctime
-function is equivalent to calliing
+function is equivalent to calling
.B localtime
and then calling
.B asctime
@@ -246,17 +246,17 @@ includes the following fields:
.PP
.nf
.ta 2n +\w'long tm_gmtoff;nn'u
- int tm_sec; /\(** seconds (0\*(en60) \(**/
- int tm_min; /\(** minutes (0\*(en59) \(**/
- int tm_hour; /\(** hours (0\*(en23) \(**/
- int tm_mday; /\(** day of month (1\*(en31) \(**/
- int tm_mon; /\(** month of year (0\*(en11) \(**/
- int tm_year; /\(** year \- 1900 \(**/
- int tm_wday; /\(** day of week (Sunday = 0) \(**/
- int tm_yday; /\(** day of year (0\*(en365) \(**/
- int tm_isdst; /\(** is daylight saving time in effect? \(**/
- char \(**tm_zone; /\(** time zone abbreviation (optional) \(**/
- long tm_gmtoff; /\(** offset from UT in seconds (optional) \(**/
+ int tm_sec; /* seconds (0\*(en60) */
+ int tm_min; /* minutes (0\*(en59) */
+ int tm_hour; /* hours (0\*(en23) */
+ int tm_mday; /* day of month (1\*(en31) */
+ int tm_mon; /* month of year (0\*(en11) */
+ int tm_year; /* year \- 1900 */
+ int tm_wday; /* day of week (Sunday = 0) */
+ int tm_yday; /* day of year (0\*(en365) */
+ int tm_isdst; /* is daylight saving time in effect? */
+ char *tm_zone; /* time zone abbreviation (optional) */
+ long tm_gmtoff; /* offset from UT in seconds (optional) */
.fi
.RE
.PP
@@ -311,13 +311,11 @@ and
functions might (or might not) also behave this way.
This is for compatibility with older platforms, as required by POSIX.
.SH FILES
-.ta \w'/usr/share/zoneinfo/posixrules\0\0'u
+.ta \w'/usr/share/zoneinfo/GMT\0\0'u
/etc/localtime local timezone file
.br
/usr/share/zoneinfo timezone directory
.br
-/usr/share/zoneinfo/posixrules default DST rules (obsolete)
-.br
/usr/share/zoneinfo/GMT for UTC leap seconds
.PP
If /usr/share/zoneinfo/GMT is absent,
diff --git a/contrib/tzcode/newstrftime.3 b/contrib/tzcode/newstrftime.3
index e9a382240ed2..182f44f738a3 100644
--- a/contrib/tzcode/newstrftime.3
+++ b/contrib/tzcode/newstrftime.3
@@ -74,7 +74,7 @@ string consists of zero or more conversion specifications and
ordinary characters.
All ordinary characters are copied directly into the array.
A conversion specification consists of a percent sign
-.Ql %
+.q %
and one other character.
.PP
No more than
diff --git a/contrib/tzcode/newtzset.3 b/contrib/tzcode/newtzset.3
index db6bfa7fa64c..77e76c9d6974 100644
--- a/contrib/tzcode/newtzset.3
+++ b/contrib/tzcode/newtzset.3
@@ -13,7 +13,7 @@ tzset \- initialize time conversion information
.PP
.B void tzset(void);
.PP
-/\(** Optional and obsolescent: \(**/
+/* Optional and obsolescent: */
.br
.B extern char *tzname[];
.br
@@ -78,7 +78,17 @@ contents are used as a pathname, a pathname beginning with
is used as-is; otherwise
the pathname is relative to a system time conversion information
directory.
-The file must be in the format specified in
+In a privileged program the pathname must be relative.
+Relative pathnames must not contain
+.q "..\&"
+components.
+For the purpose of these checks, a file name beginning with
+.q "/"
+is considered to be relative if it is the
+.B localtime
+file's name, or if it starts with the
+system timezone directory's name followed by one more more slashes.
+The file must be a regular file in the format specified in
.BR tzfile (5).
.PP
When
@@ -267,7 +277,7 @@ is a placeholder.
.TP
.B <\-03>3<\-02>,M3.5.0/\-2,M10.5.0/\-1
stands for time in western Greenland, 3 hours behind UT, where clocks
-follow the EU rules of
+follow the EU rule of
springing forward on March's last Sunday at 01:00 UT (\-02:00 local
time, i.e., 22:00 the previous day) and falling back on October's last
Sunday at 01:00 UT (\-01:00 local time, i.e., 23:00 the previous day).
@@ -280,28 +290,13 @@ If
.I TZ
specifies daylight saving time but does not specify a
.IR rule ,
-and the optional
-.BR tzfile (5)-format
-file
-.B posixrules
-is present in the system time conversion information directory, the
-rules in
-.B posixrules
-are used, with the
-.B posixrules
-standard and daylight saving time offsets from UT
-replaced by those specified by the
-.I offset
-values in
-.IR TZ .
-However, the
-.B posixrules
-file is obsolete: if it is present it is only for backward compatibility,
-and it does not work reliably.
+the rule typically defaults to the current US daylight-saving rule,
+although such a default is not guaranteed and
+is incorrect for many locations outside the US.
Therefore, if a
.I TZ
string directly specifies a timezone with daylight saving time,
-it should specify the daylight saving rules explicitly.
+it should specify the daylight saving rule explicitly.
.PP
For compatibility with System V Release 3.1, a semicolon
.RB ( ; )
@@ -369,6 +364,10 @@ If successful, the
function returns a nonnull pointer to the newly allocated object.
Otherwise, it returns a null pointer and sets
.IR errno .
+The
+.B tzfree
+function does not modify
+.IR errno .
.SH ERRORS
.TP
.B EOVERFLOW
@@ -389,13 +388,11 @@ for any of the errors specified for the routines
and
.BR read (2).
.SH FILES
-.ta \w'/usr/share/zoneinfo/posixrules\0\0'u
+.ta \w'/usr/share/zoneinfo/GMT\0\0'u
/etc/localtime local timezone file
.br
/usr/share/zoneinfo timezone directory
.br
-/usr/share/zoneinfo/posixrules default DST rules (obsolete)
-.br
/usr/share/zoneinfo/GMT for UTC leap seconds
.PP
If /usr/share/zoneinfo/GMT is absent,
diff --git a/contrib/tzcode/private.h b/contrib/tzcode/private.h
index e6b206690b73..ee191b4ec33c 100644
--- a/contrib/tzcode/private.h
+++ b/contrib/tzcode/private.h
@@ -82,8 +82,9 @@
# include <stdbool.h>
#endif
-#if __STDC_VERSION__ < 202311
-# undef static_assert
+/* For pre-C23 compilers, a substitute for static_assert.
+ Some of these compilers may warn if it is used outside the top level. */
+#if __STDC_VERSION__ < 202311 && !defined static_assert
# define static_assert(cond) extern int static_assert_check[(cond) ? 1 : -1]
#endif
@@ -98,7 +99,9 @@
#endif
/* This string was in the Factory zone through version 2016f. */
-#define GRANDPARENTED "Local time zone must be set--use tzsetup"
+#ifndef GRANDPARENTED
+# define GRANDPARENTED "Local time zone must be set--see zic manual page"
+#endif
/*
** Defaults for preprocessor symbols.
@@ -118,6 +121,14 @@
# define HAVE__GENERIC (201112 <= __STDC_VERSION__)
#endif
+#ifndef HAVE_GETEUID
+# define HAVE_GETEUID 1
+#endif
+
+#ifndef HAVE_GETRESUID
+# define HAVE_GETRESUID 1
+#endif
+
#if !defined HAVE_GETTEXT && defined __has_include
# if __has_include(<libintl.h>)
# define HAVE_GETTEXT 1
@@ -182,37 +193,44 @@
# define ctime_r _incompatible_ctime_r
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+#ifndef TZ_RUNTIME_LEAPS
+# define TZ_RUNTIME_LEAPS 1
+#endif
+
/*
** Nested includes
*/
-/* Avoid clashes with NetBSD by renaming NetBSD's declarations.
- If defining the 'timezone' variable, avoid a clash with FreeBSD's
- 'timezone' function by renaming its declaration. */
-#define localtime_rz sys_localtime_rz
-#define mktime_z sys_mktime_z
-#define posix2time_z sys_posix2time_z
-#define time2posix_z sys_time2posix_z
-#if defined USG_COMPAT && USG_COMPAT == 2
+#include <stddef.h>
+
+/* If defining the 'timezone' variable a la POSIX, avoid clashing with the old
+ 'timezone' function of FreeBSD <= 14, by renaming the latter's declaration.
+ This hack can be removed after 2028-11-30, FreeBSD 14's expected EOL. */
+#if (defined __FreeBSD__ && __FreeBSD__ < 15 && defined __BSD_VISIBLE \
+ && defined USG_COMPAT && USG_COMPAT == 2)
# define timezone sys_timezone
+# define timezone_defined
#endif
-#define timezone_t sys_timezone_t
-#define tzalloc sys_tzalloc
-#define tzfree sys_tzfree
+
#include <time.h>
-#undef localtime_rz
-#undef mktime_z
-#undef posix2time_z
-#undef time2posix_z
-#if defined USG_COMPAT && USG_COMPAT == 2
+
+#ifdef timezone_defined
# undef timezone
+# undef timezone_defined
#endif
-#undef timezone_t
-#undef tzalloc
-#undef tzfree
-#include <stddef.h>
#include <string.h>
+#if defined HAVE_STRNLEN && !HAVE_STRNLEN
+static size_t
+strnlen (char const *s, size_t maxlen)
+{
+ size_t i;
+ for (i = 0; i < maxlen && s[i]; i++)
+ continue;
+ return i;
+}
+#endif
+
#if !PORT_TO_C89
# include <inttypes.h>
#endif
@@ -234,6 +252,9 @@
#ifndef ENOMEM
# define ENOMEM EINVAL
#endif
+#ifndef ENOTCAPABLE
+# define ENOTCAPABLE EINVAL
+#endif
#ifndef ENOTSUP
# define ENOTSUP EINVAL
#endif
@@ -246,7 +267,12 @@
#endif /* HAVE_GETTEXT */
#if HAVE_UNISTD_H
-# include <unistd.h> /* for R_OK, and other POSIX goodness */
+# include <unistd.h>
+#else
+/* Assume getopt.o or equivalent is linked via Makefile configuration. */
+int getopt(int, char *const[], char const *);
+extern char *optarg;
+extern int optind;
#endif /* HAVE_UNISTD_H */
/* SUPPORT_POSIX2008 means the tzcode library should support
@@ -274,6 +300,16 @@
# endif
#endif
+#ifndef HAVE_ISSETUGID
+# if (defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
+ || (defined __linux__ && !defined __GLIBC__) /* Android, musl, etc. */ \
+ || (defined __APPLE__ && defined __MACH__) || defined __sun)
+# define HAVE_ISSETUGID 1
+# else
+# define HAVE_ISSETUGID 0
+# endif
+#endif
+
#ifndef HAVE_SNPRINTF
# define HAVE_SNPRINTF (!PORT_TO_C89 || 199901 <= __STDC_VERSION__)
#endif
@@ -310,10 +346,6 @@
# endif
#endif
-#ifndef R_OK
-# define R_OK 4
-#endif /* !defined R_OK */
-
#if PORT_TO_C89
/*
@@ -322,150 +354,144 @@
** 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
-# define HAVE_STDINT_H 1 /* C23 __has_include implies C99 stdint.h. */
-#endif
-#ifndef HAVE_STDINT_H
-# define HAVE_STDINT_H \
- (199901 <= __STDC_VERSION__ \
- || 2 < __GLIBC__ + (1 <= __GLIBC_MINOR__) \
- || __CYGWIN__ || INTMAX_MAX)
-#endif /* !defined HAVE_STDINT_H */
-
-#if HAVE_STDINT_H
-# include <stdint.h>
-#endif /* !HAVE_STDINT_H */
-
-#ifndef HAVE_INTTYPES_H
-# define HAVE_INTTYPES_H HAVE_STDINT_H
-#endif
-#if HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-
-/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
-#if defined __LONG_LONG_MAX__ && !defined __STRICT_ANSI__
-# ifndef LLONG_MAX
-# define LLONG_MAX __LONG_LONG_MAX__
+# if !defined HAVE_STDINT_H && defined __has_include
+# define HAVE_STDINT_H 1 /* C23 __has_include implies C99 stdint.h. */
# endif
-# ifndef LLONG_MIN
-# define LLONG_MIN (-1 - LLONG_MAX)
+# ifndef HAVE_STDINT_H
+# define HAVE_STDINT_H \
+ (199901 <= __STDC_VERSION__ \
+ || 2 < __GLIBC__ + (1 <= __GLIBC_MINOR__) \
+ || __CYGWIN__ || INTMAX_MAX)
+# endif /* !defined HAVE_STDINT_H */
+
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif /* !HAVE_STDINT_H */
+
+# ifndef HAVE_INTTYPES_H
+# define HAVE_INTTYPES_H HAVE_STDINT_H
# endif
-# ifndef ULLONG_MAX
-# define ULLONG_MAX (LLONG_MAX * 2ull + 1)
+# if HAVE_INTTYPES_H
+# include <inttypes.h>
+# endif
+
+/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
+# if defined __LONG_LONG_MAX__ && !defined __STRICT_ANSI__
+# ifndef LLONG_MAX
+# define LLONG_MAX __LONG_LONG_MAX__
+# endif
+# ifndef LLONG_MIN
+# define LLONG_MIN (-1 - LLONG_MAX)
+# endif
+# ifndef ULLONG_MAX
+# define ULLONG_MAX (LLONG_MAX * 2ull + 1)
+# endif
# endif
-#endif
-#ifndef INT_FAST64_MAX
-# if 1 <= LONG_MAX >> 31 >> 31
+# ifndef INT_FAST64_MAX
+# if 1 <= LONG_MAX >> 31 >> 31
typedef long int_fast64_t;
-# define INT_FAST64_MIN LONG_MIN
-# define INT_FAST64_MAX LONG_MAX
-# else
+# define INT_FAST64_MIN LONG_MIN
+# define INT_FAST64_MAX LONG_MAX
+# else
/* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */
typedef long long int_fast64_t;
-# define INT_FAST64_MIN LLONG_MIN
-# define INT_FAST64_MAX LLONG_MAX
+# define INT_FAST64_MIN LLONG_MIN
+# define INT_FAST64_MAX LLONG_MAX
+# endif
# endif
-#endif
-#ifndef PRIdFAST64
-# if INT_FAST64_MAX == LONG_MAX
-# define PRIdFAST64 "ld"
-# else
-# define PRIdFAST64 "lld"
+# ifndef PRIdFAST64
+# if INT_FAST64_MAX == LONG_MAX
+# define PRIdFAST64 "ld"
+# else
+# define PRIdFAST64 "lld"
+# endif
# endif
-#endif
-#ifndef SCNdFAST64
-# define SCNdFAST64 PRIdFAST64
-#endif
+# ifndef SCNdFAST64
+# define SCNdFAST64 PRIdFAST64
+# endif
-#ifndef INT_FAST32_MAX
-# if INT_MAX >> 31 == 0
+# ifndef INT_FAST32_MAX
typedef long int_fast32_t;
# define INT_FAST32_MAX LONG_MAX
# define INT_FAST32_MIN LONG_MIN
-# else
-typedef int int_fast32_t;
-# define INT_FAST32_MAX INT_MAX
-# define INT_FAST32_MIN INT_MIN
# endif
-#endif
-#ifndef INT_LEAST32_MAX
+# ifndef INT_LEAST32_MAX
typedef int_fast32_t int_least32_t;
-#endif
+# endif
-#ifndef INTMAX_MAX
-# ifdef LLONG_MAX
+# ifndef INTMAX_MAX
+# ifdef LLONG_MAX
typedef long long intmax_t;
-# ifndef HAVE_STRTOLL
-# define HAVE_STRTOLL 1
+# ifndef HAVE_STRTOLL
+# define HAVE_STRTOLL 1
+# endif
+# if HAVE_STRTOLL
+# define strtoimax strtoll
+# endif
+# define INTMAX_MAX LLONG_MAX
+# define INTMAX_MIN LLONG_MIN
+# else
+typedef long intmax_t;
+# define INTMAX_MAX LONG_MAX
+# define INTMAX_MIN LONG_MIN
# endif
-# if HAVE_STRTOLL
-# define strtoimax strtoll
+# ifndef strtoimax
+# define strtoimax strtol
# endif
-# define INTMAX_MAX LLONG_MAX
-# define INTMAX_MIN LLONG_MIN
-# else
-typedef long intmax_t;
-# define INTMAX_MAX LONG_MAX
-# define INTMAX_MIN LONG_MIN
-# endif
-# ifndef strtoimax
-# define strtoimax strtol
# endif
-#endif
-#ifndef PRIdMAX
-# if INTMAX_MAX == LLONG_MAX
-# define PRIdMAX "lld"
-# else
-# define PRIdMAX "ld"
+# ifndef PRIdMAX
+# if INTMAX_MAX == LLONG_MAX
+# define PRIdMAX "lld"
+# else
+# define PRIdMAX "ld"
+# endif
# endif
-#endif
-#ifndef PTRDIFF_MAX
-# define PTRDIFF_MAX MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t))
-#endif
+# ifndef PTRDIFF_MAX
+# define PTRDIFF_MAX MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t))
+# endif
-#ifndef UINT_FAST32_MAX
+# ifndef UINT_FAST32_MAX
typedef unsigned long uint_fast32_t;
-#endif
+# endif
-#ifndef UINT_FAST64_MAX
-# if 3 <= ULONG_MAX >> 31 >> 31
+# ifndef UINT_FAST64_MAX
+# if 3 <= ULONG_MAX >> 31 >> 31
typedef unsigned long uint_fast64_t;
-# define UINT_FAST64_MAX ULONG_MAX
-# else
+# define UINT_FAST64_MAX ULONG_MAX
+# else
/* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */
typedef unsigned long long uint_fast64_t;
-# define UINT_FAST64_MAX ULLONG_MAX
+# define UINT_FAST64_MAX ULLONG_MAX
+# endif
# endif
-#endif
-#ifndef UINTMAX_MAX
-# ifdef ULLONG_MAX
+# ifndef UINTMAX_MAX
+# ifdef ULLONG_MAX
typedef unsigned long long uintmax_t;
-# define UINTMAX_MAX ULLONG_MAX
-# else
+# define UINTMAX_MAX ULLONG_MAX
+# else
typedef unsigned long uintmax_t;
-# define UINTMAX_MAX ULONG_MAX
+# define UINTMAX_MAX ULONG_MAX
+# endif
# endif
-#endif
-#ifndef PRIuMAX
-# ifdef ULLONG_MAX
-# define PRIuMAX "llu"
-# else
-# define PRIuMAX "lu"
+# ifndef PRIuMAX
+# ifdef ULLONG_MAX
+# define PRIuMAX "llu"
+# else
+# define PRIuMAX "lu"
+# endif
# endif
-#endif
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
+# ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+# endif
#endif /* PORT_TO_C89 */
@@ -513,6 +539,15 @@ typedef unsigned long uintmax_t;
# define HAVE___HAS_C_ATTRIBUTE false
#endif
+#ifdef __has_attribute
+# if __has_attribute (nonstring)
+# define ATTRIBUTE_NONSTRING __attribute__((__nonstring__))
+# endif
+#endif
+#ifndef ATTRIBUTE_NONSTRING
+# define ATTRIBUTE_NONSTRING
+#endif
+
#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(deprecated)
# define ATTRIBUTE_DEPRECATED [[deprecated]]
@@ -585,11 +620,11 @@ typedef unsigned long uintmax_t;
# define ATTRIBUTE_UNSEQUENCED /* empty */
#endif
-/* GCC attributes that are useful in tzcode.
- __attribute__((const)) is stricter than [[unsequenced]],
- so the latter is an adequate substitute in non-GCC C23 platforms.
- __attribute__((pure)) is stricter than [[reproducible]],
- so the latter is an adequate substitute in non-GCC C23 platforms. */
+/* GNU C attributes that are useful in tzcode.
+ Although neither __attribute__((const)) nor __attribute__((pure)) are
+ stricter than their C23 counterparts [[unsequenced]] and [[reproducible]],
+ the C23 attributes happen to work in each tzcode use of ATTRIBUTE_CONST
+ and ATTRIBUTE_PURE. (This might not work outside of tzcode!) */
#if __GNUC__ < 3
# define ATTRIBUTE_CONST ATTRIBUTE_UNSEQUENCED
# define ATTRIBUTE_FORMAT(spec) /* empty */
@@ -608,6 +643,12 @@ typedef unsigned long uintmax_t;
#else
# define ATTRIBUTE_PURE_114833 /* empty */
#endif
+/* GCC_LINT hack to pacify GCC bug 114833 even though the attribute is
+ not strictly correct, as the function might not return whereas pure
+ functions are supposed to return exactly once. This hack is not
+ known to generate wrong code for tzcode on any platform.
+ Remove this macro and its uses when the bug is fixed in a GCC release. */
+#define ATTRIBUTE_PURE_114833_HACK ATTRIBUTE_PURE_114833
#if (__STDC_VERSION__ < 199901 && !defined restrict \
&& (PORT_TO_C89 || defined _MSC_VER))
@@ -744,10 +785,10 @@ typedef time_tz tz_time_t;
# endif
DEPRECATED_IN_C23 char *asctime(struct tm const *);
DEPRECATED_IN_C23 char *ctime(time_t const *);
-#if SUPPORT_POSIX2008
+# if SUPPORT_POSIX2008
char *asctime_r(struct tm const *restrict, char *restrict);
char *ctime_r(time_t const *, char *);
-#endif
+# endif
ATTRIBUTE_CONST double difftime(time_t, time_t);
size_t strftime(char *restrict, size_t, char const *restrict,
struct tm const *restrict);
@@ -795,6 +836,23 @@ extern char *asctime_r(struct tm const *restrict, char *restrict);
extern char **environ;
#endif
+#ifndef HAVE_MEMPCPY
+# if (defined mempcpy \
+ || defined __FreeBSD__ || defined __NetBSD__ || defined __linux__)
+# define HAVE_MEMPCPY 1
+# else
+# define HAVE_MEMPCPY 0
+# endif
+#endif
+#if !HAVE_MEMPCPY
+static void *
+mempcpy(void *restrict s1, void const *restrict s2, size_t n)
+{
+ char *p = memcpy(s1, s2, n);
+ return p + n;
+}
+#endif
+
#if 2 <= HAVE_TZNAME + (TZ_TIME_T || !HAVE_POSIX_DECLS)
extern char *tzname[];
#endif
@@ -855,26 +913,32 @@ time_t posix2time(time_t);
#endif
/*
-** Define functions that are ABI compatible with NetBSD but have
-** better prototypes. NetBSD 6.1.4 defines a pointer type timezone_t
-** and labors under the misconception that 'const timezone_t' is a
-** pointer to a constant. This use of 'const' is ineffective, so it
-** is not done here. What we call 'struct state' NetBSD calls
+** Define functions that are ABI compatible with NetBSD.
+** What we call 'struct state' NetBSD calls
** 'struct __state', but this is a private name so it doesn't matter.
*/
#if NETBSD_INSPIRED
+# ifdef _NETBSD_SOURCE
+# define state __state
+# else
typedef struct state *timezone_t;
+# endif
struct tm *localtime_rz(timezone_t restrict, time_t const *restrict,
struct tm *restrict);
time_t mktime_z(timezone_t restrict, struct tm *restrict);
timezone_t tzalloc(char const *);
void tzfree(timezone_t);
# if STD_INSPIRED
+# if TZ_RUNTIME_LEAPS
+# define ATTRIBUTE_POSIX2TIME ATTRIBUTE_PURE
+# else
+# define ATTRIBUTE_POSIX2TIME ATTRIBUTE_CONST
+# endif
# if TZ_TIME_T || !defined posix2time_z
-ATTRIBUTE_PURE time_t posix2time_z(timezone_t, time_t);
+ATTRIBUTE_POSIX2TIME time_t posix2time_z(timezone_t, time_t);
# endif
# if TZ_TIME_T || !defined time2posix_z
-ATTRIBUTE_PURE time_t time2posix_z(timezone_t, time_t);
+ATTRIBUTE_POSIX2TIME time_t time2posix_z(timezone_t, time_t);
# endif
# endif
#endif
@@ -885,7 +949,7 @@ ATTRIBUTE_PURE time_t time2posix_z(timezone_t, time_t);
#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)
+#define TWOS_COMPLEMENT(type) (TYPE_SIGNED (type) && (! ~ (type) -1))
/* Minimum and maximum of two values. Use lower case to avoid
naming clashes with standard include files. */
@@ -1008,23 +1072,27 @@ time_t timeoff(struct tm *, long);
*/
#if HAVE_GETTEXT
-#define _(msgid) gettext(msgid)
+# define _(msgid) gettext(msgid)
#else /* !HAVE_GETTEXT */
-#define _(msgid) msgid
+# define _(msgid) (msgid)
#endif /* !HAVE_GETTEXT */
+#define N_(msgid) (msgid)
#if !defined TZ_DOMAIN && defined HAVE_GETTEXT
# define TZ_DOMAIN "tz"
#endif
#if HAVE_INCOMPATIBLE_CTIME_R
-#undef asctime_r
-#undef ctime_r
+# undef asctime_r
+# undef ctime_r
char *asctime_r(struct tm const *restrict, char *restrict);
char *ctime_r(time_t const *, char *);
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
-/* Handy macros that are independent of tzfile implementation. */
+/* Handy constants that are independent of tzfile implementation. */
+
+/* 2**31 - 1 as a signed integer, and usable in #if. */
+#define TWO_31_MINUS_1 2147483647
enum {
SECSPERMIN = 60,
diff --git a/contrib/tzcode/strftime.c b/contrib/tzcode/strftime.c
index 487a5234cbc5..c249010561d1 100644
--- a/contrib/tzcode/strftime.c
+++ b/contrib/tzcode/strftime.c
@@ -49,8 +49,9 @@
and account for the tm_year origin (1900) and time_t origin (1970). */
#define MKTIME_FITS_IN(min, max) \
((min) < 0 \
- && ((min) + 0x7fffffff) / 366 / 24 / 60 / 60 / 2 + 1970 - 1900 < INT_MIN \
- && INT_MAX < ((max) - 0x7fffffff) / 366 / 24 / 60 / 60 / 2 + 1970 - 1900)
+ && (((min) + TWO_31_MINUS_1) / 366 / 24 / 60 / 60 / 2 + 1970 - 1900 \
+ < INT_MIN) \
+ && INT_MAX < ((max) - TWO_31_MINUS_1) / 366 / 24 / 60 / 60 / 2 + 1970 - 1900)
/* MKTIME_MIGHT_OVERFLOW is true if mktime can fail due to time_t overflow
or if it is not known whether mktime can fail,
diff --git a/contrib/tzcode/theory.html b/contrib/tzcode/theory.html
index 352a3d87078f..12f4f7f4b439 100644
--- a/contrib/tzcode/theory.html
+++ b/contrib/tzcode/theory.html
@@ -3,14 +3,16 @@
<head>
<title>Theory and pragmatics of the tz code and data</title>
<meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
<style>
- pre {margin-left: 2em; white-space: pre-wrap;}
+ dd {margin-left: 1.3rem;}
+ pre {margin-left: 1.3rem; overflow: auto;}
+ ul {padding-left: 1.3rem;}
</style>
</head>
<body>
<h1>Theory and pragmatics of the <code><abbr>tz</abbr></code> code and data</h1>
- <h3>Outline</h3>
<nav>
<ul>
<li><a href="#scope">Scope of the <code><abbr>tz</abbr></code>
@@ -89,24 +91,25 @@ The <code><abbr>tz</abbr></code> code is upwards compatible with <a
href="https://en.wikipedia.org/wiki/POSIX">POSIX</a>, an international
standard for <a
href="https://en.wikipedia.org/wiki/Unix">UNIX</a>-like systems.
-As of this writing, the current edition of POSIX is POSIX.1-2024,
-which has been published but not yet in HTML form.
-Unlike its predecessor POSIX.1-2017 (<a
-href="https://pubs.opengroup.org/onlinepubs/9699919799/"> The Open
-Group Base Specifications Issue 7</a>, IEEE Std 1003.1-2017, 2018
-Edition), POSIX.1-2024 requires support for the
+As of this writing, the current edition of POSIX is
+<a href="https://pubs.opengroup.org/onlinepubs/9799919799/">POSIX.1-2024</a>
+(The Open Group Base Specifications Issue 8, IEEE Std 1003.1-2024).
+Unlike its predecessors
+<a href="https://archive.org/details/POSIX.1-1988">POSIX.1-1988</a> through
+<a href="https://pubs.opengroup.org/onlinepubs/9699919799/">POSIX.1-2017</a>,
+POSIX.1-2024 requires support for the
<code><abbr>tz</abbr></code> database, which has a
model for describing civil time that is more complex than the
-standard and daylight saving times required by POSIX.1-2017.
+standard and daylight saving times required by earlier POSIX editions.
A <code><abbr>tz</abbr></code> timezone corresponds to a ruleset that can
have more than two changes per year, these changes need not merely
flip back and forth between two alternatives, and the rules themselves
can change at times.
Whether and when a timezone changes its clock,
-and even the timezone's notional base offset from <abbr>UTC</abbr>,
+and even the timezone’s notional base offset from <abbr>UTC</abbr>,
are variable.
-It does not always make sense to talk about a timezone's
-"base offset", which is not necessarily a single number.
+It does not always make sense to talk about a timezone’s
+“base offset”, which is not necessarily a single number.
</p>
</section>
@@ -118,16 +121,16 @@ Each timezone has a name that uniquely identifies the timezone.
Inexperienced users are not expected to select these names unaided.
Distributors should provide documentation and/or a simple selection
interface that explains each name via a map or via descriptive text like
-"Czech Republic" instead of the timezone name "<code>Europe/Prague</code>".
+“Czech Republic” instead of the timezone name “<code>Europe/Prague</code>”.
If geolocation information is available, a selection interface can
locate the user on a timezone map or prioritize names that are
geographically close. For an example selection interface, see the
<code>tzselect</code> program in the <code><abbr>tz</abbr></code> code.
-Unicode's <a href="https://cldr.unicode.org">Common Locale Data
+Unicode’s <a href="https://cldr.unicode.org">Common Locale Data
Repository (<abbr>CLDR</abbr>)</a>
contains data that may be useful for other selection
interfaces; it maps timezone names like <code>Europe/Prague</code> to
-locale-dependent strings like "Prague", "Praha", "Прага", and "布拉格".
+locale-dependent strings like “Prague”, “Praha”, “Прага”, and “布拉格”.
</p>
<p>
@@ -142,13 +145,13 @@ among the following goals:
civil time.
</li>
<li>
- Indicate to experts where the timezone's clocks typically are.
+ Indicate to experts where the timezone’s clocks typically are.
</li>
<li>
Be robust in the presence of political changes.
For example, names are typically not tied to countries, to avoid
incompatibilities when countries change their name (e.g.,
- Swaziland&rarr;Eswatini) or when locations change countries (e.g., Hong
+ Swaziland→Eswatini) or when locations change countries (e.g., Hong
Kong from UK colony to China).
There is no requirement that every country or national
capital must have a timezone name.
@@ -166,11 +169,11 @@ Names normally have the format
<var>AREA</var><code>/</code><var>LOCATION</var>, where
<var>AREA</var> is a continent or ocean, and
<var>LOCATION</var> is a specific location within the area.
-North and South America share the same area, '<code>America</code>'.
-Typical names are '<code>Africa/Cairo</code>',
-'<code>America/New_York</code>', and '<code>Pacific/Honolulu</code>'.
+North and South America share the same area, <code>America</code>.
+Typical names are <code>Africa/Cairo</code>,
+<code>America/New_York</code>, and <code>Pacific/Honolulu</code>.
Some names are further qualified to help avoid confusion; for example,
-'<code>America/Indiana/Petersburg</code>' distinguishes Petersburg,
+<code>America/Indiana/Petersburg</code> distinguishes Petersburg,
Indiana from other Petersburgs in America.
</p>
@@ -183,25 +186,25 @@ in decreasing order of importance:
<ul>
<li>
Use only valid POSIX file name components (i.e., the parts of
- names other than '<code>/</code>').
- Do not use the file name components '<code>.</code>' and
- '<code>..</code>'.
+ names other than "<code>/</code>").
+ Do not use the file name components "<code>.</code>" and
+ "<code>..</code>".
Within a file name component, use only <a
href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> letters,
- '<code>.</code>', '<code>-</code>' and '<code>_</code>'.
+ "<code>.</code>", "<code>-</code>" and "<code>_</code>".
Do not use digits, as that might create an ambiguity with <a
- href="https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03">POSIX's proleptic
- <code>TZ</code> strings</a>.
+ href="https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap08.html#tag_08_03">POSIX’s
+ proleptic <code>TZ</code> strings</a>.
A file name component must not exceed 14 characters or start with
- '<code>-</code>'.
+ "<code>-</code>".
E.g., prefer <code>America/Noronha</code> to
<code>America/Fernando_de_Noronha</code>.
Exceptions: see the discussion of legacy names below.
</li>
<li>
- A name must not be empty, or contain '<code>//</code>', or
- start or end with '<code>/</code>'.
- Also, a name must not be '<code>Etc/Unknown</code>', as
+ A name must not be empty, or contain "<code>//</code>", or
+ start or end with "<code>/</code>".
+ Also, a name must not be "<code>Etc/Unknown</code>", as
<abbr>CLDR</abbr> uses that string for an unknown or invalid timezone.
</li>
<li>
@@ -213,7 +216,7 @@ in decreasing order of importance:
<li>
If one name <var>A</var> is an initial prefix of another
name <var>AB</var> (ignoring case), then <var>B</var> must not
- start with '<code>/</code>', as a regular file cannot have the
+ start with "<code>/</code>", as a regular file cannot have the
same name as a directory in POSIX.
For example, <code>America/New_York</code> precludes
<code>America/New_York/Bronx</code>.
@@ -280,8 +283,8 @@ in decreasing order of importance:
<code>Atlantic/Canaries</code>.
</li>
<li>
- Omit common suffixes like '<code>_Islands</code>' and
- '<code>_City</code>', unless that would lead to ambiguity.
+ Omit common suffixes like "<code>_Islands</code>" and
+ "<code>_City</code>", unless that would lead to ambiguity.
E.g., prefer <code>America/Cayman</code> to
<code>America/Cayman_Islands</code> and
<code>America/Guatemala</code> to
@@ -292,10 +295,10 @@ in decreasing order of importance:
country of Mexico has several time zones</a>.
</li>
<li>
- Use '<code>_</code>' to represent a space.
+ Use "<code>_</code>" to represent a space.
</li>
<li>
- Omit '<code>.</code>' from abbreviations in names.
+ Omit "<code>.</code>" from abbreviations in names.
E.g., prefer <code>Atlantic/St_Helena</code> to
<code>Atlantic/St._Helena</code>.
</li>
@@ -303,15 +306,15 @@ in decreasing order of importance:
Do not change established names if they only marginally violate
the above guidelines.
For example, do not change the existing name <code>Europe/Rome</code> to
- <code>Europe/Milan</code> merely because Milan's population has grown
- to be somewhat greater than Rome's.
+ <code>Europe/Milan</code> merely because Milan’s population has grown
+ to be somewhat greater than Rome’s.
</li>
<li>
If a name is changed, put its old spelling in the
- '<code>backward</code>' file as a link to the new spelling.
+ "<code>backward</code>" file as a link to the new spelling.
This means old spellings will continue to work.
Ordinarily a name change should occur only in the rare case when
- a location's consensus English-language spelling changes; for example,
+ a location’s consensus English-language spelling changes; for example,
in 2008 <code>Asia/Calcutta</code> was renamed to <code>Asia/Kolkata</code>
due to long-time widespread use of the new city name instead of the old.
</li>
@@ -327,11 +330,11 @@ have included the following:
<ul>
<li>
Older versions of this package used a different naming scheme.
-See the file '<code>backward</code>' for most of these older names
-(e.g., '<code>US/Eastern</code>' instead of '<code>America/New_York</code>').
+See the file "<code>backward</code>" for most of these older names
+(e.g., <code>US/Eastern</code> instead of <code>America/New_York</code>).
The other old-fashioned names still supported are
-'<code>WET</code>', '<code>CET</code>', '<code>MET</code>', and
-'<code>EET</code>' (see the file '<code>europe</code>').
+<code>WET</code>, <code>CET</code>, <code>MET</code>, and
+<code>EET</code> (see the file "<code>europe</code>").
</li>
<li>
@@ -339,13 +342,13 @@ Older versions of this package defined legacy names that are
incompatible with the first guideline of location names, but which are
still supported.
These legacy names are mostly defined in the file
-'<code>etcetera</code>'.
-Also, the file '<code>backward</code>' defines the legacy names
-'<code>Etc/GMT0</code>', '<code>Etc/GMT-0</code>', '<code>Etc/GMT+0</code>',
-'<code>GMT0</code>', '<code>GMT-0</code>' and '<code>GMT+0</code>',
-and the file '<code>northamerica</code>' defines the legacy names
-'<code>EST5EDT</code>', '<code>CST6CDT</code>',
-'<code>MST7MDT</code>', and '<code>PST8PDT</code>'.
+"<code>etcetera</code>".
+Also, the file "<code>backward</code>" defines the legacy names
+<code>Etc/GMT0</code>, <code>Etc/GMT-0</code>, <code>Etc/GMT+0</code>,
+<code>GMT0</code>, <code>GMT-0</code> and <code>GMT+0</code>,
+and the file "<code>northamerica</code>" defines the legacy names
+<code>EST5EDT</code>, <code>CST6CDT</code>,
+<code>MST7MDT</code>, and <code>PST8PDT</code>.
</li>
<li>
@@ -365,11 +368,11 @@ The file <code>zone1970.tab</code> lists geographical locations used
to name timezones.
It is intended to be an exhaustive list of names for geographic
regions as described above; this is a subset of the timezones in the data.
-Although a <code>zone1970.tab</code> location's
+Although a <code>zone1970.tab</code> location’s
<a href="https://en.wikipedia.org/wiki/Longitude">longitude</a>
corresponds to
its <a href="https://en.wikipedia.org/wiki/Local_mean_time">local mean
-time (<abbr>LMT</abbr>)</a> offset with one hour for every 15&deg;
+time (<abbr>LMT</abbr>)</a> offset with one hour for every 15°
east longitude, this relationship is not exact.
The backward-compatibility file <code>zone.tab</code> is similar
but conforms to the older-version guidelines related to <abbr>ISO</abbr> 3166-1;
@@ -395,7 +398,7 @@ on platforms that do not support proleptic <code>TZ</code> strings
like <code>&lt;+08&gt;-8</code>;
no other source file other than <code>backward</code>
contains links to its zones.
-One of <code>etcetera</code>'s names is <code>Etc/UTC</code>,
+One of <code>etcetera</code>’s names is <code>Etc/UTC</code>,
used by functions like <code>gmtime</code> to obtain leap
second information on platforms that support leap seconds.
Another <code>etcetera</code> name, <code>GMT</code>,
@@ -407,7 +410,7 @@ is used by older code releases.
<h2 id="abbreviations">Time zone abbreviations</h2>
<p>
When this package is installed, it generates time zone abbreviations
-like '<code>EST</code>' to be compatible with human tradition and POSIX.
+like <code>EST</code> to be compatible with human tradition and POSIX.
Here are the general guidelines used for choosing time zone abbreviations,
in decreasing order of importance:
</p>
@@ -415,25 +418,24 @@ in decreasing order of importance:
<ul>
<li>
Use three to six characters that are ASCII alphanumerics or
- '<code>+</code>' or '<code>-</code>'.
+ "<code>+</code>" or "<code>-</code>".
Previous editions of this database also used characters like
- space and '<code>?</code>', but these characters have a
+ space and "<code>?</code>", but these characters have a
special meaning to the
<a href="https://en.wikipedia.org/wiki/Unix_shell">UNIX shell</a>
and cause commands like
- '<code><a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set">set</a>
- `<a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/date.html">date</a>`</code>'
+ "<code><a href="https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#set">set</a>
+ `<a href="https://pubs.opengroup.org/onlinepubs/9799919799/utilities/date.html">date</a>`</code>"
to have unexpected effects.
Previous editions of this guideline required upper-case letters, but the
Congressman who introduced
<a href="https://en.wikipedia.org/wiki/Chamorro_Time_Zone">Chamorro
- Standard Time</a> preferred "ChST", so lower-case letters are now
- allowed.
- Also, POSIX from 2001 on relaxed the rule to allow '<code>-</code>',
- '<code>+</code>', and alphanumeric characters from the portable
+ Standard Time</a> preferred “ChST”, so lower-case letters are now allowed.
+ Also, POSIX from 2001 on relaxed the rule to allow "<code>-</code>",
+ "<code>+</code>", and alphanumeric characters from the portable
character set in the current locale.
- In practice ASCII alphanumerics and '<code>+</code>' and
- '<code>-</code>' are safe in all locales.
+ In practice ASCII alphanumerics and "<code>+</code>" and
+ "<code>-</code>" are safe in all locales.
<p>
In other words, in the C locale the POSIX extended regular
@@ -445,10 +447,10 @@ in decreasing order of importance:
</li>
<li>
Use abbreviations that are in common use among English-speakers,
- e.g., 'EST' for Eastern Standard Time in North America.
+ e.g., “EST” for Eastern Standard Time in North America.
We assume that applications translate them to other languages
as part of the normal localization process; for example,
- a French application might translate 'EST' to 'HNE'.
+ a French application might translate “EST” to “HNE”.
<p>
<small>These abbreviations (for standard/daylight/etc. time) are:
@@ -483,7 +485,7 @@ in decreasing order of importance:
NST/NDT/NWT/NPT/NDDT Newfoundland,
NST/NDT/NWT/NPT Nome,
NZMT/NZST New Zealand through 1945,
- NZST/NZDT New Zealand 1946&ndash;present,
+ NZST/NZDT New Zealand 1946–present,
PKT/PKST Pakistan,
PST/PDT/PWT/PPT Pacific,
PST/PDT Philippine,
@@ -500,12 +502,12 @@ in decreasing order of importance:
</li>
<li>
<p>
- For times taken from a city's longitude, use the
+ For times taken from a city’s longitude, use the
traditional <var>x</var>MT notation.
- The only abbreviation like this in current use is '<abbr>GMT</abbr>'.
+ The only abbreviation like this in current use is <abbr>GMT</abbr>.
The others are for timestamps before 1960,
except that Monrovia Mean Time persisted until 1972.
- Typically, numeric abbreviations (e.g., '<code>-</code>004430' for
+ Typically, numeric abbreviations (e.g., <code>-</code>004430 for
MMT) would cause trouble here, as the numeric strings would exceed
the POSIX length limit.
</p>
@@ -546,39 +548,39 @@ in decreasing order of importance:
<small>A few abbreviations also follow the pattern that
<abbr>GMT</abbr>/<abbr>BST</abbr> established for time in the UK.
They are:
- BMT/BST for Bermuda 1890&ndash;1930,
+ BMT/BST for Bermuda 1890–1930,
CMT/BST for Calamarca Mean Time and Bolivian Summer Time
- 1890&ndash;1932,
+ 1890–1932,
DMT/IST for Dublin/Dunsink Mean Time and Irish Summer Time
- 1880&ndash;1916,
- MMT/MST/MDST for Moscow 1880&ndash;1919, and
- RMT/LST for Riga Mean Time and Latvian Summer time 1880&ndash;1926.
+ 1880–1916,
+ MMT/MST/MDST for Moscow 1880–1919, and
+ RMT/LST for Riga Mean Time and Latvian Summer time 1880–1926.
</small>
</p>
</li>
<li>
- Use '<abbr>LMT</abbr>' for local mean time of locations before the
- introduction of standard time; see "<a href="#scope">Scope of the
- <code><abbr>tz</abbr></code> database</a>".
+ Use “<abbr>LMT</abbr>” for local mean time of locations before the
+ introduction of standard time; see “<a href="#scope">Scope of the
+ <code><abbr>tz</abbr></code> database</a>”.
</li>
<li>
If there is no common English abbreviation, use numeric offsets like
<code>-</code>05 and <code>+</code>0530 that are generated
- by <code>zic</code>'s <code>%z</code> notation.
+ by <code>zic</code>’s <code>%z</code> notation.
</li>
<li>
Use current abbreviations for older timestamps to avoid confusion.
For example, in 1910 a common English abbreviation for time
- in central Europe was 'MEZ' (short for both "Middle European
- Zone" and for "Mitteleuropäische Zeit" in German).
- Nowadays 'CET' ("Central European Time") is more common in
- English, and the database uses 'CET' even for circa-1910
+ in central Europe was “MEZ” (short for both “Middle European
+ Zone” and for “Mitteleuropäische Zeit” in German).
+ Nowadays “CET” (“Central European Time”) is more common in
+ English, and the database uses “CET” even for circa-1910
timestamps as this is less confusing for modern users and avoids
- the need for determining when 'CET' supplanted 'MEZ' in common
+ the need for determining when “CET” supplanted “MEZ” in common
usage.
</li>
<li>
- Use a consistent style in a timezone's history.
+ Use a consistent style in a timezone’s history.
For example, if a history tends to use numeric
abbreviations and a particular entry could go either way, use a
numeric abbreviation.
@@ -586,13 +588,13 @@ in decreasing order of importance:
<li>
Use
<a href="https://en.wikipedia.org/wiki/Universal_Time">Universal Time</a>
- (<abbr>UT</abbr>) (with time zone abbreviation '<code>-</code>00') for
+ (<abbr>UT</abbr>) (with time zone abbreviation <code>-</code>00) for
locations while uninhabited.
- The leading '<code>-</code>' is a flag that the <abbr>UT</abbr> offset is in
+ The leading "<code>-</code>" is a flag that the <abbr>UT</abbr> offset is in
some sense undefined; this notation is derived
from <a href="https://www.rfc-editor.org/rfc/rfc3339">Internet
<abbr title="Request For Comments">RFC</abbr> 3339</a>.
- (The abbreviation 'Z' that
+ (The abbreviation Z that
<a href="https://www.rfc-editor.org/rfc/rfc9557">Internet
<abbr>RFC</abbr> 9557</a> uses for this concept
would violate the POSIX requirement
@@ -602,11 +604,11 @@ in decreasing order of importance:
<p>
Application writers should note that these abbreviations are ambiguous
-in practice: e.g., 'CST' means one thing in China and something else
-in North America, and 'IST' can refer to time in India, Ireland or
+in practice: e.g., CST means one thing in China and something else
+in North America, and IST can refer to time in India, Ireland or
Israel.
To avoid ambiguity, use numeric <abbr>UT</abbr> offsets like
-'<code>-</code>0600' instead of time zone abbreviations like 'CST'.
+<code>-</code>0600 instead of time zone abbreviations like CST.
</p>
</section>
@@ -617,7 +619,7 @@ The <code><abbr>tz</abbr></code> database is not authoritative, and it
surely has errors.
Corrections are welcome and encouraged; see the file <code>CONTRIBUTING</code>.
Users requiring authoritative data should consult national standards
-bodies and the references cited in the database's comments.
+bodies and the references cited in the database’s comments.
</p>
<p>
@@ -639,7 +641,7 @@ Errors in the <code><abbr>tz</abbr></code> database arise from many sources:
clocks actually behaved; the vast majority of the necessary
information was lost or never recorded.
Thousands more timezones would be needed if
- the <code><abbr>tz</abbr></code> database's scope were extended to
+ the <code><abbr>tz</abbr></code> database’s scope were extended to
cover even just the known or guessed history of standard time; for
example, the current single entry for France would need to split
into dozens of entries, perhaps hundreds.
@@ -648,14 +650,14 @@ Errors in the <code><abbr>tz</abbr></code> database arise from many sources:
should be observed.
In her 2015 book
<cite><a
- href="https://www.hup.harvard.edu/catalog.php?isbn=9780674286146">The
- Global Transformation of Time, 1870&ndash;1950</a></cite>,
+ href="https://www.hup.harvard.edu/books/9780674286146">The
+ Global Transformation of Time, 1870–1950</a></cite>,
Vanessa Ogle writes
- "Outside of Europe and North America there was no system of time
+ “Outside of Europe and North America there was no system of time
zones at all, often not even a stable landscape of mean times,
- prior to the middle decades of the twentieth century".
+ prior to the middle decades of the twentieth century”.
See: Timothy Shenk, <a
-href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanessa-ogle">Booked:
+href="https://dissentmagazine.org/blog/booked-a-global-history-of-time-vanessa-ogle/">Booked:
A Global History of Time</a>. <cite>Dissent</cite> 2015-12-17.
</li>
<li>
@@ -671,8 +673,8 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
For the UK the <code><abbr>tz</abbr></code> database relies on
years of first-class work done by
Joseph Myers and others; see
- "<a href="https://www.polyomino.org.uk/british-time/">History of
- legal time in Britain</a>".
+ “<a href="https://www.polyomino.org.uk/british-time/">History of
+ legal time in Britain</a>”.
Other countries are not done nearly as well.
</li>
<li>
@@ -697,13 +699,13 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
entries are often accurate for only a small subset of that region.
For example, <code>Europe/London</code> stands for the United
Kingdom, but its pre-1847 times are valid only for locations that
- have London's exact meridian, and its 1847 transition
+ have London’s exact meridian, and its 1847 transition
to <abbr>GMT</abbr> is known to be valid only for the L&amp;NW and
the Caledonian railways.
</li>
<li>
The <code><abbr>tz</abbr></code> database does not record the
- earliest time for which a timezone's
+ earliest time for which a timezone’s
data entries are thereafter valid for every location in the region.
For example, <code>Europe/London</code> is valid for all locations
in its region after <abbr>GMT</abbr> was made the standard time,
@@ -714,7 +716,7 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
</li>
<li>
The <code><abbr>tz</abbr></code> database does not record a
- region's boundaries, and in many cases the boundaries are not known.
+ region’s boundaries, and in many cases the boundaries are not known.
For example, the timezone
<code>America/Kentucky/Louisville</code> represents a region
around the city of Louisville, the boundaries of which are
@@ -747,7 +749,7 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
than what the <code><abbr>tz</abbr></code> code can handle.
For example, from 1880 to 1916 clocks in Ireland observed Dublin Mean
Time (estimated to be <abbr>UT</abbr>
- &minus;00:25:21.1); although the <code><abbr>tz</abbr></code>
+ −00:25:21.1); although the <code><abbr>tz</abbr></code>
source data can represent the .1 second, TZif files and the code cannot.
In practice these old specifications were rarely if ever
implemented to subsecond precision.
@@ -787,9 +789,9 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
non-hour-based system at night.
And even today, some local practices diverge from the Gregorian
calendar with 24-hour days. These divergences range from
- relatively minor, such as Japanese bars giving times like "24:30" for the
+ relatively minor, such as Japanese bars giving times like 24:30 for the
wee hours of the morning, to more-significant differences such as <a
- href="https://theworld.org/stories/2015-01-30/if-you-have-meeting-ethiopia-you-better-double-check-time">the
+ href="https://theworld.org/stories/2015/01/30/ethiopian-time">the
east African practice of starting the day at dawn</a>, renumbering
the Western 06:00 to be 12:00. These practices are largely outside
the scope of the <code><abbr>tz</abbr></code> code and data, which
@@ -825,16 +827,16 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
<li>
Civil time was not based on atomic time before 1972, and we do not
know the history of
- <a href="https://en.wikipedia.org/wiki/Earth's_rotation">earth's
+ <a href="https://en.wikipedia.org/wiki/Earth's_rotation">earth’s
rotation</a> accurately enough to map <a
href="https://en.wikipedia.org/wiki/International_System_of_Units"><abbr
title="International System of Units">SI</abbr></a> seconds to
historical <a href="https://en.wikipedia.org/wiki/Solar_time">solar time</a>
to more than about one-hour accuracy.
- See: Stephenson FR, Morrison LV, Hohenkerk CY.
- <a href="https://dx.doi.org/10.1098/rspa.2016.0404">Measurement of
- the Earth's rotation: 720 BC to AD 2015</a>.
- <cite>Proc Royal Soc A</cite>. 2016;472:20160404.
+ See: Morrison LV, Stephenson FR, Hohenkerk CY, Zawilski M.
+ <a href="https://doi.org/10.1098/rspa.2020.0776">Addendum 2020
+ to ‘Measurement of the Earth’s rotation: 720 BC to AD 2015’</a>.
+ <cite>Proc Royal Soc A</cite>. 2021;477:20200776.
Also see: Espenak F. <a
href="https://eclipse.gsfc.nasa.gov/SEhelp/uncertainty2004.html">Uncertainty
in Delta T (ΔT)</a>.
@@ -843,7 +845,7 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
The relationship between POSIX time (that is, <abbr>UTC</abbr> but
ignoring <a href="https://en.wikipedia.org/wiki/Leap_second">leap
seconds</a>) and <abbr>UTC</abbr> is not agreed upon.
- This affects time stamps during the leap second era (1972&ndash;2035).
+ This affects time stamps during the leap second era (1972–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
@@ -862,12 +864,12 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
<p>
In short, many, perhaps most, of the <code><abbr>tz</abbr></code>
-database's pre-1970 and future timestamps are either wrong or
+database’s pre-1970 and future timestamps are either wrong or
misleading.
Any attempt to pass the
<code><abbr>tz</abbr></code> database off as the definition of time
should be unacceptable to anybody who cares about the facts.
-In particular, the <code><abbr>tz</abbr></code> database's
+In particular, the <code><abbr>tz</abbr></code> database’s
<abbr>LMT</abbr> offsets should not be considered meaningful, and
should not prompt creation of timezones
merely because two locations
@@ -886,7 +888,7 @@ Code compatible with this package is already
primary use of this package is to update obsolete time-related files.
To do this, you may need to compile the time zone compiler
<code>zic</code> supplied with this package instead of using the
-system <code>zic</code>, since the format of <code>zic</code>'s
+system <code>zic</code>, since the format of <code>zic</code>’s
input is occasionally extended, and a platform may still be shipping
an older <code>zic</code>.
</p>
@@ -914,7 +916,8 @@ environment variable <code>TZ</code>, which can have two forms:
<h3 id="POSIX.1-2017">POSIX.1-2017 properties and limitations</h3>
<p>
-Some platforms support only the features required by POSIX.1-2017,
+Some platforms support only the features required by POSIX.1-2017
+and earlier editions,
and have not yet upgraded to POSIX.1-2024.
Code intended to be portable to these platforms must deal
with problems that were fixed in later POSIX editions.
@@ -956,14 +959,14 @@ with problems that were fixed in later POSIX editions.
are 3 or more characters specifying the standard
and daylight saving time (<abbr>DST</abbr>) zone abbreviations.
Starting with POSIX.1-2001, <var>std</var> and <var>dst</var>
- may also be in a quoted form like '<code>&lt;+09&gt;</code>';
+ may also be quoted in angle brackets, like <code>&lt;+09&gt;</code>;
this allows "<code>+</code>" and "<code>-</code>" in the names.
</dd>
<dt><var>offset</var></dt><dd>
is of the form
- '<code>[&plusmn;]<var>hh</var>:[<var>mm</var>[:<var>ss</var>]]</code>'
+ <code>[±]<var>hh</var>:[<var>mm</var>[:<var>ss</var>]]</code>
and specifies the offset west of <abbr>UT</abbr>.
- '<var>hh</var>' may be a single digit;
+ <var>hh</var> may be a single digit;
0&le;<var>hh</var>&le;24.
The default <abbr>DST</abbr> offset is one hour ahead of
standard time.
@@ -976,10 +979,10 @@ with problems that were fixed in later POSIX editions.
</dd>
<dt><var>time</var></dt><dd>
takes the form
- '<var>hh</var><code>:</code>[<var>mm</var>[<code>:</code><var>ss</var>]]'
+ <var>hh</var><code>:</code>[<var>mm</var>[<code>:</code><var>ss</var>]]
and defaults to 02:00.
This is the same format as the offset, except that a
- leading '<code>+</code>' or '<code>-</code>' is not allowed.
+ leading "<code>+</code>" or "<code>-</code>" is not allowed.
</dd>
<dt><var>date</var></dt><dd>
takes one of the following forms:
@@ -996,7 +999,7 @@ with problems that were fixed in later POSIX editions.
for the <var>d</var>th day of week <var>n</var> of
month <var>m</var> of the year, where week 1 is the first
week in which day <var>d</var> appears, and
- '<code>5</code>' stands for the last week in which
+ "<code>5</code>" stands for the last week in which
day <var>d</var> appears (which may be either the 4th or
5th week).
Typically, this is the only useful form; the <var>n</var>
@@ -1011,8 +1014,8 @@ with problems that were fixed in later POSIX editions.
Zealand after 2007.
It says that standard time (<abbr>NZST</abbr>) is 12 hours ahead
of <abbr>UT</abbr>, and that daylight saving time
- (<abbr>NZDT</abbr>) is observed from September's last Sunday at
- 02:00 until April's first Sunday at 03:00:
+ (<abbr>NZDT</abbr>) is observed from September’s last Sunday at
+ 02:00 until April’s first Sunday at 03:00:
</p>
<pre><code>TZ='NZST-12NZDT,M9.5.0,M4.1.0/3'</code></pre>
@@ -1048,11 +1051,11 @@ POSIX.1-2024 extends POSIX.1-2017 in the following significant ways:
Earlier POSIX editions lack this requirement.
</li>
<li>
- DST transition times can range from &minus;167:59:59
+ DST transition times can range from −167:59:59
to 167:59:59 instead of merely from 00:00:00 to 24:59:59.
This allows for proleptic TZ strings
like <code>"&lt;-02&gt;2&lt;-01&gt;,M3.5.0/-1,M10.5.0/0"</code>
- where the transition time &minus;1:00 means 23:00 the previous day.
+ where the transition time −1:00 means 23:00 the previous day.
</li>
</ul>
<p>
@@ -1065,14 +1068,14 @@ However POSIX.1-2024, like earlier POSIX editions, has some limitations:
</li>
<li>
In POSIX, there is no tamper-proof way for a process to learn the
- system's best idea of local (wall clock) time.
+ system’s best idea of local (wall clock) time.
This is important for applications that an administrator wants
- used only at certain times &ndash; without regard to whether the
+ used only at certain times – without regard to whether the
user has fiddled the
<code>TZ</code> environment variable.
- While an administrator can "do everything in <abbr>UT</abbr>" to
+ While an administrator can “do everything in <abbr>UT</abbr>” to
get around the problem, doing so is inconvenient and precludes
- handling daylight saving time shifts &ndash; as might be required to
+ handling daylight saving time shifts – as might be required to
limit phone calls to off-peak hours.
</li>
<li>
@@ -1081,8 +1084,7 @@ However POSIX.1-2024, like earlier POSIX editions, has some limitations:
</li>
<li>
POSIX does not define the <abbr>DST</abbr> transitions
- for <code>TZ</code> values like
- "<code>EST5EDT</code>".
+ for settings like <code>TZ='EST5EDT'</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
@@ -1124,9 +1126,9 @@ However POSIX.1-2024, like earlier POSIX editions, has some limitations:
If the <code>TZ</code> environment variable uses the geographical format,
it is used in generating
the name of a file from which time-related information is read.
- The file's format is <dfn><abbr>TZif</abbr></dfn>,
+ The file’s format is <dfn><abbr>TZif</abbr></dfn>,
a timezone information format that contains binary data; see
- <a href="https://www.rfc-editor.org/rfc/9636">Internet
+ <a href="https://www.rfc-editor.org/rfc/rfc9636">Internet
<abbr>RFC</abbr> 9636</a>.
The daylight saving time rules to be used for a
particular timezone are encoded in the
@@ -1138,18 +1140,18 @@ However POSIX.1-2024, like earlier POSIX editions, has some limitations:
<p>
When the <code><abbr>tz</abbr></code> code was developed in the 1980s,
it was recognized that allowing the <code>TZ</code> environment
- variable to take on values such as '<code>America/New_York</code>'
- might cause "old" programs (that expect <code>TZ</code> to have a
+ variable to take on values such as <code>America/New_York</code>
+ might cause old programs (that expect <code>TZ</code> to have a
certain format) to operate incorrectly; consideration was given to using
some other environment variable (for example, <code>TIMEZONE</code>)
- to hold the string used to generate the <abbr>TZif</abbr> file's name.
+ to hold the string used to generate the <abbr>TZif</abbr> file’s name.
In the end, however, it was decided to continue using
<code>TZ</code>: it is widely used for time zone purposes;
separately maintaining both <code>TZ</code>
and <code>TIMEZONE</code> seemed a nuisance; and systems where
- "new" forms of <code>TZ</code> might cause problems can simply
- use legacy <code>TZ</code> values such as "<code>EST5EDT</code>" which
- can be used by "new" programs as well as by "old" programs that
+ new forms of <code>TZ</code> might cause problems can simply
+ use legacy settings such as <code>TZ='EST5EDT'</code> which
+ can be used by new programs as well as by old programs that
assume pre-POSIX <code>TZ</code> values.
</p>
</li>
@@ -1192,20 +1194,20 @@ The vestigial <abbr>API</abbr>s are:
The POSIX <code>tzname</code> variable does not suffice and is no
longer needed.
It is planned to be removed in a future edition of POSIX.
- To get a timestamp's time zone abbreviation, consult
+ To get a timestamp’s time zone abbreviation, consult
the <code>tm_zone</code> member if available; otherwise,
- use <code>strftime</code>'s <code>"%Z"</code> conversion
+ use <code>strftime</code>’s <code>"%Z"</code> conversion
specification.
</li>
<li>
The POSIX <code>daylight</code> and <code>timezone</code>
variables do not suffice and are no longer needed.
They are planned to be removed in a future edition of POSIX.
- To get a timestamp's <abbr>UT</abbr> offset, consult
+ To get a timestamp’s <abbr>UT</abbr> offset, consult
the <code>tm_gmtoff</code> member if available; otherwise,
subtract values returned by <code>localtime</code>
and <code>gmtime</code> using the rules of the Gregorian calendar,
- or use <code>strftime</code>'s <code>"%z"</code> conversion
+ or use <code>strftime</code>’s <code>"%z"</code> conversion
specification if a string like <code>"+0900"</code> suffices.
</li>
<li>
@@ -1230,9 +1232,9 @@ The vestigial <abbr>API</abbr>s are:
<li>
The <a href="https://en.wikipedia.org/wiki/Version_7_Unix">7th Edition
UNIX</a> <code>timezone</code> function is not present in this
- package; it is impossible to reliably map <code>timezone</code>'s
- arguments (a "minutes west of <abbr>GMT</abbr>" value and a
- "daylight saving time in effect" flag) to a time zone
+ package; it is impossible to reliably map <code>timezone</code>’s
+ arguments (a “minutes west of <abbr>GMT</abbr>” value and a
+ “daylight saving time in effect” flag) to a time zone
abbreviation, and we refuse to guess.
Programs that in the past used the <code>timezone</code> function
may now examine <code>localtime(&amp;clock)-&gt;tm_zone</code>
@@ -1262,7 +1264,7 @@ The vestigial <abbr>API</abbr>s are:
The functions that are conditionally compiled
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
+ They are not in any sense “standard compatible” – some are
not, in fact, specified in <em>any</em> standard.
They do, however, represent responses of various authors to
standardization proposals.
@@ -1293,11 +1295,11 @@ The <code><abbr>tz</abbr></code> code and data supply the following interfaces:
<ul>
<li>
A set of timezone names as per
- "<a href="#naming">Timezone identifiers</a>" above.
+ “<a href="#naming">Timezone identifiers</a>” above.
</li>
<li>
- Library functions described in "<a href="#functions">Time and date
- functions</a>" above.
+ Library functions described in “<a href="#functions">Time and date
+ functions</a>” above.
</li>
<li>
The programs <code>tzselect</code>, <code>zdump</code>,
@@ -1319,7 +1321,7 @@ The <code><abbr>tz</abbr></code> code and data supply the following interfaces:
</li>
<li>
The version number of the code and data, as the first line of
- the text file '<code>version</code>' in each release.
+ the text file "<code>version</code>" in each release.
</li>
</ul>
@@ -1347,7 +1349,7 @@ For example, even though the <samp>Asia/Bangkok</samp> timezone
currently includes Chang Mai, Hanoi, and Phnom Penh, this is not part
of the stable interface and the timezone can split at any time.
If a calendar application records a future event in some location other
-than Bangkok by putting "<samp>Asia/Bangkok</samp>" in the event's record,
+than Bangkok by putting <samp>Asia/Bangkok</samp> in the event’s record,
the application should be robust in the presence of timezone splits
between now and the future time.
</p>
@@ -1381,7 +1383,7 @@ 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>
@@ -1391,8 +1393,8 @@ 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>
at the same point that time zone and <abbr>DST</abbr>
-adjustments are applied &ndash;
-namely, at calls to <code>localtime</code> and analogous functions &ndash;
+adjustments are applied –
+namely, at calls to <code>localtime</code> and analogous functions –
and the process is driven by leap second information
stored in alternate versions of the <abbr>TZif</abbr> files.
Because a leap second adjustment may be needed even
@@ -1402,7 +1404,7 @@ also need to consult a <abbr>TZif</abbr> file,
conventionally named <samp><abbr>Etc/UTC</abbr></samp>
(<samp><abbr>GMT</abbr></samp> in previous versions),
to see whether leap second corrections are needed.
-To convert an application's <code>time_t</code> timestamps to or from
+To convert an application’s <code>time_t</code> timestamps to or from
POSIX <code>time_t</code> timestamps (for use when, say,
embedding or interpreting timestamps in portable
<a href="https://en.wikipedia.org/wiki/Tar_(computing)"><code>tar</code></a>
@@ -1425,7 +1427,7 @@ So if you configure your kernel to count leap seconds, you should also
discard <samp>zoneinfo</samp> and rename <samp>zoneinfo-leaps</samp>
to <samp>zoneinfo</samp>.
Alternatively, you can install just one set of <abbr>TZif</abbr> files
-in the first place; see the <code>REDO</code> variable in this package's
+in the first place; see the <code>REDO</code> variable in this package’s
<a href="https://en.wikipedia.org/wiki/Makefile">makefile</a>.
</p>
</section>
@@ -1438,9 +1440,9 @@ but they indicate the sort of problems that we would run into if we
extended the time zone database further into the past.
An excellent resource in this area is Edward M. Reingold
and Nachum Dershowitz, <cite><a
-href="https://www.cambridge.org/fr/academic/subjects/computer-science/computing-general-interest/calendrical-calculations-ultimate-edition-4th-edition">Calendrical
+href="https://www.cambridge.org/fr/universitypress/subjects/computer-science/computing-general-interest/calendrical-calculations-ultimate-edition-4th-edition">Calendrical
Calculations: The Ultimate Edition</a></cite>, Cambridge University Press (2018).
-Other information and sources are given in the file '<code>calendars</code>'
+Other information and sources are given in the file "<code>calendars</code>"
in the <code><abbr>tz</abbr></code> distribution.
They sometimes disagree.
</p>
@@ -1450,20 +1452,20 @@ They sometimes disagree.
<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>
+href="https://www.esa.int/Applications/Satellite_navigation/Telling_time_on_the_Moon">considering</a>
the establishment of a reference timescale for the Moon, which has
days roughly equivalent to 29.5 Earth days, and where relativistic
effects cause clocks to tick slightly faster than on Earth.
Also, <abbr title="National Aeronautics and Space Administration">NASA</abbr>
has been <a
-href='https://www.whitehouse.gov/wp-content/uploads/2024/04/Celestial-Time-Standardization-Policy.pdf'>ordered</a>
+href="https://bidenwhitehouse.archives.gov/wp-content/uploads/2024/04/Celestial-Time-Standardization-Policy.pdf">ordered</a>
to consider the establishment of Coordinated Lunar Time (<abbr>LTC</abbr>).
It is not yet known whether the US and European efforts will result in
multiple timescales on the Moon.
</p>
<p>
-Some people's work schedules have used
+Some people’s work schedules have used
<a href="https://en.wikipedia.org/wiki/Timekeeping_on_Mars">Mars time</a>.
Jet Propulsion Laboratory (JPL) coordinators kept Mars time on
and off during the
@@ -1473,7 +1475,7 @@ Some of their family members also adapted to Mars time.
Dozens of special Mars watches were built for JPL workers who kept
Mars time during the
<a href="https://en.wikipedia.org/wiki/Mars_Exploration_Rover">Mars
-Exploration Rovers (MER)</a> mission (2004&ndash;2018).
+Exploration Rovers (MER)</a> mission (2004–2018).
These timepieces looked like normal Seikos and Citizens but were adjusted
to use Mars seconds rather than terrestrial seconds, although
unfortunately the adjusted watches were unreliable and appear to have
@@ -1481,12 +1483,12 @@ had only limited use.
</p>
<p>
-A Mars solar day is called a "sol" and has a mean period equal to
+A Mars solar day is called a “sol” and has a mean period equal to
about 24 hours 39 minutes 35.244 seconds in terrestrial time.
It is divided into a conventional 24-hour clock, so each Mars second
equals about 1.02749125 terrestrial seconds.
-(One MER worker noted, "If I am working Mars hours, and Mars hours are
-2.5% more than Earth hours, shouldn't I get an extra 2.5% pay raise?")
+(One MER worker noted, “If I am working Mars hours, and Mars hours are
+2.5% more than Earth hours, shouldn’t I get an extra 2.5% pay raise?”)
</p>
<p>
@@ -1494,7 +1496,7 @@ The <a href="https://en.wikipedia.org/wiki/Prime_meridian">prime
meridian</a> of Mars goes through the center of the crater
<a href="https://en.wikipedia.org/wiki/Airy-0">Airy-0</a>, named in
honor of the British astronomer who built the Greenwich telescope that
-defines Earth's prime meridian.
+defines Earth’s prime meridian.
Mean solar time on the Mars prime meridian is
called Mars Coordinated Time (<abbr>MTC</abbr>).
</p>
@@ -1502,13 +1504,13 @@ called Mars Coordinated Time (<abbr>MTC</abbr>).
<p>
Each landed mission on Mars has adopted a different reference for
solar timekeeping, so there is no real standard for Mars time zones.
-For example, the MER mission defined two time zones "Local
-Solar Time A" and "Local Solar Time B" for its two missions, each zone
+For example, the MER mission defined two time zones “Local
+Solar Time A” and “Local Solar Time B” for its two missions, each zone
designed so that its time equals local true solar time at
approximately the middle of the nominal mission.
The A and B zones differ enough so that an MER worker assigned to
-the A zone might suffer "Mars lag" when switching to work in the B zone.
-Such a "time zone" is not particularly suited for any application
+the A zone might suffer “Mars lag” when switching to work in the B zone.
+Such a “time zone” is not particularly suited for any application
other than the mission itself.
</p>
@@ -1522,13 +1524,13 @@ sequential count of Mars solar days elapsed since about 1873-12-29
<p>
In our solar system, Mars is the planet with time and calendar most
-like Earth's.
+like Earth’s.
On other planets, Sun-based time and calendars would work quite
differently.
-For example, although Mercury's
+For example, although Mercury’s
<a href="https://en.wikipedia.org/wiki/Rotation_period">sidereal
rotation period</a> is 58.646 Earth days, Mercury revolves around the
-Sun so rapidly that an observer on Mercury's equator would see a
+Sun so rapidly that an observer on Mercury’s equator would see a
sunrise only every 175.97 Earth days, i.e., a Mercury year is 0.5 of a
Mercury day.
Venus is more complicated, partly because its rotation is slightly
@@ -1554,8 +1556,8 @@ Sources for time on other planets:
<ul>
<li>
Michael Allison and Robert Schmunk,
- "<a href="https://www.giss.nasa.gov/tools/mars24/help/notes.html">Technical
- Notes on Mars Solar Time as Adopted by the Mars24 Sunclock</a>"
+ “<a href="https://www.giss.nasa.gov/tools/mars24/help/notes.html">Technical
+ Notes on Mars Solar Time as Adopted by the Mars24 Sunclock</a>”
(2020-03-08).
</li>
<li>
@@ -1565,28 +1567,33 @@ Sources for time on other planets:
</li>
<li>
Jia-Rui Chong,
- "<a href="https://www.latimes.com/archives/la-xpm-2004-jan-14-sci-marstime14-story.html">Workdays
- Fit for a Martian</a>", <cite>Los Angeles Times</cite>
- (2004-01-14), pp A1, A20&ndash;A21.
+ “<a href="https://www.latimes.com/archives/la-xpm-2004-jan-14-sci-marstime14-story.html">Workdays
+ Fit for a Martian</a>”, <cite>Los Angeles Times</cite>
+ (2004-01-14), pp A1, A20–A21.
</li>
<li>
Tom Chmielewski,
- "<a href="https://www.theatlantic.com/technology/archive/2015/02/jet-lag-is-worse-on-mars/386033/">Jet
- Lag Is Worse on Mars</a>", <cite>The Atlantic</cite> (2015-02-26)
+ “<a href="https://www.theatlantic.com/technology/archive/2015/02/jet-lag-is-worse-on-mars/386033/">Jet
+ Lag Is Worse on Mars</a>”, <cite>The Atlantic</cite> (2015-02-26)
</li>
<li>
Matt Williams,
- "<a href="https://www.universetoday.com/37481/days-of-the-planets/">How
- long is a day on the other planets of the solar system?</a>"
+ “<a href="https://www.universetoday.com/articles/days-of-the-planets">How
+ long is a day on the other planets of the solar system?</a>”
(2016-01-20).
</li>
</ul>
</section>
<footer>
- <hr>
- This file is in the public domain, so clarified as of 2009-05-17 by
- Arthur David Olson.
+<hr>
+This web page is in the public domain, so clarified as of
+2009-05-17 by Arthur David Olson.
+<br>
+Please send corrections to this web page to the
+<a href="mailto:tz@iana.org">time zone mailing list</a>.
+The mailing list and its archives are public,
+so please do not send confidential information.
</footer>
</body>
</html>
diff --git a/contrib/tzcode/time2posix.3 b/contrib/tzcode/time2posix.3
index f4e4ffdc6590..268f3727ea47 100644
--- a/contrib/tzcode/time2posix.3
+++ b/contrib/tzcode/time2posix.3
@@ -1,6 +1,6 @@
.\" This file is in the public domain, so clarified as of
.\" 1996-06-05 by Arthur David Olson.
-.Dd December 15, 2022
+.Dd March 8, 2026
.Dt TIME2POSIX 3
.Os
.Sh NAME
@@ -17,10 +17,9 @@
.Fn posix2time "time_t t"
.Sh DESCRIPTION
.St -p1003.1-88
-requires the time_t value 536457599 to stand for 1986-12-31 23:59:59 UTC.
-This effectively implies that POSIX
-.Vt time_t
-values cannot include leap
+says that
+.B time_t
+values cannot count leap
seconds and,
therefore,
that the system time must be adjusted as each leap occurs.
@@ -37,28 +36,25 @@ value).
This means that these values will differ from those required by POSIX
by the net number of leap seconds inserted since the Epoch.
.Pp
-Typically this is not a problem as the type
+For many C programs this is not a problem as the C standard says that
.Vt time_t
-is intended
-to be
+is
(mostly)
opaque \(em
.Vt time_t
-values should only be obtained-from and
-passed-to functions such as
-.Xr time 3 ,
+values should be obtained from and
+passed to functions such as
+.Xr time 2 ,
.Xr localtime 3 ,
-.Xr mktime 3
+.Xr mktime 3 ,
and
.Xr difftime 3 .
However,
-.St -p1003.1-88
-gives an arithmetic
-expression for directly computing a
+POSIX gives an arithmetic
+expression for computing a
.Vt time_t
-value from a given date/time,
+value directly from a given Universal date and time,
and the same relationship is assumed by some
-(usually older)
applications.
Any programs creating/dissecting
.Vt time_t
@@ -70,38 +66,31 @@ The
.Fn time2posix
and
.Fn posix2time
-functions are provided to address this
-.Vt time_t
-mismatch by converting
+functions address this mismatch by converting
between local
.Vt time_t
values and their POSIX equivalents.
This is done by accounting for the number of time-base changes that
would have taken place on a POSIX system as leap seconds were inserted
or deleted.
-These converted values can then be used in lieu of correcting the older
-applications,
-or when communicating with POSIX-compliant systems.
+These converted values can then be used
+when communicating with POSIX-compliant systems.
.Pp
The
.Fn time2posix
-function
-is single-valued.
-That is,
-every local
+function converts a
.Vt time_t
-corresponds to a single POSIX
-.Vt time_t .
+value to its POSIX counterpart, if one exists.
The
.Fn posix2time
-function
+function does the reverse but
is less well-behaved:
for a positive leap second hit the result is not unique,
and for a negative leap second hit the corresponding
POSIX
.Vt time_t
-does not exist so an adjacent value is returned.
-Both of these are good indicators of the inferiority of the
+doesn't exist so an adjacent value is returned.
+Both of these are indicate problems with the
POSIX representation.
.Pp
The following table summarizes the relationship between a time
@@ -109,23 +98,35 @@ T and its conversion to,
and back from,
the POSIX representation over the leap second inserted at the end of June,
1993.
-.Bl -column "93/06/30" "23:59:59" "A+0" "X=time2posix(T)"
-.It Sy "DATE TIME T X=time2posix(T) posix2time(X)"
-.It "93/06/30 23:59:59 A+0 B+0 A+0"
-.It "93/06/30 23:59:60 A+1 B+1 A+1 or A+2"
-.It "93/07/01 00:00:00 A+2 B+1 A+1 or A+2"
-.It "93/07/01 00:00:01 A+3 B+2 A+3"
-.El
+In this table,
+.Li X=time2posix(T) ,
+.Li Y=posix2time(X) ,
+.Li A=741484816 ,
+and
+.Li B=A\-17
+because 17 positive leap seconds preceded this leap second.
.Pp
-A leap second deletion would look like...
-.Bl -column "??/06/30" "23:59:58" "A+0" "X=time2posix(T)"
-.It Sy "DATE TIME T X=time2posix(T) posix2time(X)"
-.It "??/06/30 23:59:58 A+0 B+0 A+0"
-.It "??/07/01 00:00:00 A+1 B+2 A+1"
-.It "??/07/01 00:00:01 A+2 B+3 A+2"
+.Bl -column "1993-06-30" "23:59:59" "A+0" "B+0"
+.It DATE TIME T X Y
+.It 1993-06-30 23:59:59 A B A
+.It 1993-06-30 23:59:60 A+1 B+1 A+1 or A+2
+.It 1993-07-01 00:00:00 A+2 B+1 A+1 or A+2
+.It 1993-07-01 00:00:01 A+3 B+2 A+3
.El
.Pp
-.D1 No "[Note: posix2time(B+1) => A+0 or A+1]"
+A leap second deletion would look like the following, and
+.Li posix2time(B+1)
+would return either
+.Li A
+or
+.Li A+1 .
+.Pp
+.Bl -column "????-06-30" "23:59:58" "A+1" "B+2" "A+1"
+.It DATE TIME T X Y
+.It ????-06-30 23:59:58 A B A
+.It ????-07-01 00:00:00 A+1 B+2 A+1
+.It ????-07-01 00:00:01 A+2 B+3 A+2
+.El
.Pp
If leap-second support is not enabled,
local
@@ -139,6 +140,31 @@ and both
and
.Fn posix2time
degenerate to the identity function.
+.Sh RETURN VALUES
+If successful, these functions return the resulting timestamp without modifying
+.Va errno .
+Otherwise, they set
+.Va errno
+and return
+.Li "((time_t) -1)" .
+.Sh ERRORS
+These functions fail if:
+.Bl -tag -width Er
+.It Bq Er EOVERFLOW
+The resulting value cannot be represented.
+This can happen for
+.Fn posix2time
+if its argument is close to the maximum
+.Vt time_t
+value.
+In environments where the
+.Ev TZ
+environment variable names a TZif file,
+overflow can happen for either function for an argument sufficiently
+close to an extreme
+.Vt time_t
+value if the TZif file specifies unrealistic leap second corrections.
+.El
.Sh "SEE ALSO"
.Xr difftime 3 ,
.Xr localtime 3 ,
diff --git a/contrib/tzcode/tz-art.html b/contrib/tzcode/tz-art.html
index 15ba7f4ec54b..1bd1bf781166 100644
--- a/contrib/tzcode/tz-art.html
+++ b/contrib/tzcode/tz-art.html
@@ -2,6 +2,10 @@
<html lang="en">
<head>
<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+ul {padding-left: 1.3rem;}
+</style>
<title>Time and the Arts</title>
</head>
<body>
@@ -9,28 +13,40 @@
<h2>Documentaries</h2>
<ul>
<li>
-"<a href="https://www.youtube.com/watch?v=84aWtseb2-4">Daylight
-Saving Time Explained</a>" (2011; 6:39) lightly covers daylight saving
-time's theory, history, pros and cons. Among other things, it explains
-Arizona's daylight-saving enclaves quite well.</li>
+“<a href="https://www.youtube.com/watch?v=84aWtseb2-4">Daylight
+Saving Time Explained</a>” (2011; 6:39) lightly covers daylight saving
+time’s theory, history, pros and cons. Among other things, it explains
+Arizona’s daylight-saving enclaves quite well.
+</li>
<li>
-"<a href="https://www.youtube.com/watch?v=-5wpm-gesOY">The Problem
-with Time &amp; Timezones &ndash; Computerphile</a>" (2013; 10:12) delves
-into problems that programmers have with timekeeping.</li>
+“<a href="https://www.youtube.com/watch?v=-5wpm-gesOY">The Problem
+with Time &amp; Timezones – Computerphile</a>” (2013; 10:12) delves
+into problems that programmers have with timekeeping.
+</li>
<li>
-"<a href="https://www.rferl.org/a/28375932.html">All The Time In The World:
-Explaining The Mysteries Of Time Zones</a>" (2017; 2:15)
+“<a href="https://www.rferl.org/a/all-the-time-in-the-world/28375932.html">All
+The Time In The World: Explaining The Mysteries Of Time Zones</a>” (2017; 2:15)
briefly says why France has more time zones than Russia.
+</li>
<li>
-"<a href="https://www.youtube.com/watch?v=yRz-Dl60Lfc">Why Denmark used to be
-.04 seconds behind the world</a>" (2019; 6:29) explains why the United Kingdom
-&mdash; and, once, Denmark &mdash; haven't always exactly followed their own
+“<a href="https://www.youtube.com/watch?v=yRz-Dl60Lfc">Why Denmark used to be
+.04 seconds behind the world</a>” (2019; 6:29) explains why the United Kingdom
+– and, once, Denmark – haven’t always exactly followed their own
laws about civil time.
+</li>
<li>
-"About Time" (1962; 59 minutes) is part of the
+“<a href="https://www.youtube.com/watch?v=mfzsBMUiGGQ">How Daylight Savings
+Broke this $24 Million Building</a>” (2025; 5:01) describes the system of
+mirrors used at Melbourne’s Shrine of Remembrance to ensure the sun’s light
+still hits at the “correct” ceremonial hour to commemorate the Armistice which
+ended World War I.
+</li>
+<li>
+“About Time” (1962; 59 minutes) is part of the
Bell Science extravaganza, with Frank Baxter, Richard Deacon, and Les Tremayne.
Its advisor was Richard Feynman, and it was voiced by Mel Blanc.
-(<a href="https://www.imdb.com/title/tt0154110/">IMDb entry</a>.)</li>
+(<a href="https://www.imdb.com/title/tt0154110/">IMDb entry</a>.)
+</li>
</ul>
<h2>Movies</h2>
<ul>
@@ -39,15 +55,16 @@ In the 1946 movie <em>A Matter of Life and Death</em>
(U.S. title <em>Stairway to Heaven</em>)
there is a reference to British Double Summer Time.
The time does not play a large part in the plot;
-it's just a passing reference to the time when one of the
-characters was supposed to have died (but didn't).
+it’s just a passing reference to the time when one of the
+characters was supposed to have died (but didn’t).
(<a href="https://www.imdb.com/title/tt0038733/">IMDb entry.</a>)
(Dave Cantor)
+</li>
<li>
The 1953 railway comedy movie <em>The Titfield Thunderbolt</em> includes a
-play on words on British Double Summer Time. Valentine's wife wants
-him to leave the pub and asks him, "Do you know what time it is?"
-And he, happy where he is, replies: "Yes, my love. Summer double time."
+play on words on British Double Summer Time. Valentine’s wife wants
+him to leave the pub and asks him, “Do you know what time it is?”
+And he, happy where he is, replies: “Yes, my love. Summer double time.”
(<a href="https://www.imdb.com/title/tt0046436/">IMDb entry.</a>)
(Mark Brader, 2009-10-02)
</li>
@@ -60,12 +77,12 @@ is extended by 10 seconds, it will create a one-time opportunity for
a gigantic computerized theft. To achieve this, at one location the
crooks interfere with the microwave system supplying time signals to
the computer, advancing the time by 0.1 second each minute over the
-last hour of 1999. (So this movie teaches us that 0.1 &times; 60 = 10.)
+last hour of 1999. (So this movie teaches us that 0.1 × 60 = 10.)
(<a href="https://www.imdb.com/title/tt0137494/">IMDb entry.</a>)
(Mark Brader, 2009-10-02)
</li>
<li>
-One mustn't forget the
+One mustn’t forget the
<a href="https://www.youtube.com/watch?v=k4EUTMPuvHo">trailer</a>
(2014; 2:23) for the movie <em>Daylight Saving</em>.
</li>
@@ -73,74 +90,74 @@ One mustn't forget the
<h2>TV episodes</h2>
<ul>
<li>
-An episode of <em>The Adventures of Superman</em> entitled "The Mysterious
-Cube," first aired 1958-02-24, had Superman convincing the controllers
+An episode of <em>The Adventures of Superman</em> entitled “The Mysterious
+Cube”, first aired 1958-02-24, had Superman convincing the controllers
of the Arlington Time Signal to broadcast ahead of actual time;
doing so got a crook trying to be declared dead to
emerge a bit too early from the titular enclosure.
(<a href="https://www.imdb.com/title/tt0506628/">IMDb entry</a>.)
</li>
<li>
-"<a href="https://en.wikipedia.org/wiki/The_Chimes_of_Big_Ben">The Chimes
-of Big Ben</a>", <em>The Prisoner</em>, episode 2, ITC, 1967-10-06.
+“<a href="https://en.wikipedia.org/wiki/The_Chimes_of_Big_Ben">The Chimes
+of Big Ben</a>”, <em>The Prisoner</em>, episode 2, ITC, 1967-10-06.
Our protagonist tumbles to
-the fraudulent nature of a Poland-to-England escape upon hearing "Big
-Ben" chiming on Polish local time.
+the fraudulent nature of a Poland-to-England escape upon hearing Big
+Ben chiming on Polish local time.
(<a href="https://www.imdb.com/title/tt0679185/">IMDb entry.</a>)
</li>
<li>
-"The Susie", <em>Seinfeld</em>, season 8, episode 15, NBC, 1997-02-13.
+“The Susie”, <em>Seinfeld</em>, season 8, episode 15, NBC, 1997-02-13.
Kramer decides that daylight saving time
-isn't coming fast enough, so he sets his watch ahead an hour.
+isn’t coming fast enough, so he sets his watch ahead an hour.
</li>
<li>
-"20 Hours in America", <em>The West Wing</em>, season 4, episodes 1&ndash;2,
+“20 Hours in America”, <em>The West Wing</em>, season 4, episodes 1–2,
2002-09-25, contained a <a
href="https://www.youtube.com/watch?v=-J1NHzQ1sgc">scene</a> that
saw White House staffers stranded in Indiana; they thought they had time to
catch Air Force One but were done in by intra-Indiana local time changes.
</li>
<li>
-"In what time zone would you find New York City?" was a $200 question on
+“In what time zone would you find New York City?” was a $200 question on
the 1999-11-13 United States airing of <em>Who Wants to Be a Millionaire?</em>,
-and "In 1883, what industry led the movement to divide the U.S. into four time
-zones?" was a $32,000 question on the 2001-05-23 United States airing of
+and “In 1883, what industry led the movement to divide the U.S. into four time
+zones?” was a $32,000 question on the 2001-05-23 United States airing of
the same show. At this rate, the million-dollar time-zone
question should have been asked 2002-06-04.
</li>
<li>
-A private jet's mid-flight change of time zones distorts Alison Dubois'
-premonition in the "We Had a Dream" episode of <em>Medium</em>
+A private jet’s mid-flight change of time zones distorts Alison Dubois’
+premonition in the “We Had a Dream” episode of <em>Medium</em>
(originally aired 2007-02-28).
</li>
<li>
-A criminal's failure to account for the start of daylight saving is pivotal
-in "<a href="https://monk.fandom.com/wiki/Mr._Monk_and_the_Rapper">Mr. Monk
-and the Rapper</a>" (first aired 2007-07-20).
+A criminal’s failure to account for the start of daylight saving is pivotal
+in “<a href="https://monk.fandom.com/wiki/Mr._Monk_and_the_Rapper">Mr. Monk
+and the Rapper</a>” (first aired 2007-07-20).
</li>
<li>
-In the <em>30 Rock</em> episode "Anna Howard Shaw Day"
+In the <em>30 Rock</em> episode “Anna Howard Shaw Day”
(first broadcast 2010-02-11),
-Jack Donaghy's date realizes that a Geneva-to-New-York business phone call
+Jack Donaghy’s date realizes that a Geneva-to-New-York business phone call
received in the evening must be fake given the difference in local times.
</li>
<li>
-In the "Run by the Monkeys" episode of <em>Da Vinci's Inquest</em>
+In the “Run by the Monkeys” episode of <em>Da Vinci’s Inquest</em>
(first broadcast 2002-11-17),
a witness in a five-year-old fire case realizes they may not have set
their clock back when daylight saving ended on the day of the fire,
introducing the possibility of an hour when arson might have occurred.
</li>
<li>
-In "The Todd Couple" episode of <em>Outsourced</em> (first aired 2011-02-10),
-Manmeet sets up Valentine's Day teledates for 6:00 and 9:00pm;
+In “The Todd Couple” episode of <em>Outsourced</em> (first aired 2011-02-10),
+Manmeet sets up Valentine’s Day teledates for 6:00 and 9:00pm;
since one is with a New Yorker and the other with a San Franciscan,
hilarity ensues.
(Never mind that this should be 7:30am in Mumbai, yet for some reason the show
-proceeds as though it's also mid-evening there.)
+proceeds as though it’s also mid-evening there.)
</li>
<li>
-In the "14 Days to Go"/"T Minus..." episode of
+In the “14 Days to Go”/“T Minus...” episode of
<em>You, Me and the Apocalypse</em>
(first aired 2015-11-11 in the UK, 2016-03-10 in the US),
the success of a mission to deal with a comet
@@ -149,39 +166,39 @@ hinges on whether or not Russia observes daylight saving time.
the episode first aired in the week before the switch to <abbr>DST</abbr>.)
</li>
<li>
-"The Lost Hour", <em>Eerie, Indiana</em>, episode 10, NBC, 1991-12-01.
-Despite Indiana's then-lack of <abbr>DST</abbr>,
+“The Lost Hour”, <em>Eerie, Indiana</em>, episode 10, NBC, 1991-12-01.
+Despite Indiana’s then-lack of <abbr>DST</abbr>,
Marshall changes his clock with unusual consequences.
-See "<a
+See “<a
href="https://www.avclub.com/eerie-indiana-was-a-few-dimensions-ahead-of-its-time-1819833380"><em>Eerie,
-Indiana</em> was a few dimensions ahead of its time</a>".
+Indiana</em> was a few dimensions ahead of its time</a>”.
</li>
<li>
-"Time Tunnel", <em>The Adventures of Pete &amp; Pete</em>, season 2, episode 5,
-Nickelodeon, 1994-10-23.
+“Time Tunnel”, <em>The Adventures of Pete &amp; Pete</em>,
+season 2, episode 5, Nickelodeon, 1994-10-23.
The two Petes travel back in time an hour
on the day that <abbr>DST</abbr> ends.
</li>
<li>
-"King-Size Homer", <em>The Simpsons</em>, episode 135, Fox, 1995-11-05.
-Homer, working from home, remarks "8:58, first
-time I've ever been early for work. Except for all those daylight
-savings days. Lousy farmers."
+“King-Size Homer”, <em>The Simpsons</em>, episode 135, Fox, 1995-11-05.
+Homer, working from home, remarks “8:58, first
+time I’ve ever been early for work. Except for all those daylight
+savings days. Lousy farmers.”
</li>
<li>
<em>Last Week Tonight with John Oliver</em>, season 2, episode 5, 2015-03-08,
-asked, "<a href="https://www.youtube.com/watch?v=br0NW9ufUUw">Daylight Saving
-Time &ndash; How Is This Still A Thing?</a>"
+asked, “<a href="https://www.youtube.com/watch?v=br0NW9ufUUw">Daylight
+Saving Time – How Is This Still A Thing?</a>”
</li>
<li>
-"Tracks", <em>The Good Wife</em>, season 7, episode 12,
+“Tracks”, <em>The Good Wife</em>, season 7, episode 12,
CBS, 2016-01-17.
The applicability of a contract hinges on the
time zone associated with a video timestamp.
</li>
<li>
-"Justice", <em>Veep</em>, season 6, episode 4, HBO, 2017-05-07.
-Jonah's inability to understand <abbr>DST</abbr> ends up impressing a wealthy
+“Justice”, <em>Veep</em>, season 6, episode 4, HBO, 2017-05-07.
+Jonah’s inability to understand <abbr>DST</abbr> ends up impressing a wealthy
backer who sets him up for a 2020 presidential run.
</li>
</ul>
@@ -197,8 +214,8 @@ reading a paper.
Available versions include
<a href="https://www.gutenberg.org/ebooks/103">an English
translation</a>, and
-<a href="https://fourmilab.ch/etexts/www/tdm80j">the original French</a>
-"with illustrations from the original 1873 French-language edition".
+<a href="https://fourmilab.ch/etexts/www/tdm80j/">the original French</a>
+“with illustrations from the original 1873 French-language edition”.
</li>
<li>
Nick Enright, <em>Daylight Saving</em>, 1989.
@@ -208,24 +225,24 @@ A fast-paced comedy about love and loneliness as the clocks turn back.
Umberto Eco,
<a href="https://en.wikipedia.org/wiki/The_Island_of_the_Day_Before"><em>The
Island of the Day Before</em></a>
-(<em>L'isola del giorno prima</em>), 1994.
-"...the story of a 17th century Italian nobleman trapped near an island
+(<em>L’isola del giorno prima</em>), 1994.
+“...the story of a 17th century Italian nobleman trapped near an island
on the International Date Line. Time and time zones play an integral
-part in the novel." (Paul Eggert, 2006-04-22)
+part in the novel.” (Paul Eggert, 2006-04-22)
</li>
<li>
John Dunning, <a
href="https://www.simonandschuster.com/books/Two-OClock-Eastern-Wartime/John-Dunning/9781439171530"><em>Two
-O'Clock, Eastern Wartime</em></a>, 2001.
+O’Clock, Eastern Wartime</em></a>, 2001.
Mystery, history, daylight saving time, and old-time radio.
</li>
<li>
-Surrealist artist Guy Billout's work "Date Line" appeared on page 103
-of the 1999-11 <em>Atlantic Monthly</em>.
+Surrealist artist Guy Billout’s work “Date Line”
+appeared on page 103 of the 1999-11 <em>Atlantic Monthly</em>.
</li>
<li>
-"Gloom, Gloom, Go Away" by Walter Kirn appeared on page 106 of <em>Time</em>
-magazine's 2002-11-11 issue; among other things, it proposed
+“Gloom, Gloom, Go Away” by Walter Kirn appeared on page 106 of <em>Time</em>
+magazine’s 2002-11-11 issue; among other things, it proposed
year-round <abbr>DST</abbr> as a way of lessening wintertime despair.
</li>
<li>
@@ -237,20 +254,20 @@ href="https://craphound.com/est/download/"><em>Eastern Standard Tribe</em></a>,
<h2>Music</h2>
<ul>
<li>
-Recordings of "Save That Time," Russ Long, Serrob Publishing, BMI:
+Recordings of “Save That Time”, Russ Long, Serrob Publishing, BMI:
<ul>
<li>
-Karrin Allyson, <em>I Didn't Know About You</em> (1993), track 11, 3:44.
+Karrin Allyson, <em>I Didn’t Know About You</em> (1993), track 11, 3:44.
Concord Jazz CCD-4543.
Karrin Allyson, vocal;
Russ Long, piano;
Gerald Spaits, bass;
Todd Strait, drums.
-CD notes "additional lyric by Karrin Allyson;
-arranged by Russ Long and Karrin Allyson".
-ADO &#x2605;,
+CD notes “additional lyric by Karrin Allyson;
+arranged by Russ Long and Karrin Allyson”.
+ADO ★,
<a href="https://www.allmusic.com/album/i-didnt-know-about-you-mw0000618657">AMG</a>
-&#x2605;&#x2605;&#x2605;&#x2605;, Penguin &#x2605;&#x2605;&#x2605;&#x2BEA;.
+★★★★, Penguin ★★★⯪.
</li>
<li>
Kevin Mahogany, <em>Double Rainbow</em> (1993), track 3, 6:27. Enja ENJ-7097 2.
@@ -259,18 +276,18 @@ Kenny Barron, piano;
Ray Drummond, bass;
Ralph Moore, tenor saxophone;
Lewis Nash, drums.
-ADO &#x2605;&#x2BEA;,
+ADO ★⯪,
<a href="https://www.allmusic.com/album/double-rainbow-mw0000620371">AMG</a>
-&#x2605;&#x2605;&#x2605;, Penguin &#x2605;&#x2605;&#x2605;.
+★★★, Penguin ★★★.
</li>
<li>
-Joe Williams, <em>Here's to Life</em> (1994), track 7, 3:58.
+Joe Williams, <em>Here’s to Life</em> (1994), track 7, 3:58.
Telarc Jazz CD-83357.
Joe Williams, vocal; The Robert Farnon [39 piece] Orchestra.
-Also in a 3-CD package "Triple Play", Telarc CD-83461.
-ADO &#x2022;,
+Also in a 3-CD package “Triple Play”, Telarc CD-83461.
+ADO •,
<a href="https://www.allmusic.com/album/heres-to-life-mw0000623648">AMG</a>
-&#x2605;&#x2605;, Penguin &#x2605;&#x2605;&#x2605;.
+★★, Penguin ★★★.
</li>
<li>
Charles Fambrough, <em>Keeper of the Spirit</em> (1995), track 7, 7:07.
@@ -280,9 +297,9 @@ Joel Levine, tenor recorder;
Edward Simon, piano;
Lenny White, drums;
Marion Simon, percussion.
-ADO &#x2605;,
+ADO ★,
<a href="https://www.allmusic.com/album/keeper-of-the-spirit-mw0000176559">AMG</a>
-unrated, Penguin &#x2605;&#x2605;&#x2605;.
+unrated, Penguin ★★★.
</ul>
</li>
<li>
@@ -290,11 +307,11 @@ Holly Cole Trio, Blame It On My Youth (1992). Manhattan CDP 7 97349 2, 37:45.
Holly Cole, voice;
Aaron Davis, piano;
David Piltch, string bass.
-Lyrical reference to "Eastern Standard Time" in
-Tom Waits's "Purple Avenue".
-ADO &#x2605;&#x2605;&#x2BEA;,
+Lyrical reference to “Eastern Standard Time” in
+Tom Waits’s “Purple Avenue”.
+ADO ★★⯪,
<a href="https://www.allmusic.com/album/blame-it-on-my-youth-mw0000274303">AMG</a>
-&#x2605;&#x2605;&#x2605;, Penguin unrated.
+★★★, Penguin unrated.
</li>
<li>
Milt Hinton,
@@ -314,15 +331,15 @@ drums;
Lionel Hampton, vibraphone;
Cab Calloway, Joe Williams, vocal;
Buck Clayton, arrangements.
-Tunes include "Old Man Time", "Time After Time",
-"Sometimes I'm Happy",
-"A Hot Time in the Old Town Tonight",
-"Four or Five Times", "Now's the Time",
-"Time on My Hands", "This Time It's Us",
-and "Good Time Charlie".
-ADO &#x2605;&#x2605;&#x2605;,
+Tunes include “Old Man Time”, “Time After Time”,
+“Sometimes I’m Happy”,
+“A Hot Time in the Old Town Tonight”,
+“Four or Five Times”, “Now’s the Time”,
+“Time on My Hands”, “This Time It’s Us”,
+and “Good Time Charlie”.
+ADO ★★★,
<a href="https://www.allmusic.com/album/old-man-time-mw0000269353">AMG</a>
-&#x2605;&#x2605;&#x2605;&#x2605;&#x2BEA;, Penguin &#x2605;&#x2605;&#x2605;.
+★★★★⯪, Penguin ★★★.
</li>
<li>
Alan Broadbent, <em>Pacific Standard Time</em> (1995).
@@ -331,9 +348,9 @@ Alan Broadbent, piano;
Putter Smith, Bass;
Frank Gibson, Jr., drums.
The CD cover features an analemma for equation-of-time fans.
-ADO &#x2605;,
+ADO ★,
<a href="https://www.allmusic.com/album/pacific-standard-time-mw0000645433">AMG</a>
-&#x2605;&#x2605;&#x2605;&#x2605;, Penguin &#x2605;&#x2605;&#x2605;&#x2BEA;.
+★★★★, Penguin ★★★⯪.
</li>
<li>
Anthony Braxton/Richard Teitelbaum, <em>Silence/Time Zones</em> (1996).
@@ -343,88 +360,89 @@ contrebasse clarinet, miscellaneous instruments;
Leo Smith, trumpet and miscellaneous instruments;
Leroy Jenkins, violin and miscellaneous instruments;
Richard Teitelbaum, modular moog and micromoog synthesizer.
-ADO &#x2022;,
+ADO •,
<a href="https://www.allmusic.com/album/silence-time-zones-mw0000595735">AMG</a>
-&#x2605;&#x2605;&#x2605;&#x2605;.
+★★★★.
</li>
<li>
Charles Gayle, <em>Time Zones</em> (2006). Tompkins Square TSQ2839, 49:06.
Charles Gayle, piano.
-ADO &#x2605;,
+ADO ★,
<a href="https://www.allmusic.com/album/time-zones-mw0000349642">AMG</a>
-&#x2605;&#x2605;&#x2605;&#x2605;&#x2BEA;.
+★★★★⯪.
</li>
<li>
The Get Up Kids, <em>Eudora</em> (2001). Vagrant 357, 65:12.
-Includes the song "Central Standard Time."
+Includes the song “Central Standard Time”.
Thanks to Colin Bowern for this information.
<a href="https://www.allmusic.com/album/eudora-mw0000592063">AMG</a>
-&#x2605;&#x2605;&#x2BEA;.
+★★⯪.
</li>
<li>
-Coldplay, "Clocks" (2003).
+Coldplay, “Clocks” (2003).
Capitol 52608, 4:13.
Won the 2004 Record of the Year honor at the
Grammy Awards. Co-written and performed by Chris Martin,
great-great-grandson of <abbr>DST</abbr> inventor William Willett.
-The song's first line is "Lights go out and I can't be saved".
+The song’s first line is “Lights go out and I can’t be saved”.
</li>
<li>
-Jaime Guevara, "<a
-href="https://www.youtube.com/watch?v=ZfN4Fe_A50U">Qu&eacute;
-hora es</a>" (1993), 3:04.
-The song protested "Sixto Hour" in Ecuador
-(1992&ndash;3). Its lyrics include "Amanec&iacute;a en mitad de la noche, los
-guaguas iban a clase sin sol" ("It was dawning in the middle of the
-night, the buses went to class without sun").
+Jaime Guevara, “<a
+href="https://www.youtube.com/watch?v=ZfN4Fe_A50U">Qué
+hora es</a>” (1993), 3:04.
+The song protested “Sixto Hour” in Ecuador
+(1992–3). Its lyrics include “Amanecía en mitad de la noche, los
+guaguas iban a clase sin sol” (“It was dawning in the middle of the
+night, the buses went to class without sun”).
</li>
<li>
Irving Kahal and Harry Richman,
-"There Ought to be a Moonlight Saving Time" (1931).
+“There Ought to be a Moonlight Saving Time” (1931).
This musical standard was a No. 1 hit for Guy Lombardo
in 1931, and was also performed by Maurice Chevalier, Blossom Dearie
-and many others. The phrase "Moonlight saving time" also appears in
-the 1995 country song "Not Enough Hours in the Night" written by Aaron
+and many others. The phrase “Moonlight saving time” also appears in
+the 1995 country song “Not Enough Hours in the Night” written by Aaron
Barker, Kim Williams and Rob Harbin and performed by Doug
Supernaw.
</li>
<li>
The Microscopic Septet, <em>Lobster Leaps In</em> (2008).
Cuneiform 272, 73:05.
-Includes the song "Twilight Time Zone."
-ADO &#x2605;&#x2605;,
+Includes the song “Twilight Time Zone”.
+ADO ★★,
<a href="https://www.allmusic.com/album/lobster-leaps-in-mw0000794929">AMG</a>
-&#x2605;&#x2605;&#x2605;&#x2BEA;.
+★★★⯪.
</li>
<li>
-Bob Dylan, <em>The Times They Are a-Changin'</em> (1964).
+Bob Dylan, <em>The Times They Are a-Changin’</em> (1964).
Columbia CK-8905, 45:36.
-ADO &#x2605;&#x2BEA;,
+ADO ★⯪,
<a href="https://www.allmusic.com/album/the-times-they-a-changin-mw0000202344">AMG</a>
-&#x2605;&#x2605;&#x2605;&#x2605;&#x2BEA;.
-The title song is also available on "Bob Dylan's Greatest Hits" and "The Essential Bob Dylan."
+★★★★⯪.
+The title song is also available on “Bob Dylan’s Greatest Hits”
+and “The Essential Bob Dylan”.
</li>
<li>
Luciana Souza, <em>Tide</em> (2009). Universal Jazz France B0012688-02, 42:31.
-ADO &#x2605;&#x2605;&#x2BEA;,
+ADO ★★⯪,
<a href="https://www.allmusic.com/album/tide-mw0000815692">AMG</a>
-&#x2605;&#x2605;&#x2605;&#x2BEA;.
-Includes the song "Fire and Wood" with the lyric
-"The clocks were turned back you remember/Think it's still November."
+★★★⯪.
+Includes the song “Fire and Wood” with the lyric
+“The clocks were turned back you remember/Think it’s still November.”
</li>
<li>
-Ken Nordine, <em>You're Getting Better: The Word Jazz Dot Masters</em> (2005).
+Ken Nordine, <em>You’re Getting Better: The Word Jazz Dot Masters</em> (2005).
Geffen B0005171-02, 156:22.
-ADO &#x2605;,
+ADO ★,
<a href="https://www.allmusic.com/album/youre-getting-better-the-word-jazz-dot-masters-mw0000736197">AMG</a>
-&#x2605;&#x2605;&#x2605;&#x2605;&#x2BEA;.
-Includes the piece "What Time Is It"
-("He knew what time it was everywhere...that counted").
+★★★★⯪.
+Includes the piece “What Time Is It”
+(“He knew what time it was everywhere...that counted”).
</li>
<li>
Chicago, <em>Chicago Transit Authority</em> (1969). Columbia 64409, 1:16:20.
-<a href="https://www.allmusic.com/album/chicago-transit-authority-mw0000189364">AMG</a> &#x2605;&#x2605;&#x2605;&#x2605;.
-Includes the song "Does Anybody Really Know What Time It Is?".
+<a href="https://www.allmusic.com/album/chicago-transit-authority-mw0000189364">AMG</a> ★★★★.
+Includes the song “Does Anybody Really Know What Time It Is?”.
</li>
<li>
Emanuele Arciuli,
@@ -440,27 +458,27 @@ Unlike minimalism, it does not assume that the listener has plenty of time.
<ul>
<li>
The webcomic <em>xkcd</em> has the strips
-"<a href="https://xkcd.com/673/">The Sun</a>" (2009-12-09),
-"<a href="https://xkcd.com/1655/">Doomsday Clock</a>" (2016-03-14) and
-"<a href="https://xkcd.com/2549/">Edge Cake</a>" (2021-12-01),
+“<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/1799/">Bad Map Projection: Time Zones</a>"
+“<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/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),
-"<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),
-"<a href="https://xkcd.com/2594/">Consensus Time</a>" (2022-03-16),
-"<a href="https://xkcd.com/2846/">Daylight Saving Choice</a>" (2023-10-25),
-"<a href="https://xkcd.com/2854/">Date Line</a>" (2023-11-13),
-and "<a href="https://xkcd.com/2867/">DateTime</a>" (2023-12-13).
+“<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),
+“<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),
+“<a href="https://xkcd.com/2594/">Consensus Time</a>” (2022-03-16),
+“<a href="https://xkcd.com/2846/">Daylight Saving Choice</a>” (2023-10-25),
+“<a href="https://xkcd.com/2854/">Date Line</a>” (2023-11-13),
+and “<a href="https://xkcd.com/2867/">DateTime</a>” (2023-12-13).
The related book <em>What If?</em> has an entry
-"<a href="https://what-if.xkcd.com/26/">Leap Seconds</a>" (2012-12-31).
+“<a href="https://what-if.xkcd.com/26/">Leap Seconds</a>” (2012-12-31).
</li>
<li>
Pig kills time in <a
@@ -480,112 +498,116 @@ Caulfield proposes changing clocks just once a year in
(the same day)</a>.
</li>
<li>
-Peppermint Patty: "What if the world comes to an end tonight, Marcie?"
+Peppermint Patty: “What if the world comes to an end tonight, Marcie?”
<br>
-Marcie: "I promise there'll be a tomorrow, sir ... in fact,
-it's already tomorrow in Australia!"
+Marcie: “I promise there’ll be a tomorrow, sir ... in fact,
+it’s already tomorrow in Australia!”
<br>
-(Charles M. Schulz, <a href="https://www.gocomics.com/peanuts/1980/06/13"><em>Peanuts</em>, 1980-06-13</a>)
+(Charles M. Schulz,
+<a href="https://www.gocomics.com/peanuts/1980/06/13"><em>Peanuts</em>,
+1980-06-13</a>)
</li>
</ul>
<h2>Jokes</h2>
<ul>
<li>
The idea behind daylight saving time was first proposed as a joke by
-Benjamin Franklin. To enforce it, he suggested, "Every
+Benjamin Franklin. To enforce it, he suggested, “Every
morning, as soon as the sun rises, let all the bells in every church
be set ringing; and if that is not sufficient, let cannon be fired in
every street, to wake the sluggards effectually, and make them open
their eyes to see their true interest. All the difficulty will be in
the first two or three days: after which the reformation will be as
-natural and easy as the present irregularity; for, <em>ce n'est que le
-premier pas qui co&ucirc;te</em>."
-<a href="http://www.webexhibits.org/daylightsaving/franklin3.html">Franklin's
+natural and easy as the present irregularity; for, <em>ce n’est que le
+premier pas qui coûte</em>.”
+<a href="https://www.webexhibits.org/daylightsaving/franklin3.html">Franklin’s
joke</a> was first published on 1784-04-26 by the
<em>Journal de Paris</em> as <a
href="https://en.wikipedia.org/wiki/File:Franklin-Benjamin-Journal-de-Paris-1784.jpg">an
anonymous letter translated into French</a>.
</li>
<li>
-"We've been using the five-cent nickel in this country since 1492.
-Now that's pretty near 100 years, daylight saving."
+“We’ve been using the five-cent nickel in this country since 1492.
+Now that’s pretty near 100 years, daylight saving.”
(Groucho Marx as Captain Spaulding in <em>Animal Crackers</em>, 1930,
as noted by Will Fitzgerald)
</li>
<li>
BRADY. ...[Bishop Usher] determined that the Lord began the Creation
-on the 23rd of October in the Year 4,004 B.C. at &ndash; uh, 9 A.M.!
+on the 23rd of October in the Year 4,004 B.C. at – uh, 9 A.M.!
<br>
DRUMMOND. That Eastern Standard Time? (<em>Laughter.</em>) Or Rocky Mountain
-Time? (<em>More laughter.</em>) It wasn't daylight-saving time, was it? Because
-the Lord didn't make the sun until the fourth day!
+Time? (<em>More laughter.</em>) It wasn’t daylight-saving time, was it? Because
+the Lord didn’t make the sun until the fourth day!
<br>
(From the play <em>Inherit the Wind</em> by Jerome Lawrence and Robert E. Lee,
filmed in 1960 with Spencer Tracy as Drummond and Fredric March as
Brady, and several other times. Thanks to Mark Brader.)
</li>
<li>
-"Good news."
-"What did they do? Extend Daylight Saving Time year round?"
+“Good news.”
+“What did they do? Extend Daylight Saving Time year round?”
(Professional tanner George Hamilton, in dialog from a
May, 1999 episode of the syndicated television series <em>Baywatch</em>)
</li>
<li>
-"A fundamental belief held by Americans is that if you are on land, you
+“A fundamental belief held by Americans is that if you are on land, you
cannot be killed by a fish...So most Americans remain on land, believing
-they're safe. Unfortunately, this belief &ndash; like so many myths, such as that
-there's a reason for 'Daylight Saving Time' &ndash; is false."
+they’re safe. Unfortunately, this belief – like so many myths, such as that
+there’s a reason for ‘Daylight Saving Time’ – is false.”
(Dave Barry column, 2000-07-02)
</li>
<li>
-"I once had sex for an hour and five minutes, but that was on the day
-when you turn the clocks ahead."
+“I once had sex for an hour and five minutes, but that was on the day
+when you turn the clocks ahead.”
(Garry Shandling, 52nd Annual Emmys, 2000-09-10)
</li>
<li>
-"Would it impress you if I told you I invented Daylight Savings Time?"
-("Sahjhan" to "Lilah" in dialog from the "Loyalty" episode of <em>Angel</em>,
+“Would it impress you if I told you I invented Daylight Savings Time?”
+(“Sahjhan” to “Lilah” in dialog from the “Loyalty” episode of <em>Angel</em>,
originally aired 2002-02-25)
</li>
<li>
-"I thought you said Tulsa was a three-hour flight."
-"Well, you're forgetting about the time difference."
-("Joey" and "Chandler" in dialog from the episode of <em>Friends</em>
-entitled "The One With Rachel's Phone Number," originally aired 2002-12-05)
+“I thought you said Tulsa was a three-hour flight.”
+“Well, you’re forgetting about the time difference.”
+(“Joey” and “Chandler” in dialog from the
+episode of <em>Friends</em> entitled “The One With
+Rachel’s Phone Number”, originally aired 2002-12-05)
</li>
<li>
-"Is that a pertinent fact,
-or are you just trying to dazzle me with your command of time zones?"
-(Kelsey Grammer as "Frasier Crane" to "Roz" from the episode of <em>Frasier</em>
-entitled "The Kid," originally aired 1997-11-04)
+“Is that a pertinent fact,
+or are you just trying to dazzle me with your command of time zones?”
+(Kelsey Grammer as “Frasier Crane” to “Roz”
+from the episode of <em>Frasier</em> entitled “The Kid”,
+originally aired 1997-11-04)
</li>
<li>
-"I put myself and my staff through this crazy, huge ordeal, all because
+“I put myself and my staff through this crazy, huge ordeal, all because
I refused to go on at midnight, okay? And so I work, you know, and
then I get this job at eleven, supposed to be a big deal. Then
-yesterday daylight [saving] time ended. Right now it's basically
-midnight." (Conan O'Brien on the 2010-11-08 premiere of <em>Conan</em>)
+yesterday daylight [saving] time ended. Right now it’s basically midnight.”
+(Conan O’Brien on the 2010-11-08 premiere of <em>Conan</em>)
</li>
<li>
-"The best method, I told folks, was to hang a large clock high on a
+“The best method, I told folks, was to hang a large clock high on a
barn wall where all the cows could see it. If you have Holsteins, you
-will need to use an analog clock." (Jerry Nelson, <a
-href="http://www.agriculture.com/family/farm-humor/how-to-adjust-dairy-cows-to-daylight-savings-time">How
-to adjust dairy cows to daylight saving time</a>", <em>Successful Farming</em>,
-2017-10-09)
+will need to use an analog clock.” (Jerry Nelson, “<a
+href="https://www.agriculture.com/family/farm-humor/how-to-adjust-dairy-cows-to-daylight-savings-time">How
+to adjust dairy cows to daylight saving time</a>”,
+<em>Successful Farming</em>, 2017-10-09)
</li>
<li>
-"And now, driving to California, I find that I must enter a password
+“And now, driving to California, I find that I must enter a password
in order to change the time zone on my laptop clock. Evidently,
-someone is out to mess up my schedule and my clock must be secured."
+someone is out to mess up my schedule and my clock must be secured.”
(Garrison Keillor,
-"<a href="http://www.garrisonkeillor.com/weve-never-been-here-before/">We've
-never been here before</a>", 2017-08-22)
+“<a href="https://www.garrisonkeillor.com/weve-never-been-here-before/">We’ve
+never been here before</a>”, 2017-08-22)
</li>
<li>
-"Well, in my time zone that's all the time I have,
-but maybe in your time zone I haven't finished yet. So stay tuned!"
-(Goldie Hawn, <em>Rowan &amp; Martin's Laugh-In</em> No. 65, 1970-03-09)
+“Well, in my time zone that’s all the time I have,
+but maybe in your time zone I haven’t finished yet. So stay tuned!”
+(Goldie Hawn, <em>Rowan &amp; Martin’s Laugh-In</em> No. 65, 1970-03-09)
</li>
</ul>
<h2>See also</h2>
@@ -593,13 +615,16 @@ but maybe in your time zone I haven't finished yet. So stay tuned!"
<li><a href="tz-link.html">Time Zone and Daylight Saving
Time Data</a></li>
</ul>
+
+<footer>
<hr>
-<address>
This web page is in the public domain, so clarified as of
2009-05-17 by Arthur David Olson.
<br>
Please send corrections to this web page to the
<a href="mailto:tz@iana.org">time zone mailing list</a>.
-</address>
+The mailing list and its archives are public,
+so please do not send confidential information.
+</footer>
</body>
</html>
diff --git a/contrib/tzcode/tz-how-to.html b/contrib/tzcode/tz-how-to.html
index 9e438f93092a..9f4f2284c7b4 100644
--- a/contrib/tzcode/tz-how-to.html
+++ b/contrib/tzcode/tz-how-to.html
@@ -3,14 +3,15 @@
<head>
<title>How to Read the tz Database</title>
<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
-pre {margin-left: 2em; white-space: pre-wrap;}
-pre.td {margin-left: 0;}
+pre {margin-left: 1.3rem; overflow: auto;}
td {text-align: center;}
table {border: 1px outset;}
th, td {border: 1px inset;}
table.rule {border: none; margin: auto;}
td.footnote {text-align: left;}
+ul {padding-left: 1.3rem;}
</style>
</head>
<body>
@@ -23,31 +24,22 @@ times of day from the <a href="tz-link.html">tz database</a>
source files. It might be helpful, but not absolutely necessary,
for the reader to have already downloaded the
latest release of the database and become familiar with the basic layout
-of the data files. The format is explained in the &ldquo;man
-page&rdquo; for the zic compiler, <code>zic.8.txt</code>, in
+of the data files. The format is explained in the “man page”
+for the zic compiler, <code>zic.8.txt</code>, in
the <code>code</code> subdirectory.
Although this guide covers many of the common cases, it is not a
complete summary of what zic accepts; the man page is the
authoritative reference.</p>
-<p>We&rsquo;ll begin by talking about the rules for changing between standard
-and daylight saving time since we&rsquo;ll need that information when we talk
+<p>We’ll begin by talking about the rules for changing between standard
+and daylight saving time since we’ll need that information when we talk
about the zones.</p>
-<p>First, let&rsquo;s consider the special daylight saving time rules
+<p>First, let’s consider the special daylight saving time rules
for Chicago (from the <code>northamerica</code> file in
the <code>data</code> subdirectory):</p>
-<table>
-<tr>
- <th colspan="6">From the Source File</th>
-</tr>
-<tr>
- <td colspan="6">
- <table class="rule">
- <tr><td style="border:none;text-align:left">
-<pre class="td">
-#Rule NAME FROM TO - IN ON AT SAVE LETTER
+<pre>#Rule NAME FROM TO - IN ON AT SAVE LETTER
Rule Chicago 1920 only - Jun 13 2:00 1:00 D
Rule Chicago 1920 1921 - Oct lastSun 2:00 0 S
Rule Chicago 1921 only - Mar lastSun 2:00 1:00 D
@@ -55,8 +47,7 @@ Rule Chicago 1922 1966 - Apr lastSun 2:00 1:00 D
Rule Chicago 1922 1954 - Sep lastSun 2:00 0 S
Rule Chicago 1955 1966 - Oct lastSun 2:00 0 S
</pre>
- </td></tr></table></td>
-</tr>
+<table>
<tr>
<th colspan="6">Reformatted a Bit</th>
</tr>
@@ -107,7 +98,7 @@ first and last calendar years defining a contiguous range over which a specific
Rule line is to apply. The keyword <code>only</code> can be used in the
<code>TO</code> field to repeat the value of the <code>FROM</code> field in the
event that a rule should only apply to a single year. Often, the keyword
-<code>max</code> is used to extend a rule&rsquo;s application into the
+<code>max</code> is used to extend a rule’s application into the
indefinite future; it is a platform-agnostic stand-in for the largest
representable year.
@@ -117,28 +108,28 @@ Prior to the 2020b release, it was called the <code>TYPE</code> field, though
it had not been used in the main data since the 2000e release.
An obsolescent supplementary file used the
field as a proof-of-concept to allow <code>zic</code> to apply a given Rule
-line only to certain &ldquo;types&rdquo; of years within the specified range as
+line only to certain “types” of years within the specified range as
dictated by the output of a separate script, such as: only years which would
-have a US presidential election, or only years which wouldn&rsquo;t.
+have a US presidential election, or only years which wouldn’t.
<p>The <code>SAVE</code> column contains the local (wall clock) offset from
local standard time.
This is usually either zero for standard time or one hour for daylight
-saving time; but there&rsquo;s no reason, in principle, why it can&rsquo;t
+saving time; but there’s no reason, in principle, why it can’t
take on other values.
<p>The <code>LETTER</code> (sometimes called <code>LETTER/S</code>)
column can contain a variable
-part of the usual abbreviation of the time zone&rsquo;s name, or it can just
-be a hyphen if there&rsquo;s no variable part. For example, the abbreviation
-used in the central time zone will be either &ldquo;CST&rdquo; or
-&ldquo;CDT&rdquo;. The variable part is &lsquo;S&rsquo; or &lsquo;D&rsquo;;
-and, sure enough, that&rsquo;s just what we find in
+part of the usual abbreviation of the time zone’s name, or it can just
+be a hyphen if there’s no variable part. For example, the abbreviation
+used in the central time zone will be either “CST” or “CDT”.
+The variable part is ‘S’ or ‘D’;
+and, sure enough, that’s just what we find in
the <code>LETTER</code> column
in the <code>Chicago</code> rules. More about this when we talk about
-&ldquo;Zone&rdquo; lines.
+“Zone” lines.
-<p>One important thing to notice is that &ldquo;Rule&rdquo; lines
+<p>One important thing to notice is that “Rule” lines
want at once to be both <i>transitions</i> and <i>steady states</i>:
<ul>
<li>On the one hand, they represent transitions between standard and
@@ -158,18 +149,9 @@ years. Similarly, the rule for changing to daylight saving time was
the same from 1922 to 1966; but the rule for returning to standard
time changed in 1955. Got it?</p>
-<p>OK, now for the somewhat more interesting &ldquo;US&rdquo; rules:</p>
+<p>OK, now for the somewhat more interesting “US” rules:</p>
-<table>
-<tr>
- <th colspan="6">From the Source File</th>
-</tr>
-<tr>
- <td colspan="6">
- <table class="rule">
- <tr><td style="border:none;text-align:left">
-<pre class="td">
-#Rule NAME FROM TO - IN ON AT SAVE LETTER/S
+<pre>#Rule NAME FROM TO - IN ON AT SAVE LETTER/S
Rule US 1918 1919 - Mar lastSun 2:00 1:00 D
Rule US 1918 1919 - Oct lastSun 2:00 0 S
Rule US 1942 only - Feb 9 2:00 1:00 W # War
@@ -184,8 +166,7 @@ Rule US 1987 2006 - Apr Sun&gt;=1 2:00 1:00 D
Rule US 2007 max - Mar Sun&gt;=8 2:00 1:00 D
Rule US 2007 max - Nov Sun&gt;=1 2:00 0 S
</pre>
- </td></tr></table></td>
-</tr>
+<table>
<tr>
<th colspan="6">Reformatted a Bit</th>
</tr>
@@ -211,15 +192,15 @@ Rule US 2007 max - Nov Sun&gt;=1 2:00 0 S
<tr>
<td colspan="2">1942 only</td>
<td colspan="2">February 9<small><sup>th</sup></small></td>
- <td>go to &ldquo;war time&rdquo;</td>
+ <td>go to “war time”</td>
</tr>
<tr>
<td colspan="2" rowspan="2">1945 only</td>
<td colspan="2">August 14<small><sup>th</sup></small></td>
<td>23:00 <a href="https://en.wikipedia.org/wiki/Universal_Time">UT</a></td>
<td>
- rename &ldquo;war time&rdquo; to &ldquo;peace<br>time;&rdquo;
- clocks don&rsquo;t change
+ rename “war time” to “peace<br>time;”
+ clocks don’t change
</td>
</tr>
<tr>
@@ -272,33 +253,33 @@ Rule US 2007 max - Nov Sun&gt;=1 2:00 0 S
<p>First, the time that something happens (in the <code>AT</code>
column) is not necessarily the local (wall clock) time. The time can be
-suffixed with &lsquo;s&rsquo; (for &ldquo;standard&rdquo;) to mean
+suffixed with ‘s’ (for “standard”) to mean
local standard time, different from local (wall clock) time when observing
-daylight saving time; or it can be suffixed with &lsquo;g&rsquo;,
-&lsquo;u&rsquo;, or &lsquo;z&rsquo;, all three of which mean the
+daylight saving time; or it can be suffixed with ‘g’,
+‘u’, or ‘z’, all three of which mean the
standard time at the
<a href="https://en.wikipedia.org/wiki/Prime_Meridian">prime meridian</a>.
-&lsquo;g&rsquo; stands for &ldquo;<a
-href="https://en.wikipedia.org/wiki/Greenwich_Mean_Time">GMT</a>&rdquo;;
-&lsquo;u&rsquo; stands for &ldquo;<a
-href="https://en.wikipedia.org/wiki/Universal_Time">UT</a>&rdquo; or &ldquo;<a
-href="https://en.wikipedia.org/wiki/Coordinated_Universal_Time">UTC</a>&rdquo;
-(whichever was official at the time); &lsquo;z&rsquo; stands for the
+‘g’ stands for “<a
+href="https://en.wikipedia.org/wiki/Greenwich_Mean_Time">GMT</a>”;
+‘u’ stands for “<a
+href="https://en.wikipedia.org/wiki/Universal_Time">UT</a>” or “<a
+href="https://en.wikipedia.org/wiki/Coordinated_Universal_Time">UTC</a>”
+(whichever was official at the time); ‘z’ stands for the
<a href="https://en.wikipedia.org/wiki/Nautical_time">nautical time zone</a>
-Z (a.k.a. &ldquo;Zulu&rdquo; which, in turn, stands for &lsquo;Z&rsquo;).
-The time can also be suffixed with &lsquo;w&rsquo; meaning local (wall
-clock) time; but it usually isn&rsquo;t because that&rsquo;s the
+Z (a.k.a. “Zulu” which, in turn, stands for ‘Z’).
+The time can also be suffixed with ‘w’ meaning local (wall
+clock) time; but it usually isn’t because that’s the
default.</p>
<p>Second, the day in the <code>ON</code> column, in addition to
-&ldquo;<code>lastSun</code>&rdquo; or a particular day of the month,
-can have the form, &ldquo;<code>Sun&gt;=</code><i>x</i>&rdquo; or
-&ldquo;<code>Sun&lt;=</code><i>x</i>,&rdquo; where <i>x</i> is a day
-of the month. For example, &ldquo;<code>Sun&gt;=8</code>&rdquo; means
-&ldquo;the first Sunday on or after the eighth of the month,&rdquo; in
+“<code>lastSun</code>” or a particular day of the month,
+can have the form, “<code>Sun&gt;=</code><i>x</i>” or
+“<code>Sun&lt;=</code><i>x</i>,” where <i>x</i> is a day
+of the month. For example, “<code>Sun&gt;=8</code>” means
+“the first Sunday on or after the eighth of the month,” in
other words, the second Sunday of the month. Furthermore, although
-there are no examples above, the weekday needn&rsquo;t be
-&ldquo;<code>Sun</code>&rdquo; in either form, but can be the usual
+there are no examples above, the weekday needn’t be
+“<code>Sun</code>” in either form, but can be the usual
three-character English abbreviation for any day of the week.</p>
<p>And the US rules give us more examples of a couple of things
@@ -317,8 +298,8 @@ state or other more local rule).</li>
<li>The <code>SAVE</code> and <code>LETTER</code> columns
contain <i>steady state</i>, not transitions. Consider, for example,
-the transition from &ldquo;war time&rdquo; to &ldquo;peace time&rdquo;
-that happened on August 14, 1945. The &ldquo;1:00&rdquo; in
+the transition from “war time” to “peace time”
+that happened on August 14, 1945. The “1:00” in
the <code>SAVE</code> column is <i>not</i> an instruction to advance
the clock an hour. It means that clocks should <i>be</i> one hour
ahead of standard time, which they already are because of the previous
@@ -326,17 +307,9 @@ rule, so there should be no change.</li>
</ul>
-<p>OK, now let&rsquo;s look at a Zone record:</p>
+<p>OK, now let’s look at a Zone record:</p>
-<table>
-<tr>
- <th colspan="5">From the Source File</th>
-</tr>
-<tr>
- <td colspan="5">
- <table class="rule">
- <tr><td style="border:none;text-align:left">
-<pre class="td">
+<pre>
#Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24
-6:00 US C%sT 1920
@@ -347,8 +320,7 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24
-6:00 Chicago C%sT 1967
-6:00 US C%sT
</pre>
- </td></tr></table></td>
-</tr>
+<table>
<tr>
<th colspan="5">Columns Renamed</th>
</tr>
@@ -365,14 +337,14 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24
<th>Time</th>
</tr>
<tr>
- <td>&minus;5:50:36</td>
+ <td>−5:50:36</td>
<td>not observed</td>
<td>LMT</td>
<td>1883-11-18</td>
<td>12:09:24</td>
</tr>
<tr>
- <td rowspan="2">&minus;6:00:00</td>
+ <td rowspan="2">−6:00:00</td>
<td>US rules</td>
<td rowspan="2">CST or CDT</td>
<td>1920-01-01</td>
@@ -384,13 +356,13 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24
<td rowspan="2">02:00:00</td>
</tr>
<tr>
- <td>&minus;5:00:00</td>
+ <td>−5:00:00</td>
<td>not observed</td>
<td>EST</td>
<td>1936-11-15</td>
</tr>
<tr>
- <td rowspan="4">&minus;6:00:00</td>
+ <td rowspan="4">−6:00:00</td>
<td>Chicago rules</td>
<td>CST or CDT</td>
<td>1942-01-01</td>
@@ -408,7 +380,7 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24
</tr>
<tr>
<td>US rules</td>
- <td colspan="2">&mdash;</td>
+ <td colspan="2">–</td>
</tr>
</table>
@@ -417,24 +389,24 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24
<p>First, and somewhat trivially, whereas Rules are considered to
contain one or more records, a Zone is considered to be a single
record with zero or more <i>continuation lines</i>. Thus, the keyword,
-&ldquo;<code>Zone</code>,&rdquo; and the zone name are not
+“<code>Zone</code>,” and the zone name are not
repeated. The last line is the one without anything in
the <code>[UNTIL]</code> column.</p>
<p>Second, and more fundamentally, each line of a Zone represents a
steady state, not a transition between states. The state exists from
-the date and time in the previous line&rsquo;s <code>[UNTIL]</code>
+the date and time in the previous line’s <code>[UNTIL]</code>
column up to the date and time in the current
-line&rsquo;s <code>[UNTIL]</code> column. In other words, the date and
+line’s <code>[UNTIL]</code> column. In other words, the date and
time in the <code>[UNTIL]</code> column is the instant that separates
this state from the next. Where that would be ambiguous because
-we&rsquo;re setting our clocks back, the <code>[UNTIL]</code> column
+we’re setting our clocks back, the <code>[UNTIL]</code> column
specifies the first occurrence of the instant. The state specified by
the last line, the one without anything in the <code>[UNTIL]</code>
column, continues to the present.</p>
<p>The first line typically specifies the mean solar time observed
-before the introduction of standard time. Since there&rsquo;s no line before
+before the introduction of standard time. Since there’s no line before
that, it has no beginning. <code>8-) </code> For some places near the <a
href="https://en.wikipedia.org/wiki/International_Date_Line">International
Date Line</a>, the first <i>two</i> lines will show solar times
@@ -453,16 +425,16 @@ Alaska was then 24 hours earlier than it had
been. <code>&lt;aside&gt;</code>(6 October in the Julian calendar,
which Russia was still using then for religious reasons, was followed
by <i>a second instance of the same day with a different name</i>, 18
-October in the Gregorian calendar. Isn&rsquo;t civil time
+October in the Gregorian calendar. Isn’t civil time
wonderful? <code>8-)</code>)<code>&lt;/aside&gt;</code></p>
-<p>The abbreviation, &ldquo;LMT&rdquo; stands for &ldquo;local mean
-time&rdquo;, which is an invention of
+<p>The abbreviation, “LMT” stands for “local mean
+time”, which is an invention of
the <a href="https://en.wikipedia.org/wiki/Tz_database">tz
database</a> and was probably never actually used during the
period. Furthermore, the value is almost certainly wrong except in the
archetypal place after which the zone is named. (The tz database
-usually doesn&rsquo;t provide a separate Zone record for places where
+usually doesn’t provide a separate Zone record for places where
nothing significant happened after 1970.)</p>
<p>The <code>RULES</code> column tells us whether daylight saving time is being observed:
@@ -470,7 +442,7 @@ nothing significant happened after 1970.)</p>
<li>A hyphen, a kind of null value, means that we have not set our
clocks ahead of standard time.</li>
-<li>An amount of time (usually but not necessarily &ldquo;1:00&rdquo;
+<li>An amount of time (usually but not necessarily “1:00”
meaning one hour) means that we have set our clocks ahead by that
amount.</li>
@@ -488,10 +460,10 @@ Zone Pacific/Honolulu ... 1933 Apr 30 2:00
</pre>
<p>Hawaii tried daylight saving time for three weeks in 1933 and
-decided they didn&rsquo;t like it. <code>8-) </code>Note that
+decided they didn’t like it. <code>8-) </code>Note that
the <code>STDOFF</code> column always contains the standard time
-offset, so the local (wall clock) time during this period was GMT &minus;
-10:30 + 1:00 = GMT &minus; 9:30.</p>
+offset, so the local (wall clock) time during this period was GMT −
+10:30 + 1:00 = GMT − 9:30.</p>
<p>The <code>FORMAT</code> column specifies the usual abbreviation of
the time zone name. It should have one of four forms:</p>
@@ -499,24 +471,24 @@ the time zone name. It should have one of four forms:</p>
<li>a time zone abbreviation that is a string of three or more
characters that are either ASCII alphanumerics,
-&ldquo;<code>+</code>&rdquo;, or &ldquo;<code>-</code>&rdquo;</li>
+“<code>+</code>”, or “<code>-</code>”</li>
-<li>the string &ldquo;%z&rdquo;, in which case the
-&ldquo;<code>%z</code>&rdquo; will be replaced by a numeric time zone
+<li>the string “%z”, in which case the
+“<code>%z</code>” will be replaced by a numeric time zone
abbreviation</li>
<li>a pair of time zone abbreviations separated by a slash
-(&lsquo;<code>/</code>&rsquo;), in which case the first string is the
+(‘<code>/</code>’), in which case the first string is the
abbreviation for the standard time name and the second string is the
abbreviation for the daylight saving time name</li>
-<li>a string containing &ldquo;<code>%s</code>&rdquo;, in which case
-the &ldquo;<code>%s</code>&rdquo; will be replaced by the text in the
-appropriate Rule&rsquo;s <code>LETTER</code> column, and the resulting
+<li>a string containing “<code>%s</code>”, in which case
+the “<code>%s</code>” will be replaced by the text in the
+appropriate Rule’s <code>LETTER</code> column, and the resulting
string should be a time zone abbreviation</li>
</ul>
-<p>The last two make sense only if there&rsquo;s a named rule in effect.</p>
+<p>The last two make sense only if there’s a named rule in effect.</p>
<p>An example of a slash is:</p>
<pre>
@@ -552,9 +524,9 @@ 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
+“HST” for “Hawaii standard time” even though the
<a href="https://www.law.cornell.edu/uscode/text/15/263">legal</a>
-name for that time zone is &ldquo;Hawaii-Aleutian standard time.&rdquo;
+name for that time zone is “Hawaii–Aleutian standard time”.
This author has read that there are also some places in Australia where
popular time zone names differ from the legal ones.
@@ -562,10 +534,10 @@ popular time zone names differ from the legal ones.
href="https://en.wikipedia.org/wiki/Internationalization_and_localization">localize</a>
the abbreviations. They are intended to be the values returned through the
<code>"%Z"</code> format specifier to
-<a href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a>&rsquo;s
-<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/strftime.html"><code>strftime</code></a>
+<a href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a>’s
+<a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/strftime.html"><code>strftime</code></a>
function in the
-<a href="https://kirste.userpage.fu-berlin.de/chemnet/use/info/libc/libc_19.html#SEC324">&ldquo;C&rdquo; locale</a>.
+<a href="https://kirste.userpage.fu-berlin.de/chemnet/use/info/libc/libc_19.html#SEC324">“C” locale</a>.
<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
@@ -574,33 +546,16 @@ zone while uninhabited, where the offset is zero but in some sense
the true offset is undefined.
</ul>
-<p>As a final example, here&rsquo;s the complete history for Hawaii:</p>
+<p>As a final example, here’s the complete history for Hawaii:</p>
-<table>
-<tr>
- <th colspan="6">Relevant Excerpts from the US Rules</th>
-</tr>
-<tr>
- <td colspan="6">
- <table class="rule">
- <tr><td style="border:none;text-align:left">
-<pre class="td">
+<pre># Relevant Excerpts from the US Rules
#Rule NAME FROM TO - IN ON AT SAVE LETTER/S
Rule US 1918 1919 - Oct lastSun 2:00 0 S
Rule US 1942 only - Feb 9 2:00 1:00 W # War
Rule US 1945 only - Aug 14 23:00u 1:00 P # Peace
Rule US 1945 only - Sep lastSun 2:00 0 S
-</pre>
- </td></tr></table></td>
-</tr>
-<tr>
- <th colspan="6">The Zone Record</th>
-</tr>
-<tr>
- <td colspan="6">
- <table class="rule">
- <tr><td style="border:none;text-align:left">
-<pre class="td">
+
+# The Zone Record
#Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00
-10:30 - HST 1933 Apr 30 2:00
@@ -608,8 +563,7 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00
-10:30 US H%sT 1947 Jun 8 2:00
-10:00 - HST
</pre>
- </td></tr></table></td>
-</tr>
+<table>
<tr>
<th colspan="6">What We Infer</th>
</tr>
@@ -626,15 +580,15 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00
<th>Time</th>
</tr>
<tr>
- <td>&minus;10:31:26</td>
- <td>&mdash;</td>
+ <td>−10:31:26</td>
+ <td>–</td>
<td>LMT</td>
<td>local mean time</td>
<td>1896-01-13</td>
<td>12:00</td>
</tr>
<tr>
- <td>&minus;10:30</td>
+ <td>−10:30</td>
<td>+0:01:26</td>
<td>HST</td>
<td>Hawaii standard time</td>
@@ -642,7 +596,7 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00
<td>02:00</td>
</tr>
<tr>
- <td>&minus;9:30</td>
+ <td>−9:30</td>
<td>+1:00</td>
<td>HDT</td>
<td>Hawaii daylight time</td>
@@ -650,15 +604,15 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00
<td>12:00</td>
</tr>
<tr>
- <td>&minus;10:30&sup1;</td>
- <td>&minus;1:00&sup1;</td>
+ <td>−10:30&sup1;</td>
+ <td>−1:00&sup1;</td>
<td>HST&sup1;</td>
<td>Hawaii standard time</td>
<td>1942-02-09</td>
<td>02:00</td>
</tr>
<tr>
- <td rowspan="2">&minus;9:30</td>
+ <td rowspan="2">−9:30</td>
<td>+1:00</td>
<td>HWT</td>
<td>Hawaii war time</td>
@@ -673,34 +627,34 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00
<td rowspan="2">02:00</td>
</tr>
<tr>
- <td>&minus;10:30</td>
- <td>&minus;1:00</td>
+ <td>−10:30</td>
+ <td>−1:00</td>
<td rowspan="2">HST</td>
<td rowspan="2">Hawaii standard time</td>
<td>1947-06-08</td>
</tr>
<tr>
- <td>&minus;10:00&sup3;</td>
+ <td>−10:00&sup3;</td>
<td>+0:30&sup3;</td>
- <td colspan="2">&mdash;</td>
+ <td colspan="2">–</td>
</tr>
<tr>
<td colspan="6" class="footnote">
- &sup1;Switching to US rules&hellip;most recent transition (in 1919) was to standard time
+ &sup1;Switching to US rules...most recent transition (in 1919) was to standard time
</td>
</tr>
<tr>
<td colspan="6" class="footnote">
&sup2;23:00 <a href="https://en.wikipedia.org/wiki/Universal_Time">UT</a>
- + (&minus;9:30) = 13:30 local
+ + (−9:30) = 13:30 local
</td>
</tr>
<tr>
<td colspan="6" class="footnote">
- &sup3;Since <a href="https://en.wikipedia.org/wiki/ISO_8601">1947&ndash;06&ndash;08T12:30Z</a>,
+ &sup3;Since <a href="https://en.wikipedia.org/wiki/ISO_8601">1947-06-08T12:30Z</a>,
the civil time in Hawaii has been
<a href="https://en.wikipedia.org/wiki/Universal_Time">UT</a>/<a href="https://en.wikipedia.org/wiki/Coordinated_Universal_Time">UTC</a>
- &minus; 10:00 year-round.
+ −10:00 year-round.
</td>
</tr>
</table>
diff --git a/contrib/tzcode/tz-link.html b/contrib/tzcode/tz-link.html
index ad2cc972a4f9..5f1989f014b3 100644
--- a/contrib/tzcode/tz-link.html
+++ b/contrib/tzcode/tz-link.html
@@ -3,8 +3,11 @@
<head>
<title>Time zone and daylight saving time data</title>
<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
-pre {margin-left: 2em; white-space: pre-wrap;}
+dd {margin-left: 1.3rem;}
+pre {margin-left: 1.3rem; overflow: auto;}
+ul {padding-left: 1.3rem;}
</style>
</head>
<body>
@@ -18,7 +21,6 @@ histories and planned futures are often recorded only fitfully. Here
is a summary of attempts to organize and record relevant data in this
area.
</p>
- <h3>Outline</h3>
<nav>
<ul>
<li>The <code><abbr>tz</abbr></code> database product and process
@@ -73,7 +75,7 @@ This database (known as <code><abbr>tz</abbr></code>,
is used by several implementations,
including
<a href="https://www.gnu.org/software/libc/">the
-<abbr title="GNU's Not Unix">GNU</abbr>
+<abbr title="GNU’s Not Unix">GNU</abbr>
C Library</a> (used in
<a href="https://en.wikipedia.org/wiki/Linux"><abbr>GNU</abbr>/Linux</a>),
<a href="https://www.android.com">Android</a>,
@@ -84,21 +86,21 @@ title="Berkeley Software Distribution">BSD</abbr></a>,
<a href="https://www.chromium.org/chromium-os/">ChromiumOS</a>,
<a href="https://cygwin.com">Cygwin</a>,
<a href="https://mariadb.org">MariaDB</a>,
-<a href="https://en.wikipedia.org/wiki/MINIX">MINIX</a>,
<a href="https://musl.libc.org">musl libc</a>,
<a href="https://www.mysql.com">MySQL</a>,
<a href="https://en.wikipedia.org/wiki/WebOS"><abbr
title="Web Operating System">webOS</abbr></a>,
<a href="https://en.wikipedia.org/wiki/IBM_AIX"><abbr
title="Advanced Interactive eXecutive">AIX</abbr></a>,
-<a href="https://www.apple.com/ios"><abbr
+<a href="https://www.apple.com/os/ios/"><abbr
title="iPhone OS">iOS</abbr></a>,
-<a href="https://www.apple.com/macos">macOS</a>,
+<a href="https://www.apple.com/os/macos/">macOS</a>,
<a href="https://www.microsoft.com/en-us/windows">Microsoft Windows</a>,
-<a href="https://www.vmssoftware.com">Open<abbr
+<a href="https://vmssoftware.com">Open<abbr
title="Virtual Memory System">VMS</abbr></a>,
-<a href="https://www.oracle.com/database/">Oracle Database</a>, and
-<a href="https://www.oracle.com/solaris">Oracle Solaris</a>.</p>
+<a href="https://www.oracle.com/database/">Oracle Database</a>,
+<a href="https://www.oracle.com/solaris/solaris11/">Oracle Solaris</a>,
+and <a href="https://qnx.software/en">QNX</a>.</p>
<p>
Each main entry in the database represents a <dfn>timezone</dfn>
for a set of civil-time clocks that have all agreed since 1970.
@@ -117,7 +119,7 @@ To use the database on a <a
href="https://en.wikipedia.org/wiki/POSIX"><abbr
title="Portable Operating System Interface">POSIX</abbr>.1-2024</a>
implementation set the <code><abbr>TZ</abbr></code>
-environment variable to the location's full name,
+environment variable to the location’s full name,
e.g., <code><abbr>TZ</abbr>="America/New_York"</code>.</p>
<p>
Associated with each timezone is a history of offsets from
@@ -138,7 +140,7 @@ for Eastern Standard Time in the <abbr>US</abbr>.</p>
<p>
The following <a
href="https://en.wikipedia.org/wiki/Unix_shell">shell</a> commands download
-the latest release's two
+the latest release’s two
<a href="https://en.wikipedia.org/wiki/Tar_(computing)">tarballs</a>
to a <abbr>GNU</abbr>/Linux or similar host.</p>
<pre><code>mkdir tzdb
@@ -169,16 +171,19 @@ lower-case letter (<samp>a</samp> through <samp>z</samp>,
then <samp>za</samp> through <samp>zz</samp>, then <samp>zza</samp>
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
+<a href="https://pubs.opengroup.org/onlinepubs/9799919799/utilities/pax.html#tag_20_94_13_06">POSIX
ustar interchange format</a>, compressed as described above;
older releases use a nearly compatible format.
Since version 2016h, each release has contained a text file named
-"<code>version</code>" 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>
+“<code>version</code>” whose first (and currently only) line is the version.
+<a href="https://ftp.iana.org/tz/releases/">Older archived releases are
+available</a> via
+<a href="https://en.wikipedia.org/wiki/HTTPS"><abbr
+title="Hypertext Transfer Protocol Secure">HTTPS</abbr></a>,
+<a href="https://en.wikipedia.org/wiki/Rsync"><abbr
+title="remote sync">rsync</abbr></a>, and
+<a href="https://en.wikipedia.org/wiki/FTP"><abbr
+title="File Transfer Protocol">FTP</abbr></a>.
<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>
@@ -194,7 +199,7 @@ After obtaining the code and data files, see the
The code lets you compile the <code><abbr>tz</abbr></code> source files into
machine-readable binary files, one for each location. The binary files
are in a special format specified by
-<a href="https://www.rfc-editor.org/rfc/9636">The
+<a href="https://www.rfc-editor.org/rfc/rfc9636">The
Time Zone Information Format (<abbr>TZif</abbr>)</a>
(Internet <abbr title="Request For Comments">RFC</abbr> 9636).
The code also lets
@@ -208,9 +213,12 @@ location.</p>
The <code><abbr>tz</abbr></code> code and data
are by no means authoritative. If you find errors, please
email changes to <a href="mailto:tz@iana.org"><code>tz@iana.org</code></a>,
-the time zone mailing list. See
+the time zone mailing list.
+The mailing list and its archives are public,
+so please do not send confidential information.
+See
<a href="https://lists.iana.org/postorius/lists/tz.iana.org/">the mailing
-list's main page</a> to subscribe or to browse its archive of old messages.
+list’s main page</a> to subscribe or to browse its archive of old messages.
<a href="https://tzdata-meta.timtimeonline.com">Metadata for mailing list
discussions</a> and corresponding data changes can be
generated <a href="https://github.com/timparenti/tzdata-meta">automatically</a>.
@@ -228,7 +236,7 @@ data yourself. System-specific instructions for installing the
latest <code><abbr>tz</abbr></code> data have also been published
for <a href="https://www.ibm.com/support/pages/aix-time-zone-olson-tzdata-updates"><abbr>AIX</abbr></a>,
<a
-href="https://source.android.com/devices/tech/config/timezone-rules">Android</a>,
+href="https://source.android.com/docs/core/permissions/timezone-rules">Android</a>,
<a
href="https://unicode-org.github.io/icu/userguide/datetime/timezone/"><abbr
title="International Components for Unicode">ICU</abbr></a>,
@@ -248,7 +256,7 @@ with lines terminated by <a href="https://en.wikipedia.org/wiki/Newline"><abbr
title="linefeed">LF</abbr></a>,
which can be modified by common text editors such
as <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>,
-<a href="https://gedit-technology.github.io/apps/gedit/">gedit</a>, and
+<a href="https://gedit-text-editor.org">gedit</a>, and
<a href="https://www.vim.org">vim</a>.
Specialized source-file editing can be done via the
<a href="https://packagecontrol.io/packages/zoneinfo">Sublime
@@ -274,14 +282,15 @@ displays changes between recent <code><abbr>tzdb</abbr></code> versions.
<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
+“<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,
+daylight saving rules, please send email as described in
+“<a href="#changes">Changes to the <code><abbr>tz</abbr></code> database</a>”.
+Do this 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
@@ -289,7 +298,7 @@ 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
+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.
@@ -303,7 +312,7 @@ 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 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,
@@ -313,9 +322,9 @@ 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.
+The shorter the notice, the more likely clock problems will arise; see “<a
+href="https://codeofmatt.com/on-the-timing-of-time-zone-changes/">On
+the Timing of Time Zone Changes</a>” for examples.
</p>
</section>
@@ -331,7 +340,7 @@ database format.</li>
<li><a
href="https://blog.jonudell.net/2009/10/23/a-literary-appreciation-of-the-olsonzoneinfotz-database/">A
literary appreciation of the Olson/Zoneinfo/tz database</a> comments on the
-database's style.</li>
+database’s style.</li>
<li><a href="https://doi.org/10.1145/3340301.3341125">What time is it:
managing time in the internet</a> analyzes the database longitudinally.</li>
</ul>
@@ -344,7 +353,7 @@ managing time in the internet</a> analyzes the database longitudinally.</li>
These are listed roughly in ascending order of complexity and fanciness.
</p>
<ul>
-<li><a href="https://time.is">Time.is</a> shows locations'
+<li><a href="https://time.is">Time.is</a> shows locations’
time and zones.</li>
<li><a href="https://www.timejones.com">TimeJones.com</a>,
<a href="https://timezoneconverterapp.com">Time Zone Converter</a> and
@@ -362,7 +371,7 @@ lets you see the <code><abbr>TZ</abbr></code> values directly.</li>
<li><a
href="https://www.convertit.com/Go/ConvertIt/World_Time/Current_Time.ASP">Current
Time in 1000 Places</a> uses descriptions of the values.</li>
-<li><a href="https://www.timeanddate.com/worldclock/">The World Clock &ndash;
+<li><a href="https://www.timeanddate.com/worldclock/">The World Clock –
Worldwide</a> lets you sort zone names and convert times.</li>
<li><a href="https://24timezones.com">24TimeZones</a> has a world
time map and a time converter.</li>
@@ -376,21 +385,16 @@ calculates the current time difference between locations.</li>
<section>
<h2 id="protocols">Network protocols for <code><abbr>tz</abbr></code> data</h2>
<ul>
-<li>The <a href="https://www.ietf.org">Internet Engineering Task Force</a>'s
-<a href="https://datatracker.ietf.org/wg/tzdist/charter/">Time Zone Data
-Distribution Service (tzdist) working group</a> defined <a
-href="https://www.rfc-editor.org/rfc/rfc7808">TZDIST</a>
-(Internet <abbr>RFC</abbr> 7808), a time zone data distribution service,
-along with <a href="https://www.rfc-editor.org/rfc/rfc7809">CalDAV</a>
+<li><a href="https://www.rfc-editor.org/rfc/rfc7808">Time Zone
+Data Distribution Service</a> (TZDIST, Internet <abbr>RFC</abbr> 7808)
+is associated with
+<a href="https://www.rfc-editor.org/rfc/rfc7809">CalDAV</a>
(Internet <abbr>RFC</abbr> 7809), a calendar access protocol for
transferring time zone data by reference.
<a href="https://devguide.calconnect.org/Time-Zones/TZDS/">TZDIST
-implementations</a> are available.
-The <a href="https://www.ietf.org/mailman/listinfo/tzdist-bis">tzdist-bis
-mailing list</a> discusses possible extensions.</li>
-<li>The <a href="https://www.rfc-editor.org/rfc/rfc5545">
-Internet Calendaring and Scheduling Core Object Specification
-(iCalendar)</a> (Internet <abbr>RFC</abbr> 5445)
+implementations</a> are available.</li>
+<li>The <a href="https://www.rfc-editor.org/rfc/rfc5545">iCalendar format</a>
+(Internet <abbr>RFC</abbr> 5445)
covers time zone
data; see its VTIMEZONE calendar component.
The iCalendar format requires specialized parsers and generators; a
@@ -422,10 +426,6 @@ available under the <a
href="https://www.gnu.org/copyleft/gpl.html"><abbr>GNU</abbr>
General Public License (<abbr
title="General Public License">GPL</abbr>)</a>.</li>
-<li><a href="https://sourceforge.net/projects/tzical/">tziCal &ndash; tz
-database conversion utility</a> is like Vzic, except for the <a
-href="https://dotnet.microsoft.com">.NET framework</a>
-and with a <abbr>BSD</abbr>-style license.</li>
<li><a
href="https://metacpan.org/release/DateTime-TimeZone">DateTime::TimeZone</a>
contains a script <code>parse_olson</code> that compiles
@@ -441,7 +441,7 @@ transition in the <code><abbr>tz</abbr></code> database.</li>
Database Parser</a> is a
<a href="https://en.wikipedia.org/wiki/C++">C++</a> parser and
runtime library with a <a
-href="https://en.cppreference.com/w/cpp/chrono"><code>std::chrono</code> API</a>
+href="https://en.cppreference.com/w/cpp/chrono.html"><code>std::chrono</code> API</a>
that is a standard part of C++.
It is freely available under the
<abbr title="Massachusetts Institute of Technology">MIT</abbr> license.</li>
@@ -471,11 +471,11 @@ Although its source code is proprietary, its executable is available under the
<a href="https://www.oracle.com/a/tech/docs/tzupdater-lic.html">Java SE
Timezone Updater License Agreement</a>.</li>
<li>The <a
-href="https://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html">Java
+href="https://www.oracle.com/technical-resources/articles/java/jf14-date-time.html">Java
SE 8 Date and Time</a> <abbr>API</abbr> can be supplemented by <a
href="https://www.threeten.org/threeten-extra/">ThreeTen-Extra</a>,
which is freely available under a <abbr>BSD</abbr>-style license.</li>
-<li><a href="https://www.joda.org/joda-time/">Joda-Time &ndash; Java date
+<li><a href="https://www.joda.org/joda-time/">Joda-Time – Java date
and time <abbr>API</abbr></a> contains a class
<code>org.joda.time.tz.ZoneInfoCompiler</code> that compiles
<code><abbr>tz</abbr></code> source into a binary format. It inspired
@@ -483,8 +483,8 @@ Java 8 <code>java.time</code>, which its users should migrate to once
they can assume Java 8 or later. It is available under the <a
href="https://www.apache.org/licenses/LICENSE-2.0">Apache License</a>.</li>
<li><a href="https://bell-sw.com/pages/iana-updater/">IANA Updater</a> and <a
-href="https://www.azul.com/products/open-source-tools/ziupdater-time-zone-tool/">ZIUpdater</a>
-are alternatives to TZUpdater. IANA Updater's license is unclear;
+href="https://www.azul.com/products/components/ziupdater-time-zone-tool/">ZIUpdater</a>
+are alternatives to TZUpdater. IANA Updater’s license is unclear;
ZIUpdater is licensed under the <abbr>GPL</abbr>.</li>
<li><a href="https://github.com/MenoData/Time4A">Time4A: Advanced date and
time library for Android</a> and
@@ -499,7 +499,7 @@ License">LGPL</abbr>)</a>.</li>
<li><abbr>ICU</abbr> (mentioned <a href="#ICU">above</a>) contains compilers and
Java-based libraries.</li>
</ul>
-<li><a href="https://nodatime.org">Noda Time &ndash; Date and
+<li><a href="https://nodatime.org">Noda Time – Date and
time <abbr>API</abbr> for .NET</a>
is like Joda-Time and Time4J, but for the .NET framework instead of Java.
It is freely available under the Apache License.</li>
@@ -548,13 +548,13 @@ The proposed <a
href="https://github.com/tc39/proposal-temporal"><code>Temporal</code>
objects</a> let programs access an abstract view of
<code><abbr>tzdb</abbr></code> data, and are designed to replace <a
-href="https://codeofmatt.com/javascript-date-type-is-horribly-broken/">JavaScript's
+href="https://codeofmatt.com/javascript-date-type-is-horribly-broken/">JavaScript’s
problematic <code>Date</code> objects</a> when working with dates and times.
<li><a href="https://github.com/JuliaTime">JuliaTime</a> contains a
compiler from <code><abbr>tz</abbr></code> source into
<a href="https://julialang.org">Julia</a>. It is freely available
under the <abbr>MIT</abbr> license.</li>
-<li><a href="https://github.com/pavkam/tzdb"><abbr>TZDB</abbr> &ndash;
+<li><a href="https://github.com/pavkam/tzdb"><abbr>TZDB</abbr> –
<abbr>IANA</abbr> Time Zone Database for Delphi/<abbr
title="Free Pascal Compiler">FPC</abbr></a>
compiles from <code><abbr>tz</abbr></code> source into
@@ -563,14 +563,14 @@ as compiled by <a href="https://en.wikipedia.org/wiki/Delphi_(IDE)">Delphi</a>
and <a
href="https://en.wikipedia.org/wiki/Free_Pascal"><abbr>FPC</abbr></a>.
It is freely available under a <abbr>BSD</abbr>-style license.</li>
-<li><a href="https://pythonhosted.org/pytz/">pytz &ndash; World Timezone
+<li><a href="https://pythonhosted.org/pytz/">pytz – World Timezone
Definitions for Python</a> compiles <code><abbr>tz</abbr></code> source into
<a href="https://www.python.org">Python</a>.
It is freely available under a <abbr>BSD</abbr>-style license.
In code that can assume Python 3.6 or later it is largely superseded; see <a
href="https://blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html">pytz:
The Fastest Footgun in the West</a>.</li>
-<li><a href="https://tzinfo.github.io">TZInfo &ndash;
+<li><a href="https://tzinfo.github.io">TZInfo –
Ruby Timezone Library</a>
compiles <code><abbr>tz</abbr></code> source into
<a href="https://www.ruby-lang.org/en/">Ruby</a>.
@@ -582,7 +582,7 @@ library that compiles <code><abbr>tz</abbr></code> source into a time
zone repository whose format
is either proprietary or an <abbr>XML</abbr>-encoded
representation.</li>
-<li><a id="Tcl" href="https://tcl.tk">Tcl</a>
+<li><a id="Tcl" href="https://www.tcl-lang.org">Tcl</a>
contains a developer-oriented parser that compiles <code><abbr>tz</abbr></code>
source into text files, along with a runtime that can read those
files. Tcl is freely available under a <abbr>BSD</abbr>-style
@@ -600,14 +600,14 @@ has an independent, thread-safe implementation of
a <abbr>TZif</abbr> file reader.
This library is freely available under the LGPL
and is widely used in <abbr>GNU</abbr>/Linux systems.</li>
-<li><a href="https://www.gnome.org">GNOME</a>'s
-<a href="https://developer.gnome.org/glib/">GLib</a> has
+<li><a href="https://www.gnome.org">GNOME</a>’s
+<a href="https://docs.gtk.org/glib/">GLib</a> has
a <abbr>TZif</abbr> file reader written in C that
creates a <code>GTimeZone</code> object representing sets
of <abbr>UT</abbr> offsets.
It is freely available under the <abbr>LGPL</abbr>.</li>
<li>The
-<a href="https://github.com/bloomberg/bde/wiki">BDE Standard Library</a>'s
+<a href="https://github.com/bloomberg/bde/wiki">BDE Standard Library</a>’s
<code>baltzo::TimeZoneUtil</code> component contains a C++
implementation of a <abbr>TZif</abbr> file reader. It is freely available under
the Apache License.</li>
@@ -615,6 +615,9 @@ the Apache License.</li>
library that translates between <abbr>UT</abbr> and civil time and
can read <abbr>TZif</abbr> files. It is freely available under the Apache
License.</li>
+<li>The <a href="https://go.dev">Go programming language</a>
+has a <abbr>TZif</abbr> file reader <a
+href="https://pkg.go.dev/time#LoadLocationFromTZData"><code>LoadLocationFromTZData</code></a>.</li>
<li>The
<a href="https://github.com/nayarsystems/posix_tz_db"><code>posix_tz_db</code>
package</a> contains Python code
@@ -628,7 +631,7 @@ The package is freely available under the MIT license.</li>
<li><a href="https://github.com/derickr/timelib">Timelib</a> is a C
library that reads <abbr>TZif</abbr> files and converts
timestamps from one time zone or format to another.
-It is used by <a href="https://secure.php.net"><abbr
+It is used by <a href="https://www.php.net"><abbr
title="PHP: Hypertext Preprocessor">PHP</abbr></a>,
<a href="https://hhvm.com"><abbr title="HipHop Virtual Machine">HHVM</abbr></a>,
and <a href="https://www.mongodb.com">MongoDB</a>.
@@ -672,38 +675,36 @@ available under a <abbr>BSD</abbr>-style license.</li>
<li><a href="https://foxclocks.org">FoxClocks</a>
is an extension for <a href="https://www.google.com/chrome/">Google
Chrome</a>, <a
-href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> and <a
-href="https://www.mozilla.org/en-US/thunderbird/">Thunderbird</a>.
+href="https://www.firefox.com/en-US/">Firefox</a> and <a
+href="https://www.thunderbird.net/en-US/">Thunderbird</a>.
It displays multiple clocks in the application window, and has a mapping
-interface to <a href="https://www.google.com/earth/">Google Earth</a>.
+interface to <a href="https://earth.google.com/web/">Google Earth</a>.
It is freely available under the <abbr>GPL</abbr>.</li>
-<li><a href="https://golang.org">Go programming language</a>
-implementations contain a copy of a 32-bit subset of a recent
-<code><abbr>tz</abbr></code> database in a
-Go-specific format.</li>
<li>Microsoft Windows 8.1
and later has <code><abbr>tz</abbr></code> data and <abbr>CLDR</abbr>
data (mentioned <a href="#CLDR">below</a>) used by the
<a href="https://en.wikipedia.org/wiki/Windows_Runtime">Windows Runtime</a> /
<a href="https://en.wikipedia.org/wiki/Universal_Windows_Platform">Universal Windows Platform</a> classes
-<a href="https://docs.microsoft.com/uwp/api/Windows.Globalization.DateTimeFormatting.DateTimeFormatter"><code>DateTimeFormatter</code></a> and
-<a href="https://docs.microsoft.com/uwp/api/windows.globalization.calendar"><code>Calendar</code></a>.
+<a href="https://learn.microsoft.com/en-us/uwp/api/Windows.Globalization.DateTimeFormatting.DateTimeFormatter"><code>DateTimeFormatter</code></a> and
+<a href="https://learn.microsoft.com/en-us/uwp/api/windows.globalization.calendar"><code>Calendar</code></a>.
<a id="System.TimeZoneInfo"
-href="https://blogs.msdn.microsoft.com/bclteam/2007/06/07/exploring-windows-time-zones-with-system-timezoneinfo-josh-free/">Exploring
+href="https://learn.microsoft.com/en-us/archive/blogs/bclteam/exploring-windows-time-zones-with-system-timezoneinfo-josh-free">Exploring
Windows Time Zones with <code>System.TimeZoneInfo</code></a> describes
the older, proprietary method of Microsoft Windows 2000 and later,
which stores time zone data in the
<a href="https://en.wikipedia.org/wiki/Windows_Registry">Windows Registry</a>. The
<a
-href="https://unicode.org/cldr/charts/latest/supplemental/zone_tzid.html">Zone &rarr;
-Tzid table</a> or <a
-href="https://github.com/unicode-org/cldr/blob/master/common/supplemental/windowsZones.xml"><abbr>XML</abbr>
+href="https://unicode.org/cldr/charts/latest/supplemental/zone_tzid.html">Zone
+→ Tzid table</a> or <a
+href="https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml"><abbr>XML</abbr>
file</a> of the <abbr>CLDR</abbr> data maps proprietary zone IDs
to <code><abbr>tz</abbr></code> names.
-These mappings can be performed programmatically via the <a href="https://github.com/mj1856/TimeZoneConverter">TimeZoneConverter</a> .NET library,
+These mappings can be performed programmatically via the
+<a href="https://github.com/mattjohnsonpint/TimeZoneConverter">TimeZoneConverter</a>
+.NET library,
or the ICU Java and C++ libraries mentioned <a href="#ICU">above</a>.
<li><a
-href="https://www.oracle.com/java/index.html">Oracle
+href="https://www.oracle.com/java/">Oracle
Java</a> contains a copy of a subset of a recent
<code><abbr>tz</abbr></code> database in a
Java-specific format.</li>
@@ -714,10 +715,10 @@ Java-specific format.</li>
<h2 id="other-dbs">Other time zone databases</h2>
<ul>
<li><a href="https://www.astro.com/atlas">Time-zone Atlas</a>
-is Astrodienst's Web version of Shanks and Pottenger's out-of-print
+is Astrodienst’s Web version of Shanks and Pottenger’s out-of-print
time zone history atlases
-<a href="https://www.worldcat.org/oclc/468828649">for the US</a> and
-<a href="https://www.worldcat.org/oclc/76950459">for the world</a>.
+<a href="https://search.worldcat.org/title/468828649">for the US</a> and
+<a href="https://search.worldcat.org/title/76950459">for the world</a>.
Although these extensive atlases
<a href="https://astrologynewsservice.com/opinion/how-astrologers-contributed-to-the-information-age-a-brief-history-of-time/">were
sources for much of the older <code><abbr>tz</abbr></code> data</a>,
@@ -731,7 +732,7 @@ its own <code>tztab</code>(4) format.</li>
<li><a href="https://www.worldtimeserver.com">World Time Server</a>
is another time zone database.</li>
<li>The <a
-href="https://www.iata.org/publications/store/Pages/standard-schedules-information.aspx">Standard
+href="https://www.iata.org/en/publications/manuals/standard-schedules-information">Standard
Schedules Information Manual</a> of the
International Air Transport Association
gives current time zone rules for airports served by commercial aviation.</li>
@@ -741,32 +742,24 @@ gives current time zone rules for airports served by commercial aviation.</li>
<section>
<h2 id="maps">Maps</h2>
<ul>
-<li>The <a
-href="https://www.cia.gov/the-world-factbook/maps/world-regional/">World
-and Regional Maps section</a> of <em>The World Factbook</em>, published by the
-<a href="https://www.cia.gov">US Central Intelligence
-Agency (<abbr
-title="Central Intelligence Agency">CIA</abbr>)</a>, contains a time
-zone map; the
-<a
-href="https://legacy.lib.utexas.edu/maps/world.html">Perry&ndash;Casta&ntilde;eda
-Library Map Collection</a>
-of the University of Texas at Austin has copies of
-recent editions.
-The pictorial quality is good,
-but the maps do not indicate daylight saving time,
-and parts of the data are a few years out of date.</li>
<li><a href="https://www.worldtimezone.com">World Time Zone Map
with current time</a>
-has several fancy time zone maps; it covers Russia particularly well.
-The maps' pictorial quality is not quite as good as the
-<abbr>CIA</abbr>'s
-but the maps are more up to date.</li>
+has several fancy time zone maps; it covers Russia particularly well.</li>
<li><a
href="https://blog.poormansmath.net/how-much-is-time-wrong-around-the-world/">How
much is time wrong around the world?</a> maps the difference between
mean solar and standard time, highlighting areas such as western China
-where the two differ greatly. It's a bit out of date, unfortunately.</li>
+where the two differ greatly. It’s a bit out of date, unfortunately.</li>
+<li>The
+<a
+href="https://maps.lib.utexas.edu/maps/world.html">Perry–Castañeda
+Library Map Collection</a> of the University of Texas at Austin has
+copies of old maps taken from <a
+href="https://en.wikipedia.org/wiki/The_World_Factbook"><em>The
+World Factbook</em></a>, formerly published by the
+<a href="https://www.cia.gov">US Central Intelligence Agency</a>.
+Although the maps’ pictorial quality is good,
+the maps do not indicate daylight saving time.</li>
</ul>
</section>
@@ -792,32 +785,32 @@ for looking up a timezone name from a GPS coordinate.</li>
the <a
href="https://www.geonames.org/export/web-services.html#timezone">GeoNames
Timezone web service</a>, the <a
-href="https://developers.google.com/maps/documentation/timezone/intro">Google
+href="https://developers.google.com/maps/documentation/timezone/overview">Google
Maps Time Zone API</a>, and
the <a href="https://timezonedb.com/api">TimeZoneDB API</a>.
Commercial network API access is provided
by <a href="https://askgeo.com">AskGeo</a>
and <a href="https://www.geogarage.com/blog/news-1/post/geogarage-time-zone-api-31">GeoGarage</a>.
</li>
-<li>"<a
+<li>“<a
href="https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates/16086964">How
to get a time zone from a location using latitude and longitude
-coordinates?</a>" discusses other geolocation possibilities.</li>
-<li><a href="http://statoids.com/statoids.html">Administrative
-Divisions of Countries ("Statoids")</a> lists
+coordinates?</a>” discusses other geolocation possibilities.</li>
+<li><a href="https://statoids.com/statoids.html">Administrative
+Divisions of Countries (“Statoids”)</a> lists
political subdivision data related to time zones.</li>
<li><a href="https://manifold.net/info/freestuff.shtml">Manifold Software
-&ndash; GIS and Database Tools</a> includes a Manifold-format map of
+– GIS and Database Tools</a> includes a Manifold-format map of
world time zone boundaries circa 2007, distributed under the
<abbr>GPL</abbr>.</li>
<li>A ship within the <a
href="https://en.wikipedia.org/wiki/Territorial_waters">territorial
-waters</a> of any nation uses that nation's time. In international
-waters, time zone boundaries are meridians 15&deg; apart, except that
-<abbr>UT</abbr>&minus;12 and <abbr>UT</abbr>+12 are each 7.5&deg;
+waters</a> of any nation uses that nation’s time. In international
+waters, time zone boundaries are meridians 15° apart, except that
+<abbr>UT</abbr>−12 and <abbr>UT</abbr>+12 are each 7.5°
wide and are separated by
-the 180&deg; meridian (not by the International Date Line, which is
-for land and territorial waters only). A captain can change ship's
+the 180° meridian (not by the International Date Line, which is
+for land and territorial waters only). A captain can change ship’s
clocks any time after entering a new time zone; midnight changes are
common.</li>
</ul>
@@ -830,19 +823,20 @@ common.</li>
Walk through Time</a>
surveys the evolution of timekeeping.</li>
<li>The history of daylight saving time is surveyed in <a
-href="http://www.webexhibits.org/daylightsaving/">About Daylight
-Saving Time &ndash; History, rationale, laws &amp; dates</a> and summarized in
+href="https://www.webexhibits.org/daylightsaving/">About Daylight
+Saving Time – History, rationale, laws &amp; dates</a> and summarized in
<a href="http://seizethedaylight.com/dst/">A Brief
History of Daylight Saving Time</a>.</li>
<li><a href="https://www.laphamsquarterly.org/roundtable/time-lords">Time
Lords</a> discusses how authoritarians manipulate civil time.</li>
-<li><a href="https://www.w3.org/TR/timezone/">Working with Time Zones</a>
+<li><a href="https://www.w3.org/TR/timezone/">Working with Time
+and Time Zones</a>
contains guidelines and best practices for software applications that
deal with civil time.</li>
<li><a href="https://webspace.science.uu.nl/~gent0113/idl/idl.htm">A History of
the International Date Line</a> tells the story of the most important
time zone boundary.</li>
-<li><a href="http://statoids.com/tconcept.html">Basic Time
+<li><a href="https://statoids.com/tconcept.html">Basic Time
Zone Concepts</a> discusses terminological issues behind time zones.</li>
</ul>
</section>
@@ -851,10 +845,7 @@ Zone Concepts</a> discusses terminological issues behind time zones.</li>
<h2 id="national">National histories of legal time</h2>
<dl>
<dt>Australia</dt>
-<dd>The Parliamentary Library commissioned a <a
-href="https://parlinfo.aph.gov.au/parlInfo/download/library/prspub/359V6/upload_binary/359v60.pdf">research
-paper on daylight saving time in Australia</a>.
-The Bureau of Meteorology publishes a list of <a
+<dd>The Bureau of Meteorology publishes a list of <a
href="http://www.bom.gov.au/climate/averages/tables/dst_times.shtml">Implementation
Dates of Daylight Savings Time within Australia</a>.</dd>
<dt>Belgium</dt>
@@ -867,7 +858,7 @@ hreflang="fr">French</a>).</dd>
<dt>Brazil</dt>
<dd>The Time Service Department of the National Observatory
records <a href="http://pcdsh01.on.br/DecHV.html"
-hreflang="pt-BR">Brazil's daylight saving time decrees (in
+hreflang="pt-BR">Brazil’s daylight saving time decrees (in
Portuguese)</a>.</dd>
<dt>Canada</dt>
<dd>National Research Council Canada publishes current
@@ -877,12 +868,12 @@ zones and daylight saving time</a>.</dd>
<dt>Chile</dt>
<dd>The Hydrographic and Oceanographic Service of the Chilean Navy publishes a
<a href="https://www.horaoficial.cl/historia_hora.php" hreflang="es">history of
-Chile's official time (in Spanish)</a>.</dd>
+Chile’s official time (in Spanish)</a>.</dd>
<dt>China</dt>
<dd>The Hong Kong Observatory maintains a
<a href="https://www.hko.gov.hk/en/gts/time/Summertime.htm">history of
summer time in Hong Kong</a>,
-and Macau's Meteorological and Geophysical Bureau maintains a <a
+and Macau’s Meteorological and Geophysical Bureau maintains a <a
href="https://www.smg.gov.mo/en/subpage/224/page/174">similar
history for Macau</a>.
Unfortunately the latter is incomplete and has errors.</dd>
@@ -892,7 +883,7 @@ hreflang="cs">When daylight saving time starts and ends (in Czech)</a>
summarizes and cites historical <abbr>DST</abbr> regulations.</dd>
<dt>Germany</dt>
<dd>The National Institute for Science and Technology maintains the <a
-href="https://www.ptb.de/cms/en/fachabteilungen/abt4/fb-44/ag-441/realisation-of-legal-time-in-germany.html">Realisation
+href="https://www.ptb.de/cms/en/ptb/fachabteilungen/abt4/fb-44/ag-441/realisation-of-legal-time-in-germany.html">Realisation
of Legal Time in Germany</a>.</dd>
<dt>Israel</dt>
<dd><a
@@ -912,11 +903,11 @@ hreflang="nl">Legal time in the Netherlands (in Dutch)</a>
covers the history of local time in the Netherlands from ancient times.</dd>
<dt>New Zealand</dt>
<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>
+href="https://www.govt.nz/browse/recreation-and-the-environment/daylight-saving/history-of-daylight-saving-in-nz/">History
+of Daylight Saving in NZ</a>.</dd>
<dt>Palestine</dt>
-<dd>The Ministry of Telecom and IT publishes a <a
-href="https://mtit.pna.ps/home/TimeZone"
+<dd>The Ministry of Telecom and Digital Economy publishes a <a
+href="https://mtde.gov.ps/home/TimeZone"
hreflang="ar">history of clock changes (in Arabic)</a>.</dd>
<dt>Portugal</dt>
<dd>The Lisbon Astronomical Observatory publishes a
@@ -925,7 +916,7 @@ legal time (in Portuguese)</a>.</dd>
<dt>Singapore</dt>
<dd><a id="Singapore"
href="https://web.archive.org/web/20190822231045/http://www.math.nus.edu.sg/~mathelmr/teaching/timezone.html">Why
-is Singapore in the "Wrong" Time Zone?</a> details the
+is Singapore in the “Wrong” Time Zone?</a> details the
history of legal time in Singapore and Malaysia.</dd>
<dt>United Kingdom</dt>
<dd><a
@@ -933,7 +924,7 @@ href="https://www.polyomino.org.uk/british-time/">History of
legal time in Britain</a> discusses in detail the country
with perhaps the best-documented history of clock adjustments.</dd>
<dt>United States</dt>
-<dd>The Department of Transportation's <a
+<dd>The Department of Transportation’s <a
href="https://www.transportation.gov/regulations/recent-time-zone-proceedings">Recent
Time Zone Proceedings</a> lists changes to
official written time zone boundaries, and its <a
@@ -957,9 +948,6 @@ zone shifts, and many scientific studies have been conducted. This
section summarizes reviews and position statements based on
scientific literature in the area.</p>
<ul>
-<li>In 2022 the American Medical Association issued a
-<a href="https://www.ama-assn.org/press-center/press-releases/ama-calls-permanent-standard-time">statement
-supporting permanent standard time</a> on health grounds.</li>
<li>Carey RN, Sarma KM.
<a href="https://bmjopen.bmj.com/content/7/6/e014319.long">Impact of
daylight saving time on road traffic collision risk: a systematic
@@ -969,13 +957,41 @@ This reviews research literature and concludes that the evidence
neither supports nor refutes road safety benefits from
shifts in time zones.</li>
<li>Havranek T, Herman D, Irsova D.
-<a href="https://www.iaee.org/en/publications/ejarticle.aspx?id=3051">Does
-daylight saving save electricity? A meta-analysis</a>.
-<em>Energy J.</em> 2018;39(2):35&ndash;61.
+Does daylight saving save electricity? A meta-analysis.
+<em>Energy J.</em> 2018;39(2):35–61.
doi:<a href="https://doi.org/10.5547/01956574.39.2.thav">10.5547/01956574.39.2.thav</a>.
-This analyzes research literature and concludes, "Electricity savings
+This analyzes research literature and concludes, “Electricity savings
are larger for countries farther away from the equator, while
-subtropical regions consume more electricity because of <abbr>DST</abbr>."</li>
+subtropical regions consume more electricity because of <abbr>DST</abbr>.”</li>
+<li>Neumann P, von Blanckenburg K. <a
+href="https://journals.sagepub.com/doi/full/10.1177/0961463X241310562">What
+time will it be? A comprehensive literature review on daylight saving time</a>.
+<em>Time Soc</em>. 2025;34(4):684–745.
+doi:<a href="https://doi.org/10.1177/0961463X241310562">10.1177/0961463X241310562</a>.
+This reviews <abbr>DST</abbr>’s effects on electricity, health, crime, road
+safety, and the economy, focusing on research since 2010, and concludes that
+year-round standard time is preferable overall.</li>
+<li>Romigi A, Franco V, Scoditti E <em>et al</em>.
+The effects of daylight saving time and clock time transitions on sleep and
+sleepiness: a systematic review. <em>Sleep Med Rev.</em> 2025;84:102161. doi:<a
+href="https://doi.org/10.1016/j.smrv.2025.102161">10.1016/j.smrv.2025.102161</a>.
+This reviews <abbr>DST</abbr> and <abbr>DST</abbr> transitions,
+and concludes that they both harm sleep, health and behavior.</li>
+</ul>
+
+<p>The following medical societies have taken positions on the
+advisability of clock shifts:</p>
+
+<ul>
+<li>In 2022 the American Medical Association issued a
+<a href="https://www.ama-assn.org/press-center/ama-press-releases/ama-calls-permanent-standard-time">statement
+supporting permanent standard time</a> on health grounds.</li>
+<li>Crawford MR, Winnebeck EC, von Schantz M <em>et al</em>.
+<a href="https://onlinelibrary.wiley.com/doi/10.1111/jsr.14352">The
+British Sleep Society position statement on Daylight Saving Time in the UK</a>.
+<em>J Sleep Res.</em> 2025;34(3):e14352.
+doi:<a href="https://doi.org/10.1111/jsr.14352">10.1111/jsr.14352</a>.
+This recommends that the UK abolish <abbr>DST</abbr> for health reasons.</li>
<li>Malow BA. <a
href="https://academic.oup.com/sleep/article/45/12/zsac236/6717940">It is time
to abolish the clock change and adopt permanent
@@ -983,21 +999,13 @@ standard time in the United States:
a Sleep Research Society position statement</a>.
<em>Sleep.</em> 2022;45(12):zsac236.
doi:<a href="https://doi.org/10.1093/sleep/zsac236">10.1093/sleep/zsac236</a>.
-After reviewing the scientific literature, the Sleep Research Society
-advocates permanent standard time due to its health benefits.
-<li>Neumann P, von Blanckenburg K. <a
-href="https://journals.sagepub.com/doi/full/10.1177/0961463X241310562">What
-time will it be? A comprehensive literature review on daylight saving time</a>.
-<em>Time Soc</em>. 2025-01-21.
-doi:<a href="https://doi.org/10.1177/0961463X241310562">10.1177/0961463X241310562</a>.
-This reviews DST's effects on electricity, health, crime, road safety,
-and the economy, focusing on research since 2010, and concludes that
-year-round standard time is preferable overall.
+The Sleep Research Society
+advocates permanent standard time due to its health benefits.</li>
<li>Rishi MA, Cheng JY, Strang AR <em>et al</em>.
<a href="https://jcsm.aasm.org/doi/10.5664/jcsm.10898">Permanent standard time
is the optimal choice for health and safety:
an American Academy of Sleep Medicine position statement</a>.
-<em>J Clin Sleep Med.</em> 2024;20(1):121&ndash;125.
+<em>J Clin Sleep Med.</em> 2024;20(1):121–125.
doi:<a href="https://doi.org/10.5664/jcsm.10898">10.5664/jcsm.10898</a>.
The AASM argues for permanent standard time due to health and safety risks
and economic costs of both <abbr>DST</abbr> transitions and
@@ -1005,12 +1013,12 @@ permanent <abbr>DST</abbr>.</li>
<li>Roenneberg T, Wirz-Justice A, Skene DJ <em>et al</em>.
<a href="https://journals.sagepub.com/doi/10.1177/0748730419854197">Why
should we abolish Daylight Saving Time?</a>
-<em>J Biol Rhythms.</em> 2019;34(3):227&ndash;230.
+<em>J Biol Rhythms.</em> 2019;34(3):227–230.
doi:<a href="https://doi.org/10.1177/0748730419854197">10.1177/0748730419854197</a>.
The Society for Research on Biological Rhythms
opposes <abbr>DST</abbr> changes and permanent <abbr>DST</abbr>,
and advocates that governments adopt
-"permanent Standard Time for the health and safety of their citizens".</li>
+“permanent Standard Time for the health and safety of their citizens”.</li>
</ul>
</section>
@@ -1032,7 +1040,7 @@ Internet hosts.</li>
family of software algorithms can achieve accuracy to a few tens of
nanoseconds in scalable server farms without special hardware.</li>
<li>The <a
-href="https://www.nist.gov/intelligent-systems-division/ieee-1588">Precision
+href="https://www.nist.gov/el/intelligent-systems-division-73500/ieee-1588">Precision
Time Protocol</a> (<abbr
title="Institute of Electrical and Electronics Engineers">IEEE</abbr> 1588)
can achieve submicrosecond clock accuracy on a local area network
@@ -1044,14 +1052,14 @@ Options for <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr></a>
specifies a <a
href="https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol"><abbr>DHCP</abbr></a>
option for a server to configure
-a client's time zone and daylight saving settings automatically.</li>
+a client’s time zone and daylight saving settings automatically.</li>
<li><a href="https://www.ucolick.org/~sla/leapsecs/timescales.html">Time
Scales</a> describes astronomical time scales like
<abbr title="Terrestrial Dynamic Time">TDT</abbr>,
<abbr title="Geocentric Coordinate Time">TCG</abbr>, and
<abbr title="Barycentric Dynamic Time">TDB</abbr>.
<li>The <a href="https://www.iau.org"><abbr
-title="International Astronomical Union">IAU</abbr></a>'s <a
+title="International Astronomical Union">IAU</abbr></a>’s <a
href="https://www.iausofa.org"><abbr
title="Standards Of Fundamental Astronomy">SOFA</abbr></a>
collection contains C and <a
@@ -1060,10 +1068,10 @@ code for converting among time scales like
<abbr title="International Atomic Time">TAI</abbr>,
<abbr>TDB</abbr>, <abbr>TDT</abbr> and
<abbr>UTC</abbr>. It is freely available under the
-<a href="https://www.iausofa.org/tandc.html">SOFA license</a>.</li>
+<a href="https://www.iausofa.org/terms-and-conditions">SOFA license</a>.</li>
<li><a
href="https://www.giss.nasa.gov/tools/mars24/help/notes.html">Mars24 Sunclock
-&ndash; Time on Mars</a> describes Airy Mean Time (<abbr>AMT</abbr>) and the
+– Time on Mars</a> describes Airy Mean Time (<abbr>AMT</abbr>) and the
diverse local time
scales used by each landed mission on Mars.</li>
<li><a href="http://leapsecond.com">LeapSecond.com</a> is
@@ -1072,25 +1080,26 @@ in general. It covers the state of the art in amateur timekeeping, and
how the art has progressed over the past few decades.</li>
<li>The rules for leap seconds are specified in Annex 1 (Time scales) of <a
href="https://www.itu.int/rec/R-REC-TF.460-6-200202-I/">Standard-frequency
-and time-signal emissions</a>, International Telecommunication Union &ndash;
+and time-signal emissions</a>, International Telecommunication Union –
Radiocommunication Sector (ITU-R) Recommendation TF.460-6 (02/2002).</li>
<li><a
href="https://www.iers.org/IERS/EN/Publications/Bulletins/bulletins.html"><abbr
title="International Earth Rotation and Reference Systems Service">IERS</abbr>
Bulletins</a> contains official publications of the International
Earth Rotation and Reference Systems Service, which decides when leap
-seconds occur. The <code><abbr>tz</abbr></code> code and data support leap seconds
-via an optional "<code>right</code>" configuration where a computer's internal
+seconds occur.
+The <code><abbr>tz</abbr></code> code and data support leap seconds
+via an optional <code>"right"</code> configuration where a computer’s internal
<code>time_t</code> integer clock counts every <abbr>TAI</abbr> second,
-as opposed to the default "<code>posix</code>" configuration
+as opposed to the default <code>"posix"</code> configuration
where the internal clock ignores leap seconds.
The two configurations agree for timestamps starting with 1972-01-01 00:00:00
<abbr>UTC</abbr> (<code>time_t</code> 63&thinsp;072&thinsp;000) and diverge for
timestamps starting with <code>time_t</code> 78&thinsp;796&thinsp;800,
which corresponds to the first leap second
-1972-06-30 23:59:60 <abbr>UTC</abbr> in the "<code>right</code>" configuration,
+1972-06-30 23:59:60 <abbr>UTC</abbr> in the <code>"right"</code> configuration,
and to
-1972-07-01 00:00:00 <abbr>UTC</abbr> in the "<code>posix</code>" configuration.
+1972-07-01 00:00:00 <abbr>UTC</abbr> in the <code>"posix"</code> configuration.
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>
@@ -1105,7 +1114,7 @@ The <abbr>IERS</abbr> maintains this file, and a copy is distributed by
and <a href="https://ntpsec.org">NTPsec</a>.
The <code><abbr>tz</abbr></code> database also distributes leap second
information in a differently-formatted <code>leapseconds</code> text file,
-as well as in the "<code>right</code>" configuration in binary form; for
+as well as in the <code>"right"</code> configuration in binary form; for
example, <code>right/UTC</code> can be used
by <a href="https://chrony-project.org"><code>chrony</code></a>,
another <abbr>NTP</abbr> implementation.</li>
@@ -1114,13 +1123,13 @@ 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
half second, even though every <abbr>POSIX</abbr> minute has exactly
sixty seconds. This approach works with the default <code><abbr>tz</abbr></code>
-"<code>posix</code>" configuration, is <a
-href="http://bk1.ntp.org/ntp-stable/README.leapsmear">supported</a> by
-the abovementioned <abbr>NTP</abbr> implementations, <a
+<code>"posix"</code> configuration, is <a
+href="https://gitlab.com/NTPsec/ntpsec/-/blob/master/docs/leapsmear.adoc">supported</a>
+by the abovementioned <abbr>NTP</abbr> implementations, <a
href="https://github.com/google/unsmear">supports</a> conversion between
<abbr>UTC</abbr> and smeared <abbr>POSIX</abbr> timestamps, and is used by major
cloud service providers. However, according to
-<a href="https://www.rfc-editor.org/rfc/rfc8633#section-3.7.1">&sect;3.7.1 of
+<a href="https://www.rfc-editor.org/rfc/rfc8633#section-3.7.1">§3.7.1 of
Network Time Protocol Best Current Practices</a>
(Internet <abbr>RFC</abbr> 8633), leap smearing is not suitable for
applications requiring accurate <abbr>UTC</abbr> or civil time,
@@ -1128,8 +1137,8 @@ and is intended for use only in single, well-controlled environments.</li>
<li>The <a
href="https://pairlist6.pair.net/mailman/listinfo/leapsecs">Leap
Second Discussion List</a> covers <a
-href="https://www2.unb.ca/gge/Resources/gpsworld.november99.pdf">McCarthy
-and Klepczynski's 1999 proposal to discontinue leap seconds</a>,
+href="https://gge.ext.unb.ca/Resources/gpsworld.november99.pdf">McCarthy
+and Klepczynski’s 1999 proposal to discontinue leap seconds</a>,
discussed further in
<a href="https://www.cl.cam.ac.uk/~mgk25/time/metrologia-leapsecond.pdf">The
leap second: its history and possible future</a>.
@@ -1143,12 +1152,16 @@ to discontinue the use of leap seconds by 2035, and requested that no
discontinuous adjustments be made to UTC for at least a century.
The World Radiocommunication Conference <a
href="https://www.itu.int/dms_pub/itu-r/opb/act/R-ACT-WRC.15-2023-PDF-E.pdf">resolved
-in 2023</a> to cooperate with this process.
-<a href="https://www.preprints.org/manuscript/202406.0043/v1">A proposal
-to change the leap-second adjustments to Coordinated Universal Time</a>
-(doi:<a href="https://doi.org/10.1088/1681-7575/ad6266">10.1088/1681-7575/ad6266</a>)
-would replace leap seconds with 13-second leap smears occurring once per
+in 2023</a> to cooperate with this process. One proposal to implement this
+would replace leap seconds with seven 13-second leap smears occurring once per
decade until 2100, with leap smears after that gradually increasing in size.
+See:
+<ul>
+<li>Levine J. <a href="https://www.preprints.org/manuscript/202406.0043">A
+proposal to change the leap-second adjustments to
+coordinated universal time</a>. <em>Metrologia.</em> 2024;61(5):055002. doi:<a
+href="https://doi.org/10.1088/1681-7575/ad6266">10.1088/1681-7575/ad6266</a>.</li>
+</ul>
However, there is still no consensus on whether this is the best way
to replace leap seconds.
</li>
@@ -1161,9 +1174,8 @@ to replace leap seconds.
<li>The <a id="CLDR" href="https://cldr.unicode.org">Unicode Common Locale Data
Repository (<abbr>CLDR</abbr>) Project</a> has localizations for time
zone names, abbreviations, identifiers, and formats. For example, it
-contains French translations for "Eastern European Summer Time",
-"<abbr title="Eastern European Summer Time">EEST</abbr>", and
-"Bucharest". Its
+contains French translations for “Eastern European Summer Time”,
+“<abbr title="Eastern European Summer Time">EEST</abbr>”, and “Bucharest”. Its
<a href="https://unicode.org/cldr/charts/latest/by_type/">by-type
charts</a> show these values for many locales. Data values are available in
both <abbr title="Locale Data Markup Language">LDML</abbr>
@@ -1174,13 +1186,13 @@ the international standard date and time notation</a> covers
<a
href="https://www.iso.org/standard/70907.html"><em><abbr
title="International Organization for Standardization">ISO</abbr>
-8601-1:2019 &ndash; Date and time &ndash; Representations for information
-interchange &ndash; Part 1: Basic rules</em></a>.</li>
+8601-1:2019 – Date and time – Representations for information
+interchange – Part 1: Basic rules</em></a>.</li>
<li>
<a href="https://www.w3.org/TR/xmlschema/#dateTime"><abbr>XML</abbr>
-Schema: Datatypes &ndash; dateTime</a> specifies a format inspired by
+Schema: Datatypes – dateTime</a> specifies a format inspired by
<abbr>ISO</abbr> 8601 that is in common use in <abbr>XML</abbr> data.</li>
-<li><a href="https://www.rfc-editor.org/rfc/rfc5322#section-3.3">&sect;3.3 of
+<li><a href="https://www.rfc-editor.org/rfc/rfc5322#section-3.3">§3.3 of
Internet Message Format</a> (Internet <abbr>RFC</abbr> 5322)
specifies the time notation used in email and <a
href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol"><abbr>HTTP</abbr></a>
@@ -1193,7 +1205,7 @@ An extension, <a href="https://www.rfc-editor.org/rfc/rfc9557">Date
and Time on the Internet: Timestamps with Additional Information</a>
(Internet <abbr>RFC</abbr> 9557) extends this profile
to let you specify the <code><abbr>tzdb</abbr></code> timezone of a timestamp
-via suffixes like "<code>[Asia/Tokyo]</code>".
+via suffixes like <code>[Asia/Tokyo]</code>.
<li>
<a href="https://web.archive.org/web/20190130042457/https://www.hackcraft.net/web/datetime/">Date &amp; Time
Formats on the Web</a> surveys web- and Internet-oriented date and time
@@ -1201,17 +1213,17 @@ formats.</li>
<li>Alphabetic time zone abbreviations should not be used as unique
identifiers for <abbr>UT</abbr> offsets as they are ambiguous in
practice. For example, in English-speaking North America
-"<abbr>CST</abbr>" denotes 6 hours behind <abbr>UT</abbr>,
+“<abbr>CST</abbr>” denotes 6 hours behind <abbr>UT</abbr>,
but in China it denotes 8 hours ahead of <abbr>UT</abbr>,
and French-speaking North Americans prefer
-"<abbr title="Heure Normale du Centre">HNC</abbr>" to
-"<abbr>CST</abbr>". The <code><abbr>tz</abbr></code>
+“<abbr title="Heure Normale du Centre">HNC</abbr>” to
+“<abbr>CST</abbr>”. The <code><abbr>tz</abbr></code>
database contains English abbreviations for many timestamps;
-unfortunately some of these abbreviations were merely the database maintainers'
+unfortunately some of these abbreviations were merely the database maintainers’
inventions, and these have been removed when possible.</li>
<li>Numeric time zone abbreviations typically count hours east of
<abbr>UT</abbr>, e.g., +09 for Japan and
-&minus;10 for Hawaii. However, <abbr>POSIX</abbr> proleptic
+−10 for Hawaii. However, <abbr>POSIX</abbr> proleptic
<code><abbr>TZ</abbr></code> settings use the opposite convention.
For example, one might use <code><abbr>TZ</abbr>="<abbr
title="Japan Standard Time">JST</abbr>-9"</code> and
@@ -1225,7 +1237,7 @@ any future changes to the rules. One should never set
<abbr>POSIX</abbr> <code><abbr>TZ</abbr></code> to a value like
<code>"GMT-9"</code>, though, since this would incorrectly imply that
local time is nine hours ahead of <abbr>UT</abbr> and the time zone
-is called "<abbr>GMT</abbr>".</li>
+is called “<abbr>GMT</abbr>”.</li>
</ul>
</section>
@@ -1245,6 +1257,8 @@ This web page is in the public domain, so clarified as of
<br>
Please send corrections to this web page to the
<a href="mailto:tz@iana.org">time zone mailing list</a>.
+The mailing list and its archives are public,
+so please do not send confidential information.
</footer>
</body>
</html>
diff --git a/contrib/tzcode/tzconfig.h b/contrib/tzcode/tzconfig.h
index c692d06953a2..8cdffeb17c57 100644
--- a/contrib/tzcode/tzconfig.h
+++ b/contrib/tzcode/tzconfig.h
@@ -1,19 +1,31 @@
#ifndef TZCONFIG_H_INCLUDED
#define TZCONFIG_H_INCLUDED
-#define TM_GMTOFF tm_gmtoff
-#define TM_ZONE tm_zone
+#define TM_GMTOFF tm_gmtoff
+#define TM_ZONE tm_zone
-#define HAVE_GETTEXT false
-#define HAVE_SYS_STAT_H true
-#define HAVE_UNISTD_H true
-#define HAVE_STDINT_H true
+#define FREE_PRESERVES_ERRNO false
+#define HAVE_GETTEXT false
+#define HAVE_ISSETUGID true
+#define HAVE___ISTHREADED true
+#define HAVE_MEMPCPY true
+#define HAVE_PWD_H true
+#define HAVE_SETMODE true
+#define HAVE_STRUCT_STAT_ST_CTIM true
+#define HAVE_SYS_STAT_H true
+#define HAVE_UNISTD_H true
+#define HAVE_STDINT_H true
+#define OPENAT_TZDIR true
+#define THREAD_PREFER_SINGLE true
+#define THREAD_TM_MULTI true
-#define PCTS 1
-#define NETBSD_INSPIRED 0
-#define STD_INSPIRED 1
-#define HAVE_TZNAME 2
-#define USG_COMPAT 2
-#define ALTZONE 0
+#define PCTS 1
+#define NETBSD_INSPIRED 0
+#define STD_INSPIRED 1
+#define HAVE_TZNAME 2
+#define USG_COMPAT 2
+#define ALTZONE 0
+
+#define GRANDPARENTED "Local time zone must be set--use tzsetup"
#endif /* !TZCONFIG_H_INCLUDED */
diff --git a/contrib/tzcode/tzfile.5 b/contrib/tzcode/tzfile.5
index 66d169fc5302..b6e805e9135f 100644
--- a/contrib/tzcode/tzfile.5
+++ b/contrib/tzcode/tzfile.5
@@ -1,6 +1,6 @@
.\" This file is in the public domain, so clarified as of
.\" 1996-06-05 by Arthur David Olson.
-.Dd December 15, 2022
+.Dd March 8, 2026
.Dt TZFILE 5
.Os
.Sh NAME
@@ -123,7 +123,7 @@ already support the POSIX-required range [\-24:59:59, 25:59:59].
bytes that represent time zone designations,
which are null-terminated byte strings, each indexed by the
.Va tt_desigidx
-values mentioned above.
+values mentioned above, and each corresponding to a time zone abbreviation.
The byte strings can overlap if one is a suffix of the other.
The encoding of these strings is not specified.
.It Va tzh_leapcnt
@@ -170,14 +170,15 @@ for another time zone specified via
a proleptic TZ string that lacks rules.
For example, when TZ="EET\-2EEST" and there is no TZif file "EET\-2EEST",
the idea was to adapt the transition times from a TZif file with the
-well-known name "posixrules" that is present only for this purpose and
-is a copy of the file "Europe/Brussels", a file with a different UT offset.
+well-known name "posixrules" that was present only for this purpose and
+was a copy of the file "Europe/Brussels", a file with a different UT offset.
POSIX does not specify the details of this obsolete transformational behavior,
the default rules are installation-dependent, and no implementation
is known to support this feature for timestamps past 2037,
so users desiring (say) Greek time should instead specify
TZ="Europe/Athens" for better historical coverage, falling back on
-TZ="EET\-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required
+TZ="EET\-2EEST,M3.5.0/3,M10.5.0/4"
+if conformance to POSIX.1-2017 or earlier is required
and older timestamps need not be handled accurately.
.Pp
The
@@ -203,6 +204,7 @@ after the last transition time stored in the file
or for all instants if the file has no transitions.
The TZ string is empty (i.e., nothing between the newlines)
if there is no proleptic representation for such instants.
+.PP
If non-empty, the 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
@@ -211,6 +213,10 @@ then if a last transition time is in July, the transition's local time
type must specify a daylight-saving time abbreviated
.Dq "WEST"
that is one hour east of UT.
+.PP
+The TZ string can contain time zone abbreviations and UT offsets that
+do not appear elsewhere in the TZif file.
+.PP
Also, if there is at least one transition, time type 0 is associated
with the time period from the indefinite past up to but not including
the earliest transition time.
@@ -272,7 +278,7 @@ time, TZif readers should either refuse to process
post-expiration timestamps, or process them as if the expiration
time did not exist (possibly with an error indication).
.Pp
-Time zone designations should consist of at least three (3)
+Time zone abbreviations should consist of at least three (3)
and no more than six (6) ASCII characters from the set of
alphanumerics,
.Dq "\-" ,
@@ -281,6 +287,10 @@ and
This is for compatibility with POSIX requirements for
time zone abbreviations.
.Pp
+A numeric time zone abbreviation should match the UT offset.
+For example, "+0530" should be used only if the UT offset is 5.5 hours
+ahead of UT, and "\-00" should be used only if the UT offset is zero.
+.Pp
When reading a version 2 or higher file, readers
should ignore the version 1 header and data block except for
the purpose of skipping over them.
@@ -343,6 +353,14 @@ As a partial workaround, a writer can output more transitions
than necessary, so that only far-future timestamps are
mishandled by version 2 readers.
.It
+Some readers might mishandle timestamps after a file's last transition,
+because they require that all abbreviations or UT offsets
+in the proleptic TZ string must also occur somewhere in the file's tables
+of time zone designations and local time type records.
+As a workaround, a writer can output more transitions than necessary,
+so that the other tables contain duplicates of the proleptic TZ string's
+abbreviations and offsets.
+.It
Some readers designed for version 2 do not support
permanent daylight saving time with transitions after 24:00
\(en e.g., a TZ string
diff --git a/contrib/tzcode/tzfile.h b/contrib/tzcode/tzfile.h
index 55867b5c260c..1941bc3b7693 100644
--- a/contrib/tzcode/tzfile.h
+++ b/contrib/tzcode/tzfile.h
@@ -1,14 +1,12 @@
/* Layout and location of TZif files. */
#ifndef TZFILE_H
-#define TZFILE_H
+#define TZFILE_H
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.
-**
-** $FreeBSD$
*/
/*
@@ -19,22 +17,14 @@
** Thank you!
*/
-/*
-** Information about time zone files.
-*/
-
-#ifndef TZDEFRULES
-# define TZDEFRULES "posixrules"
-#endif /* !defined TZDEFRULES */
-
-
-/* See Internet RFC 9636 for more details about the following format. */
+/* Information about time zone files.
+ See Internet RFC 9636 for more details about the following format. */
/*
** Each file begins with. . .
*/
-#define TZ_MAGIC "TZif"
+#define TZ_MAGIC "TZif"
struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
@@ -99,23 +89,25 @@ struct tzhead {
*/
#ifndef TZ_MAX_TIMES
-/* This must be at least 242 for Europe/London with 'zic -b fat'. */
+/* The following limit applies to localtime.c; zic has no such limit.
+ The limit must be at least 310 for Asia/Hebron with 'zic -b fat'. */
# define TZ_MAX_TIMES 2000
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
/* 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 */
+# define TZ_MAX_TYPES 256 /* Limited to 256 by Internet RFC 9636. */
#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) */
+# define TZ_MAX_CHARS 256 /* Maximum number of abbreviation characters */
+ /* (limited to 256 by Internet RFC 9636) */
#endif /* !defined TZ_MAX_CHARS */
#ifndef TZ_MAX_LEAPS
-/* This must be at least 27 for leap seconds from 1972 through mid-2023.
+/* The following limit applies to localtime.c; zic has no such limit.
+ The limit must be at least 27 for leap seconds from 1972 through mid-2023.
There's a plan to discontinue leap seconds by 2035. */
# define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
#endif /* !defined TZ_MAX_LEAPS */
diff --git a/contrib/tzcode/tzselect.ksh b/contrib/tzcode/tzselect.ksh
index ca3d82c6aab6..85a8c670e0da 100644
--- a/contrib/tzcode/tzselect.ksh
+++ b/contrib/tzcode/tzselect.ksh
@@ -145,9 +145,11 @@ do
t*) # Undocumented option, used for developer testing.
zonetabtype=$OPTARG;;
-help)
- exec echo "$usage";;
+ say "$usage"
+ exit;;
-version)
- exec echo "tzselect $PKGVERSION$TZVERSION";;
+ say "tzselect $PKGVERSION$TZVERSION"
+ exit;;
-*)
say >&2 "$0: -$opt$OPTARG: unknown option; try '$0 --help'"; exit 1;;
*)
@@ -161,15 +163,15 @@ case $# in
*) say >&2 "$0: $1: unknown argument"; exit 1
esac
-# translit=true to try transliteration.
+# translit=: to try transliteration.
# This is false if U+12345 CUNEIFORM SIGN URU TIMES KI has length 1
# which means the shell and (presumably) awk do not need transliteration.
-# It is true if the byte string has some other length in characters, or
+# It is ':' if the byte string has some other length in characters, or
# if this is a POSIX.1-2017 or earlier shell that does not support $'...'.
CUNEIFORM_SIGN_URU_TIMES_KI=$'\360\222\215\205'
if test ${#CUNEIFORM_SIGN_URU_TIMES_KI} = 1
then translit=false
-else translit=true
+else translit=:
fi
# Read into shell variable $1 the contents of file $2.
@@ -516,8 +518,7 @@ while
' ="$distance_table"
)
echo >&2 'Please select one of the following timezones,'
- echo >&2 'listed roughly in increasing order' \
- "of distance from $coord".
+ say >&2 "listed roughly in increasing order of distance from $coord."
doselect $regions
region=$select_result
tz=$(
diff --git a/contrib/tzcode/version b/contrib/tzcode/version
index ef468adcecf9..5d9126009e7f 100644
--- a/contrib/tzcode/version
+++ b/contrib/tzcode/version
@@ -1 +1 @@
-2025b
+2026a
diff --git a/contrib/tzcode/workman.sh b/contrib/tzcode/workman.sh
index 29f317cb40c4..5da55654b01c 100644
--- a/contrib/tzcode/workman.sh
+++ b/contrib/tzcode/workman.sh
@@ -4,17 +4,35 @@
# This file is in the public domain, so clarified as of
# 2009-05-17 by Arthur David Olson.
-if (type nroff && type perl) >/dev/null 2>&1; then
+manflags=
+while
+ case $1 in
+ -*) :;;
+ *) false;;
+ esac
+do
+ manflags="$manflags $1"
+ shift
+done
- # Tell groff not to emit SGR escape sequences (ANSI color escapes).
- export GROFF_NO_SGR=1
-
- echo ".am TH
-.hy 0
+groff="groff -dAD=l -rHY=0 $manflags -mtty-char -man -ww -P-bcou"
+if ($groff) </dev/null >/dev/null 2>&1; then
+ $groff "$@"
+elif (type mandoc && type col) >/dev/null 2>&1; then
+ mandoc $manflags -man "$@" | col -bx
+elif (type nroff && type perl) >/dev/null 2>&1; then
+ printf '%s\n' '.
+.\" Left-adjust and do not hyphenate.
+.am TH
.na
+.hy 0
..
+.\" Omit internal page headers and footers.
+.\" Unfortunately this also omits the starting header and ending footer,
+.\" but that is the best old nroff can easily do.
.rm }H
-.rm }F" | nroff -man - ${1+"$@"} | perl -ne '
+.rm }F
+.' | nroff -man - "$@" | perl -ne '
binmode STDIN, '\'':encoding(utf8)'\'';
binmode STDOUT, '\'':encoding(utf8)'\'';
chomp;
@@ -32,9 +50,7 @@ if (type nroff && type perl) >/dev/null 2>&1; then
$didprint = 1;
}
'
-elif (type mandoc && type col) >/dev/null 2>&1; then
- mandoc -man -T ascii "$@" | col -bx
else
- echo >&2 "$0: please install nroff and perl, or mandoc and col"
+ printf >&2 '%s\n' "$0: please install groff, or mandoc and col"
exit 1
fi
diff --git a/contrib/tzcode/zdump.c b/contrib/tzcode/zdump.c
index a8a8f5aa42ca..94b441336d25 100644
--- a/contrib/tzcode/zdump.c
+++ b/contrib/tzcode/zdump.c
@@ -61,13 +61,6 @@ enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 };
# define timezone_t char **
#endif
-#if !HAVE_POSIX_DECLS
-extern int getopt(int argc, char * const argv[],
- const char * options);
-extern char * optarg;
-extern int optind;
-#endif
-
/* The minimum and maximum finite time values. */
enum { atime_shift = CHAR_BIT * sizeof(time_t) - 2 };
static time_t const absolute_min_time =
@@ -130,7 +123,8 @@ size_overflow(void)
/* Return A + B, exiting if the result would overflow either ptrdiff_t
or size_t. A and B are both nonnegative. */
-ATTRIBUTE_PURE_114833 static ptrdiff_t
+ATTRIBUTE_PURE_114833_HACK
+static ptrdiff_t
sumsize(ptrdiff_t a, ptrdiff_t b)
{
#ifdef ckd_add
@@ -929,6 +923,7 @@ my_snprintf(char *s, size_t size, char const *format, ...)
int n;
va_list args;
char const *arg;
+ char *cp;
size_t arglen, slen;
char buf[1024];
va_start(args, format);
@@ -945,8 +940,9 @@ my_snprintf(char *s, size_t size, char const *format, ...)
arglen = n;
}
slen = arglen < size ? arglen : size - 1;
- memcpy(s, arg, slen);
- s[slen] = '\0';
+ cp = s;
+ cp = mempcpy(cp, arg, slen);
+ *cp = '\0';
n = arglen <= INT_MAX ? arglen : -1;
va_end(args);
return n;
@@ -1075,8 +1071,9 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt,
char fbuf[100];
bool oversized = sizeof fbuf <= (size_t)f_prefix_copy_size;
char *f_prefix_copy = oversized ? xmalloc(f_prefix_copy_size) : fbuf;
- memcpy(f_prefix_copy, f, f_prefix_len);
- strcpy(f_prefix_copy + f_prefix_len, "X");
+ char *cp = f_prefix_copy;
+ cp = mempcpy(cp, f, f_prefix_len);
+ strcpy(cp, "X");
formatted_len = strftime(b, s, f_prefix_copy, tm);
if (oversized)
free(f_prefix_copy);
diff --git a/contrib/tzcode/zic.8 b/contrib/tzcode/zic.8
index d83ff7c4a0b1..f7c4e94c665f 100644
--- a/contrib/tzcode/zic.8
+++ b/contrib/tzcode/zic.8
@@ -1,6 +1,6 @@
.\" This file is in the public domain, so clarified as of
.\" 2009-05-17 by Arthur David Olson.
-.Dd January 21, 2023
+.Dd March 8, 2026
.Dt ZIC 8
.Os
.Sh NAME
@@ -13,7 +13,6 @@
.Op Fl Dsv
.Op Fl b Ar slim | fat
.Op Fl d Ar directory
-.Op Fl g Ar gid
.Op Fl l Ar localtime
.Op Fl L Ar leapseconds
.Op Fl m Ar mode
@@ -25,7 +24,7 @@
.Oc
.Op Fl R @ Ns Ar hi
.Op Fl t Ar localtime-link
-.Op Fl u Ar uid
+.Op Fl u Ar owner Ns Op Li : Ns Ar group
.Op Ar filename ...
.Sh DESCRIPTION
The
@@ -54,7 +53,7 @@ is
.Cm fat ,
generate additional data entries that work around potential bugs or
incompatibilities in older software, such as software that mishandles
-the 64-bit generated data.
+a TZif file's 64-bit data or proleptic TZ string.
If
.Ar bloat
is
@@ -63,13 +62,18 @@ keep the output files small; this can help check for the bugs
and incompatibilities.
The default is
.Cm slim ,
-as software that mishandles 64-bit data typically
-mishandles timestamps after the year 2038 anyway.
+as the
+.Cm fat
+workarounds are typically good only until the year 2038 anyway.
Also see the
.Fl r
option for another way to alter output size.
.It Fl D
-Do not create directories.
+Do not create ancestor directories of output files,
+For example, for a zone named America/Los_Angeles
+the directory America should already exist.
+By default, the directory and its ancestors are created
+if they do not already exist.
.It Fl d Ar directory
Create time conversion information files in the named directory rather than
in the standard directory named below.
@@ -93,18 +97,10 @@ any already-existing link is removed.
.It Fl L Ar filename
Read leap second information from the file with the given name.
If this option is not used,
-no leap second information appears in output files.
+no leap second information appears in output files;
+this is required by some TZif readers.
.It Fl p Ar timezone
-Use
-.Ar timezone 's
-rules when handling nonstandard
-TZ strings like
-.Dq "EET\-2EEST"
-that lack transition rules.
-The
-.Nm
-utility
-will act as if the input contained a link line of the form
+Act as if the input contained a link line of the form
.Bd -literal -offset indent
Link \fItimezone\fP posixrules
.Ed
@@ -119,13 +115,33 @@ Unless
.Ar timezone
is
.Dq "\-" ,
-this option is obsolete and poorly supported.
+this option is obsolete and is no longer supported by most runtimes.
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
if
.Ar timezone 's
transitions are at standard time or Universal Time (UT) instead of local time.
+The option is present only to support obsolete runtimes that used
+.Ar timezone 's
+rules when handling obsolescent
+TZ strings like "AST4ADT" that lack transition rules;
+modern runtimes that support these TZ strings
+typically just use current US rules
+as the TZ strings were mainly used in the US.
+Similarly, any Zone or Link named "posixrules" is obsolete and problematic.
+.It Fl m Ar mode
+Create TZif files with the given file mode bits.
+By default the files are created with mode 644 as modified by the umask.
+With this option they are created with the given mode instead.
+For portability the mode should be an unsigned octal integer,
+typically 644 or 444;
+some platforms also support
+.Xr chmod 1 -style
+symbolic modes.
+This option does not affect created ancestor directories,
+which have mode 755 as modified by the umask.
+The option is ignored on platforms lacking the notion of file mode bits.
.It Fl r Oo @ Ns Ar lo Oc Ns Oo /@ Ns Ar hi Oc
Limit the applicability of output files
to timestamps in the range from
@@ -177,6 +193,18 @@ it increases the size of the altered output files.
.It Fl t Ar file
When creating local time information, put the configuration link in
the named file rather than in the standard location.
+.It Fl u Ar owner Ns Op Li : Ns Ar group
+Change the output regular files' owner and group to those specified.
+The
+.Ar owner
+is either a user name, or an unsigned decimal integer user ID,
+or an empty string meaning no change to the owner.
+The
+.Ar group
+is similar for group names and IDs.
+This option does not affect directories or hard or symbolic links.
+It typically needs special privileges to change ownership,
+and is ignored on platforms that lack the notions of owners and groups.
.It Fl v
Be more verbose, and complain about the following situations:
.Bl -bullet
@@ -283,8 +311,10 @@ zero or more lines, each ending in a newline byte and containing at
most 2048 bytes counting the newline, and without any NUL bytes.
The input text's encoding
is typically UTF-8 or ASCII; it should have a unibyte representation
-for the POSIX Portable Character Set (PPCS)
-\*<https://pubs\*:.opengroup\*:.org/\*:onlinepubs/\*:9699919799/\*:basedefs/\*:V1_chap06\*:.html\*>
+for the
+.UR https://\:pubs\:.opengroup\:.org/\:onlinepubs/\:9799919799/\:basedefs/\:V1_chap06\:.html
+POSIX Portable Character Set (PPCS)
+.UE
and the encoding's non-unibyte characters should consist entirely of
non-PPCS bytes.
Non-PPCS characters typically occur only in comments:
@@ -319,12 +349,12 @@ A name can be abbreviated by omitting all but an initial prefix; any
abbreviation must be unambiguous in context.
.Pp
A rule line has the form
-.Bd -literal -offset indent
+.Bd -literal
Rule NAME FROM TO \- IN ON AT SAVE LETTER/S
.Ed
.Pp
For example:
-.Bd -literal -offset indent
+.Bd -literal
Rule US 1967 1973 \- Apr lastSun 2:00w 1:00d D
.Ed
.Pp
@@ -663,11 +693,14 @@ Zone America/Menominee -5:00 - EST 1973 Apr 29 2:00
-6:00 US C%sT
.Ed
Here, an incorrect reading would be there were two clock changes on 1973-04-29,
-the first from 02:00 EST (\-05) to 01:00 CST (\-06),
-and the second an hour later from 02:00 CST (\-06) to 03:00 CDT (\-05).
+the first from 02:00 EST (\-05) to 01:00 CST (\-06) according to the
+.q "until"
+value in the zone line,
+and the second an hour later from 02:00 CST (\-06) to 03:00 CDT (\-05)
+according to the values in the April rule line.
However,
.Nm
-interprets this more sensibly as a single transition from 02:00 CST (\-05) to
+interprets this more sensibly as a single transition from 02:00 EST (\-05) to
02:00 CDT (\-05).
.Pp
A link line has the form
diff --git a/contrib/tzcode/zic.c b/contrib/tzcode/zic.c
index 80902ce534a1..d1084b4a25e9 100644
--- a/contrib/tzcode/zic.c
+++ b/contrib/tzcode/zic.c
@@ -18,6 +18,10 @@
#include "tzfile.h"
#include <fcntl.h>
+#ifndef O_BINARY
+# define O_BINARY 0 /* MS-Windows */
+#endif
+
#include <locale.h>
#include <signal.h>
#include <stdarg.h>
@@ -27,8 +31,8 @@ typedef int_fast64_t zic_t;
static zic_t const
ZIC_MIN = INT_FAST64_MIN,
ZIC_MAX = INT_FAST64_MAX,
- ZIC32_MIN = -1 - (zic_t) 0x7fffffff,
- ZIC32_MAX = 0x7fffffff;
+ ZIC32_MIN = -1 - (zic_t) TWO_31_MINUS_1,
+ ZIC32_MAX = TWO_31_MINUS_1;
#define SCNdZIC SCNdFAST64
#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
@@ -44,8 +48,8 @@ enum { FORMAT_LEN_GROWTH_BOUND = 5 };
#ifdef HAVE_DIRECT_H
# include <direct.h>
# include <io.h>
-# undef mkdir
# define mkdir(name, mode) _mkdir(name)
+typedef unsigned short gid_t, mode_t, uid_t;
#endif
#ifndef HAVE_GETRANDOM
@@ -61,13 +65,94 @@ enum { FORMAT_LEN_GROWTH_BOUND = 5 };
# include <sys/random.h>
#endif
+
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
-#ifdef S_IRUSR
-# define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
+
+#ifndef S_IRWXU
+# define S_IRUSR 0400
+# define S_IWUSR 0200
+# define S_IXUSR 0100
+# define S_IRGRP 0040
+# define S_IWGRP 0020
+# define S_IXGRP 0010
+# define S_IROTH 0004
+# define S_IWOTH 0002
+# define S_IXOTH 0001
+# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+#endif
+
+/* All file permission bits. */
+#define ALL_PERMS (S_IRWXU | S_IRWXG | S_IRWXO)
+
+/* Troublesome file permission bits. */
+#define TROUBLE_PERMS (S_IWGRP | S_IWOTH)
+
+/* File permission bits for making directories.
+ The umask modifies these bits. */
+#define MKDIR_PERMS (ALL_PERMS & ~TROUBLE_PERMS)
+
+/* File permission bits for making regular files.
+ The umask modifies these bits. */
+#define CREAT_PERMS (MKDIR_PERMS & ~(S_IXUSR | S_IXGRP | S_IXOTH))
+static mode_t creat_perms = CREAT_PERMS;
+
+#ifndef HAVE_PWD_H
+# ifdef __has_include
+# if __has_include(<pwd.h>) && __has_include(<grp.h>)
+# define HAVE_PWD_H 1
+# else
+# define HAVE_PWD_H 0
+# endif
+# endif
+#endif
+#ifndef HAVE_PWD_H
+# define HAVE_PWD_H 1
+#endif
+#if HAVE_PWD_H
+# include <grp.h>
+# include <pwd.h>
#else
-# define MKDIR_UMASK 0755
+struct group { gid_t gr_gid; };
+struct passwd { uid_t pw_uid; };
+# define getgrnam(arg) NULL
+# define getpwnam(arg) NULL
+# define fchown(fd, owner, group) ((fd) < 0 ? -1 : 0)
+#endif
+static gid_t const no_gid = -1;
+static uid_t const no_uid = -1;
+static gid_t output_group = -1;
+static uid_t output_owner = -1;
+#ifndef GID_T_MAX
+# define GID_T_MAX_NO_PADDING MAXVAL(gid_t, TYPE_BIT(gid_t))
+# if HAVE__GENERIC
+# define GID_T_MAX \
+ (TYPE_SIGNED(gid_t) \
+ ? _Generic((gid_t) 0, \
+ signed char: SCHAR_MAX, short: SHRT_MAX, \
+ int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \
+ default: GID_T_MAX_NO_PADDING) \
+ : (gid_t) -1)
+# else
+# define GID_T_MAX GID_T_MAX_NO_PADDING
+# endif
+#endif
+#ifndef UID_T_MAX
+# define UID_T_MAX_NO_PADDING MAXVAL(uid_t, TYPE_BIT(uid_t))
+# if HAVE__GENERIC
+# define UID_T_MAX \
+ (TYPE_SIGNED(uid_t) \
+ ? _Generic((uid_t) 0, \
+ signed char: SCHAR_MAX, short: SHRT_MAX, \
+ int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \
+ default: UID_T_MAX_NO_PADDING) \
+ : (uid_t) -1)
+# else
+# define UID_T_MAX UID_T_MAX_NO_PADDING
+# endif
#endif
/* The minimum alignment of a type, for pre-C23 platforms.
@@ -79,6 +164,11 @@ enum { FORMAT_LEN_GROWTH_BOUND = 5 };
# include <stdalign.h>
#endif
+/* The name used for the file implementing the obsolete -p option. */
+#ifndef TZDEFRULES
+# define TZDEFRULES "posixrules"
+#endif
+
/* The maximum length of a text line, including the trailing newline. */
#ifndef _POSIX2_LINE_MAX
# define _POSIX2_LINE_MAX 2048
@@ -144,14 +234,6 @@ struct zone {
zic_t z_untiltime;
};
-#if !HAVE_POSIX_DECLS
-extern int getopt(int argc, char * const argv[],
- const char * options);
-extern int link(const char * target, const char * linkname);
-extern char * optarg;
-extern int optind;
-#endif
-
#if ! HAVE_SYMLINK
static ssize_t
readlink(char const *restrict file, char *restrict buf, size_t size)
@@ -167,8 +249,8 @@ symlink(char const *target, char const *linkname)
}
#endif
#ifndef AT_SYMLINK_FOLLOW
-# define linkat(targetdir, target, linknamedir, linkname, flag) \
- (errno = ENOTSUP, -1)
+# define linkat(targetdir, target, linknamedir, linkname, flag) \
+ (errno = ENOTSUP, -1)
#endif
static void addtt(zic_t starttime, int type);
@@ -194,16 +276,22 @@ static char lowerit(char);
static void mkdirs(char const *, bool);
static void newabbr(const char * abbr);
static zic_t oadd(zic_t t1, zic_t t2);
+static zic_t omul(zic_t, zic_t);
static void outzone(const struct zone * zp, ptrdiff_t ntzones);
static zic_t rpytime(const struct rule * rp, zic_t wantedy);
static bool rulesub(struct rule * rp,
const char * loyearp, const char * hiyearp,
const char * typep, const char * monthp,
const char * dayp, const char * timep);
-static void setgroup(gid_t *flag, const char *name);
-static void setuser(uid_t *flag, const char *name);
static zic_t tadd(zic_t t1, zic_t t2);
+/* Is C an ASCII digit? */
+static bool
+is_digit(char c)
+{
+ return '0' <= c && c <= '9';
+}
+
/* Bound on length of what %z can expand to. */
enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
@@ -211,7 +299,8 @@ static int charcnt;
static bool errors;
static bool warnings;
static int filenum;
-static int leapcnt;
+static ptrdiff_t leapcnt;
+static ptrdiff_t leap_alloc;
static bool leapseen;
static zic_t leapminyear;
static zic_t leapmaxyear;
@@ -221,6 +310,7 @@ static int max_format_len;
static zic_t max_year;
static zic_t min_year;
static bool noise;
+static bool skip_mkdir;
static int rfilenum;
static lineno rlinenum;
static const char * progname;
@@ -451,9 +541,11 @@ static unsigned char desigidx[TZ_MAX_TYPES];
static bool ttisstds[TZ_MAX_TYPES];
static bool ttisuts[TZ_MAX_TYPES];
static char chars[TZ_MAX_CHARS];
-static zic_t trans[TZ_MAX_LEAPS];
-static zic_t corr[TZ_MAX_LEAPS];
-static char roll[TZ_MAX_LEAPS];
+static struct {
+ zic_t trans;
+ zic_t corr;
+ char roll;
+} *leap;
/*
** Memory allocation.
@@ -472,7 +564,8 @@ size_overflow(void)
memory_exhausted(_("size overflow"));
}
-ATTRIBUTE_PURE_114833 static ptrdiff_t
+ATTRIBUTE_PURE_114833_HACK
+static ptrdiff_t
size_sum(size_t a, size_t b)
{
#ifdef ckd_add
@@ -486,7 +579,8 @@ size_sum(size_t a, size_t b)
size_overflow();
}
-ATTRIBUTE_PURE_114833 static ptrdiff_t
+ATTRIBUTE_PURE_114833_HACK
+static ptrdiff_t
size_product(ptrdiff_t nitems, ptrdiff_t itemsize)
{
#ifdef ckd_mul
@@ -501,10 +595,11 @@ size_product(ptrdiff_t nitems, ptrdiff_t itemsize)
size_overflow();
}
-ATTRIBUTE_PURE_114833 static ptrdiff_t
+ATTRIBUTE_PURE_114833_HACK
+static ptrdiff_t
align_to(ptrdiff_t size, ptrdiff_t alignment)
{
- size_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits);
+ ptrdiff_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits);
return sum & ~lo_bits;
}
@@ -645,14 +740,96 @@ warning(const char *const string, ...)
warnings = true;
}
-/* Close STREAM. If it had an I/O error, report it against DIR/NAME,
- remove TEMPNAME if nonnull, and then exit. */
+/* Convert ARG, a string in base BASE, to an unsigned long value no
+ greater than MAXVAL. On failure, diagnose with MSGID and exit. */
+static unsigned long
+arg2num(char const *arg, int base, unsigned long maxval, char const *msgid)
+{
+ unsigned long n;
+ char *ep;
+ errno = 0;
+ n = strtoul(arg, &ep, base);
+ if (ep == arg || *ep || maxval < n || errno) {
+ fprintf(stderr, _(msgid), progname, arg);
+ exit(EXIT_FAILURE);
+ }
+ return n;
+}
+
+#ifndef MODE_T_MAX
+# define MODE_T_MAX_NO_PADDING MAXVAL(mode_t, TYPE_BIT(mode_t))
+# if HAVE__GENERIC
+# define MODE_T_MAX \
+ (TYPE_SIGNED(mode_t) \
+ ? _Generic((mode_t) 0, \
+ signed char: SCHAR_MAX, short: SHRT_MAX, \
+ int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \
+ default: MODE_T_MAX_NO_PADDING) \
+ : (mode_t) -1)
+# else
+# define MODE_T_MAX MODE_T_MAX_NO_PADDING
+# endif
+#endif
+
+#ifndef HAVE_FCHMOD
+# define HAVE_FCHMOD 1
+#endif
+#if !HAVE_FCHMOD
+# define fchmod(fd, mode) 0
+#endif
+
+#ifndef HAVE_SETMODE
+# if (defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
+ || (defined __APPLE__ && defined __MACH__))
+# define HAVE_SETMODE 1
+# else
+# define HAVE_SETMODE 0
+# endif
+#endif
+
+static mode_t const no_mode = -1;
+static mode_t output_mode = -1;
+
+static mode_t
+mode_option(char const *arg)
+{
+#if HAVE_SETMODE
+ void *set = setmode(arg);
+ if (set) {
+ mode_t mode = getmode(set, CREAT_PERMS);
+ free(set);
+ return mode;
+ }
+#endif
+ return arg2num(arg, 8, min(MODE_T_MAX, ULONG_MAX),
+ N_("%s: -m '%s': invalid mode\n"));
+}
+
+static int
+chmetadata(FILE *stream)
+{
+ if (output_owner != no_uid || output_group != no_gid) {
+ int r = fchown(fileno(stream), output_owner, output_group);
+ if (r < 0)
+ return r;
+ }
+ return output_mode == no_mode ? 0 : fchmod(fileno(stream), output_mode);
+}
+
+/* Close STREAM.
+ If it had an I/O error, report it against DIR/NAME,
+ remove TEMPNAME if nonnull, and then exit.
+ If TEMPNAME is nonnull, and if requested,
+ change the stream's metadata before closing. */
static void
close_file(FILE *stream, char const *dir, char const *name,
char const *tempname)
{
char const *e = (ferror(stream) ? _("I/O error")
- : fclose(stream) != 0 ? strerror(errno) : NULL);
+ : ((tempname
+ && (fflush(stream) < 0 || chmetadata(stream) < 0))
+ || fclose(stream) < 0)
+ ? strerror(errno) : NULL);
if (e) {
if (name && *name == '/')
dir = NULL;
@@ -661,20 +838,27 @@ close_file(FILE *stream, char const *dir, char const *name,
name ? name : "", name ? ": " : "",
e);
if (tempname)
- (void)remove(tempname);
+ remove(tempname);
exit(EXIT_FAILURE);
}
}
ATTRIBUTE_NORETURN static void
+duplicate_options(char const *opt)
+{
+ fprintf(stderr, _("%s: More than one %s option specified\n"), progname, opt);
+ exit(EXIT_FAILURE);
+}
+
+ATTRIBUTE_NORETURN static void
usage(FILE *stream, int status)
{
fprintf(stream,
_("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
- "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]"
- " [ -L leapseconds ] \\\n"
- "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R '@hi' ] \\\n"
- "\t[ -t localtime-link ] [ -D ] [ -g gid ] [ -u uid ] \\\n"
+ "\t[ -b {slim|fat} ] [ -d directory ] [ -D ] \\\n"
+ "\t[ -l localtime ] [ -L leapseconds ] [ -m mode ] \\\n"
+ "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R @hi ] \\\n"
+ "\t[ -t localtime-link ] [ -u 'owner[:group]' ] \\\n"
"\t[ filename ... ]\n\n"
"Report bugs to %s.\n"),
progname, progname, REPORT_BUGS_TO);
@@ -683,6 +867,71 @@ usage(FILE *stream, int status)
exit(status);
}
+static void
+group_option(char const *arg)
+{
+ if (*arg) {
+ if (output_group != no_gid) {
+ fprintf(stderr, _("multiple groups specified"));
+ exit(EXIT_FAILURE);
+ } else {
+ struct group *gr = getgrnam(arg);
+ output_group = (gr ? gr->gr_gid
+ : arg2num(arg, 10, min(GID_T_MAX, ULONG_MAX),
+ N_("%s: invalid group: %s\n")));
+ }
+ }
+}
+
+static void
+owner_option(char const *arg)
+{
+ if (*arg) {
+ if (output_owner != no_uid) {
+ fprintf(stderr, _("multiple owners specified"));
+ exit(EXIT_FAILURE);
+ } else {
+ struct passwd *pw = getpwnam(arg);
+ output_owner = (pw ? pw->pw_uid
+ : arg2num(arg, 10, min(UID_T_MAX, ULONG_MAX),
+ N_("%s: invalid owner: %s\n")));
+ }
+ }
+}
+
+/* If setting owner or group, use temp file permissions that avoid
+ security races before the fchmod at the end. */
+static void
+use_safe_temp_permissions(void)
+{
+ if (output_owner != no_uid || output_group != no_gid) {
+
+ /* The mode when done with the file. */
+ mode_t omode;
+ if (output_mode == no_mode) {
+ mode_t cmask = umask(0);
+ umask(cmask);
+ omode = CREAT_PERMS & ~cmask;
+ } else
+ omode = output_mode;
+
+ /* The mode passed to open+O_CREAT. Do not bother with executable
+ permissions, as they should not be used and this mode is merely
+ a nicety (even a mode of 0 still work). */
+ creat_perms = ((((omode & (S_IRUSR | S_IRGRP | S_IROTH))
+ == (S_IRUSR | S_IRGRP | S_IROTH))
+ ? S_IRUSR | S_IRGRP | S_IROTH : 0)
+ | (((omode & (S_IWUSR | S_IWGRP | S_IWOTH))
+ == (S_IWUSR | S_IWGRP | S_IWOTH))
+ ? S_IWUSR | S_IWGRP | S_IWOTH : 0));
+
+ /* If creat_perms is not the final mode, arrange to run
+ fchmod later, even if -m was not used. */
+ if (creat_perms != omode)
+ output_mode = omode;
+ }
+}
+
/* Change the working directory to DIR, possibly creating DIR and its
ancestors. After this is done, all files are accessed with names
relative to DIR. */
@@ -955,12 +1204,6 @@ redundant_time_option(char *opt)
static const char * psxrules;
static const char * lcltime;
static const char * directory;
-static const char * leapsec;
-static int Dflag;
-static uid_t uflag = (uid_t)-1;
-static gid_t gflag = (gid_t)-1;
-static mode_t mflag = (S_IRUSR | S_IRGRP | S_IROTH
- | S_IWUSR);
static const char * tzdefault;
/* True if DIRECTORY ends in '/'. */
@@ -988,9 +1231,6 @@ main(int argc, char **argv)
register ptrdiff_t i, j;
bool timerange_given = false;
-#ifdef S_IWGRP
- umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
-#endif
#if HAVE_GETTEXT
setlocale(LC_ALL, "");
# ifdef TZ_DOMAINDIR
@@ -1013,14 +1253,10 @@ main(int argc, char **argv)
} else if (strcmp(argv[k], "--help") == 0) {
usage(stdout, EXIT_SUCCESS);
}
- while ((c = getopt(argc, argv, "Db:d:g:l:L:m:p:r:R:st:u:vy:")) != EOF
- && c != -1)
+ while ((c = getopt(argc, argv, "b:d:Dg:l:L:m:p:r:R:st:u:vy:")) != -1)
switch (c) {
default:
usage(stderr, EXIT_FAILURE);
- case 'D':
- Dflag = 1;
- break;
case 'b':
if (strcmp(optarg, "slim") == 0) {
if (0 < bloat)
@@ -1034,91 +1270,65 @@ main(int argc, char **argv)
error(_("invalid option: -b '%s'"), optarg);
break;
case 'd':
- if (directory == NULL)
- directory = optarg;
- else {
- fprintf(stderr,
- _("%s: More than one -d option"
- " specified\n"),
- progname);
- return EXIT_FAILURE;
- }
+ if (directory)
+ duplicate_options("-d");
+ directory = optarg;
+ break;
+ case 'D':
+ skip_mkdir = true;
break;
case 'g':
- setgroup(&gflag, optarg);
+ /* This undocumented option is present for
+ compatibility with FreeBSD 14. */
+ group_option(optarg);
break;
case 'l':
- if (lcltime == NULL)
- lcltime = optarg;
- else {
- fprintf(stderr,
- _("%s: More than one -l option"
- " specified\n"),
- progname);
- return EXIT_FAILURE;
- }
+ if (lcltime)
+ duplicate_options("-l");
+ lcltime = optarg;
break;
case 'm':
- {
- void *set = setmode(optarg);
- if (set == NULL) {
- fprintf(stderr,
-_("invalid file mode"));
- return EXIT_FAILURE;
- }
- mflag = getmode(set, mflag);
- free(set);
+ if (output_mode != no_mode)
+ duplicate_options("-m");
+ output_mode = mode_option(optarg);
break;
- }
case 'p':
- if (psxrules == NULL)
- psxrules = optarg;
- else {
- fprintf(stderr,
- _("%s: More than one -p option"
- " specified\n"),
- progname);
- return EXIT_FAILURE;
- }
+ if (psxrules)
+ duplicate_options("-p");
+ if (strcmp(optarg, "-") != 0)
+ warning(_("-p is obsolete"
+ " and likely ineffective"));
+ psxrules = optarg;
break;
case 't':
- if (tzdefault != NULL) {
- fprintf(stderr,
- _("%s: More than one -t option"
- " specified\n"),
- progname);
- return EXIT_FAILURE;
- }
+ if (tzdefault)
+ duplicate_options("-t");
tzdefault = optarg;
break;
case 'u':
- setuser(&uflag, optarg);
+ {
+ char *colon = strchr(optarg, ':');
+ if (colon)
+ *colon = '\0';
+ owner_option(optarg);
+ if (colon)
+ group_option(colon + 1);
+ }
break;
case 'y':
warning(_("-y ignored"));
break;
case 'L':
- if (leapsec == NULL)
- leapsec = optarg;
- else {
- fprintf(stderr,
- _("%s: More than one -L option"
- " specified\n"),
- progname);
- return EXIT_FAILURE;
- }
+ if (leapsec)
+ duplicate_options("-L");
+ leapsec = optarg;
break;
case 'v':
noise = true;
break;
case 'r':
- if (timerange_given) {
- fprintf(stderr,
- _("%s: More than one -r option"
- " specified\n"),
- progname);
- return EXIT_FAILURE;
- }
+ if (timerange_given)
+ duplicate_options("-r");
if (! timerange_option(optarg)) {
fprintf(stderr,
_("%s: invalid time range: %s\n"),
@@ -1170,6 +1380,7 @@ _("invalid file mode"));
if (errors)
return EXIT_FAILURE;
associate();
+ use_safe_temp_permissions();
change_directory(directory);
directory_ends_in_slash = directory[strlen(directory) - 1] == '/';
catch_signals();
@@ -1359,10 +1570,10 @@ random_dirent(char const **name, char **namealloc)
uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6);
if (!dst) {
- dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
- memcpy(dst, src, dirlen);
- memcpy(dst + dirlen, prefix, prefixlen);
- dst[dirlen + prefixlen + suffixlen] = '\0';
+ char *cp = dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
+ cp = mempcpy(cp, src, dirlen);
+ cp = mempcpy(cp, prefix, prefixlen);
+ cp[suffixlen] = '\0';
*name = *namealloc = dst;
}
@@ -1399,13 +1610,6 @@ diagslash(char const *filename)
static FILE *
open_outfile(char const **outname, char **tempname)
{
-#if __STDC_VERSION__ < 201112
- static char const fopen_mode[] = "wb";
-#else
- static char const fopen_mode[] = "wbx";
-#endif
-
- FILE *fp;
bool dirs_made = false;
if (!*tempname)
random_dirent(outname, tempname);
@@ -1418,22 +1622,31 @@ open_outfile(char const **outname, char **tempname)
exit(EXIT_FAILURE);
}
- while (! (fp = fopen(*outname, fopen_mode))) {
- int fopen_errno = errno;
- if (fopen_errno == ENOENT && !dirs_made) {
+ while (true) {
+ int oflags = O_WRONLY | O_BINARY | O_CREAT | O_EXCL;
+ int fd = open(*outname, oflags, creat_perms);
+ int err;
+ if (fd < 0)
+ err = errno;
+ else {
+ FILE *fp = fdopen(fd, "wb");
+ if (fp)
+ return fp;
+ err = errno;
+ close(fd);
+ }
+ if (err == ENOENT && !dirs_made) {
mkdirs(*outname, true);
dirs_made = true;
- } else if (fopen_errno == EEXIST)
+ } else if (err == EEXIST)
random_dirent(outname, tempname);
else {
fprintf(stderr, _("%s: Can't create %s%s%s: %s\n"),
progname, diagdir(*outname), diagslash(*outname), *outname,
- strerror(fopen_errno));
+ strerror(err));
exit(EXIT_FAILURE);
}
}
-
- return fp;
}
/* If TEMPNAME, the result is in the temporary file TEMPNAME even
@@ -1470,15 +1683,17 @@ relname(char const *target, char const *linkname)
if (*linkname == '/') {
/* Make F absolute too. */
size_t len = strlen(directory);
- size_t lenslash = len + (len && directory[len - 1] != '/');
+ bool needs_slash = len && directory[len - 1] != '/';
+ size_t lenslash = len + needs_slash;
size_t targetsize = strlen(target) + 1;
+ char *cp;
if (*directory != '/')
return NULL;
linksize = size_sum(lenslash, targetsize);
- f = result = xmalloc(linksize);
- memcpy(result, directory, len);
- result[len] = '/';
- memcpy(result + lenslash, target, targetsize);
+ f = cp = result = xmalloc(linksize);
+ cp = mempcpy(cp, directory, len);
+ *cp = '/';
+ memcpy(cp + needs_slash, target, targetsize);
}
for (i = 0; f[i] && f[i] == linkname[i]; i++)
if (f[i] == '/')
@@ -1488,11 +1703,13 @@ relname(char const *target, char const *linkname)
taillen = strlen(f + dir_len);
dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1);
if (dotdotetcsize <= linksize) {
+ char *cp;
if (!result)
result = xmalloc(dotdotetcsize);
+ cp = result;
for (i = 0; i < dotdots; i++)
- memcpy(result + 3 * i, "../", 3);
- memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
+ cp = mempcpy(cp, "../", 3);
+ memmove(cp, f + dir_len, taillen + 1);
}
return result;
}
@@ -1500,7 +1717,8 @@ relname(char const *target, char const *linkname)
/* Return true if A and B must have the same parent dir if A and B exist.
Return false if this is not necessarily true (though it might be true).
Keep it simple, and do not inspect the file system. */
-ATTRIBUTE_PURE_114833 static bool
+ATTRIBUTE_PURE_114833
+static bool
same_parent_dirs(char const *a, char const *b)
{
for (; *a == *b; a++, b++)
@@ -1860,7 +2078,7 @@ gethms(char const *string, char const *errstring)
&hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) {
default: ok = false; break;
case 8:
- ok = '0' <= xr && xr <= '9';
+ ok = is_digit(xr);
ATTRIBUTE_FALLTHROUGH;
case 7:
ok &= ssx == '.';
@@ -1882,15 +2100,11 @@ gethms(char const *string, char const *errstring)
error("%s", errstring);
return 0;
}
- if (ZIC_MAX / SECSPERHOUR < hh) {
- error(_("time overflow"));
- return 0;
- }
ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */
if (noise && (hh > HOURSPERDAY ||
(hh == HOURSPERDAY && (mm != 0 || ss != 0))))
warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
- return oadd(sign * hh * SECSPERHOUR,
+ return oadd(omul(hh, sign * SECSPERHOUR),
sign * (mm * SECSPERMIN + ss));
}
@@ -1915,7 +2129,7 @@ getsave(char *field, bool *isdst)
static void
inrule(char **fields, int nfields)
{
- struct rule r = { 0 };
+ struct rule r;
if (nfields != RULE_FIELDS) {
error(_("wrong number of fields on Rule line"));
@@ -1992,7 +2206,7 @@ inzsub(char **fields, int nfields, bool iscont)
{
register char * cp;
char * cp1;
- struct zone z = { 0 };
+ struct zone z;
int format_len;
register int i_stdoff, i_rule, i_format;
register int i_untilyear, i_untilmonth;
@@ -2050,10 +2264,6 @@ inzsub(char **fields, int nfields, bool iscont)
z.z_untiltime = rpytime(&z.z_untilrule,
z.z_untilrule.r_loyear);
if (iscont && nzones > 0 &&
- z.z_untiltime > min_time &&
- z.z_untiltime < max_time &&
- zones[nzones - 1].z_untiltime > min_time &&
- zones[nzones - 1].z_untiltime < max_time &&
zones[nzones - 1].z_untiltime >= z.z_untiltime) {
error(_("Zone continuation line end time is"
" not after end time of previous line"));
@@ -2135,15 +2345,7 @@ getleapdatetime(char **fields, bool expire_line)
return -1;
}
dayoff = oadd(dayoff, day - 1);
- if (dayoff < min_time / SECSPERDAY) {
- error(_("time too small"));
- return -1;
- }
- if (dayoff > max_time / SECSPERDAY) {
- error(_("time too large"));
- return -1;
- }
- t = dayoff * SECSPERDAY;
+ t = omul(dayoff, SECSPERDAY);
tod = gethms(fields[LP_TIME], _("invalid time of day"));
t = tadd(t, tod);
if (t < 0)
@@ -2403,7 +2605,7 @@ atcomp(const void *avp, const void *bvp)
struct timerange {
int defaulttype;
ptrdiff_t base, count;
- int leapbase, leapcount;
+ ptrdiff_t leapbase, leapcount;
bool leapexpiry;
};
@@ -2423,13 +2625,13 @@ limitrange(struct timerange r, zic_t lo, zic_t hi,
positive leap second if and only if it has a positive correction.
This supports common TZif readers that assume that the first leap
second is positive if and only if its correction is positive. */
- while (1 < r.leapcount && trans[r.leapbase + 1] <= lo) {
+ while (1 < r.leapcount && leap[r.leapbase + 1].trans <= lo) {
r.leapcount--;
r.leapbase++;
}
while (0 < r.leapbase
- && ((corr[r.leapbase - 1] < corr[r.leapbase])
- != (0 < corr[r.leapbase]))) {
+ && ((leap[r.leapbase - 1].corr < leap[r.leapbase].corr)
+ != (0 < leap[r.leapbase].corr))) {
r.leapcount++;
r.leapbase--;
}
@@ -2439,7 +2641,7 @@ limitrange(struct timerange r, zic_t lo, zic_t hi,
if (hi < max_time) {
while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
r.count--;
- while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1])
+ while (0 < r.leapcount && hi + 1 < leap[r.leapbase + r.leapcount - 1].trans)
r.leapcount--;
}
@@ -2476,7 +2678,7 @@ writezone(const char *const name, const char *const string, char version,
if (timecnt > 1)
qsort(attypes, timecnt, sizeof *attypes, atcomp);
/*
- ** Optimize.
+ ** Optimize and skip unwanted transitions.
*/
{
ptrdiff_t fromi, toi;
@@ -2484,16 +2686,28 @@ writezone(const char *const name, const char *const string, char version,
toi = 0;
fromi = 0;
for ( ; fromi < timecnt; ++fromi) {
- if (toi != 0
- && ((attypes[fromi].at
+ if (toi != 0) {
+ /* Skip the previous transition if it is unwanted
+ because its local time is not earlier.
+ The UT offset additions can't overflow because
+ of how the times were calculated. */
+ unsigned char type_2 =
+ toi == 1 ? 0 : attypes[toi - 2].type;
+ if ((attypes[fromi].at
+ utoffs[attypes[toi - 1].type])
- <= (attypes[toi - 1].at
- + utoffs[toi == 1 ? 0
- : attypes[toi - 2].type]))) {
+ <= attypes[toi - 1].at + utoffs[type_2]) {
+ if (attypes[fromi].type == type_2)
+ toi--;
+ else
attypes[toi - 1].type =
attypes[fromi].type;
- continue;
+ continue;
+ }
}
+
+ /* Use a transition if it is the first one,
+ or if it cannot be merged for other reasons,
+ or if it transitions to different timekeeping. */
if (toi == 0
|| attypes[fromi].dontmerge
|| (utoffs[attypes[toi - 1].type]
@@ -2507,14 +2721,19 @@ writezone(const char *const name, const char *const string, char version,
timecnt = toi;
}
- if (noise && timecnt > 1200) {
- if (timecnt > TZ_MAX_TIMES)
+ if (noise) {
+ if (1200 < timecnt) {
+ if (TZ_MAX_TIMES < timecnt)
warning(_("reference clients mishandle"
" more than %d transition times"),
TZ_MAX_TIMES);
- else
+ else
warning(_("pre-2014 clients may mishandle"
" more than 1200 transition times"));
+ }
+ if (TZ_MAX_LEAPS < leapcnt)
+ warning(_("reference clients mishandle more than %d leap seconds"),
+ TZ_MAX_LEAPS);
}
/*
** Transfer.
@@ -2530,8 +2749,8 @@ writezone(const char *const name, const char *const string, char version,
for (i = 0; i < timecnt; ++i) {
j = leapcnt;
while (--j >= 0)
- if (ats[i] > trans[j] - corr[j]) {
- ats[i] = tadd(ats[i], corr[j]);
+ if (leap[j].trans - leap[j].corr < ats[i]) {
+ ats[i] = tadd(ats[i], leap[j].corr);
break;
}
}
@@ -2560,7 +2779,7 @@ writezone(const char *const name, const char *const string, char version,
version = '4';
}
if (0 < r->leapcount
- && corr[r->leapbase] != 1 && corr[r->leapbase] != -1) {
+ && leap[r->leapbase].corr != 1 && leap[r->leapbase].corr != -1) {
if (noise)
warning(_("%s: pre-2021b clients may mishandle"
" leap second table truncation"),
@@ -2575,7 +2794,7 @@ writezone(const char *const name, const char *const string, char version,
for (pass = 1; pass <= 2; ++pass) {
register ptrdiff_t thistimei, thistimecnt, thistimelim;
- register int thisleapi, thisleapcnt, thisleaplim;
+ register ptrdiff_t thisleapi, thisleapcnt, thisleaplim;
struct tzhead tzh;
int pretranstype = -1, thisdefaulttype;
bool locut, hicut, thisleapexpiry;
@@ -2780,6 +2999,11 @@ writezone(const char *const name, const char *const string, char version,
continue;
}
+ if (pass == 2 && noise && 50 < thischarcnt)
+ warning(_("%s: pre-2026 reference clients mishandle"
+ " more than 50 bytes of abbreviations"),
+ name);
+
/* Output a LO_TIME transition if needed; see limitrange.
But do not go below the minimum representable value
for this pass. */
@@ -2815,8 +3039,8 @@ writezone(const char *const name, const char *const string, char version,
for (i = thisleapi; i < thisleaplim; ++i) {
register zic_t todo;
- if (roll[i]) {
- if (timecnt == 0 || trans[i] < ats[0]) {
+ if (leap[i].roll) {
+ if (timecnt == 0 || leap[i].trans < ats[0]) {
j = 0;
while (isdsts[j])
if (++j >= typecnt) {
@@ -2826,14 +3050,14 @@ writezone(const char *const name, const char *const string, char version,
} else {
j = 1;
while (j < timecnt &&
- trans[i] >= ats[j])
+ ats[j] <= leap[i].trans)
++j;
j = types[j - 1];
}
- todo = tadd(trans[i], -utoffs[j]);
- } else todo = trans[i];
+ todo = tadd(leap[i].trans, -utoffs[j]);
+ } else todo = leap[i].trans;
puttzcodepass(todo, fp, pass);
- puttzcode(corr[i], fp);
+ puttzcode(leap[i].corr, fp);
}
if (thisleapexpiry) {
/* Append a no-op leap correction indicating when the leap
@@ -2842,7 +3066,7 @@ writezone(const char *const name, const char *const string, char version,
the plan is to amend the RFC to allow this in version 4
TZif files. */
puttzcodepass(leapexpires, fp, pass);
- puttzcode(thisleaplim ? corr[thisleaplim - 1] : 0, fp);
+ puttzcode(thisleaplim ? leap[thisleaplim - 1].corr : 0, fp);
}
if (stdcnt != 0)
for (i = old0; i < typecnt; i++)
@@ -2855,17 +3079,6 @@ writezone(const char *const name, const char *const string, char version,
}
fprintf(fp, "\n%s\n", string);
close_file(fp, directory, name, tempname);
- if (chmod(tempname, mflag) < 0) {
- fprintf(stderr, _("cannot change mode of %s to %03o"),
- tempname, (unsigned)mflag);
- exit(EXIT_FAILURE);
- }
- if ((uflag != (uid_t)-1 || gflag != (gid_t)-1)
- && chown(tempname, uflag, gflag) < 0) {
- fprintf(stderr, _("cannot change ownership of %s"),
- tempname);
- exit(EXIT_FAILURE);
- }
rename_dest(tempname, name);
free(ats);
}
@@ -2913,11 +3126,10 @@ doabbr(char *abbr, struct zone const *zp, char const *letters,
bool isdst, zic_t save, bool doquotes)
{
register char * cp;
- register char * slashp;
ptrdiff_t len;
char const *format = zp->z_format;
+ char const *slashp = strchr(format, '/');
- slashp = strchr(format, '/');
if (slashp == NULL) {
char letterbuf[PERCENT_Z_LEN_BOUND + 1];
if (zp->z_format_specifier == 'z')
@@ -2927,11 +3139,11 @@ doabbr(char *abbr, struct zone const *zp, char const *letters,
else if (letters == disable_percent_s)
return 0;
sprintf(abbr, format, letters);
- } else if (isdst) {
- strcpy(abbr, slashp + 1);
- } else {
- memcpy(abbr, format, slashp - format);
- abbr[slashp - format] = '\0';
+ } else if (isdst)
+ strcpy(abbr, slashp + 1);
+ else {
+ char *abbrend = mempcpy(abbr, format, slashp - format);
+ *abbrend = '\0';
}
len = strlen(abbr);
if (!doquotes)
@@ -3391,9 +3603,6 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
if (!r->r_todisstd)
offset = oadd(offset, save);
jtime = r->r_temp;
- if (jtime == min_time ||
- jtime == max_time)
- continue;
jtime = tadd(jtime, -offset);
if (k < 0 || jtime < ktime) {
k = j;
@@ -3573,7 +3782,8 @@ addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
{
register int i, j;
- if (! (-1L - 2147483647L <= utoff && utoff <= 2147483647L)) {
+ /* RFC 9636 section 3.2 specifies this range for utoff. */
+ if (! (-TWO_31_MINUS_1 <= utoff && utoff <= TWO_31_MINUS_1)) {
error(_("UT offset out of range"));
exit(EXIT_FAILURE);
}
@@ -3612,32 +3822,27 @@ addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
static void
leapadd(zic_t t, int correction, int rolling)
{
- register int i;
+ register ptrdiff_t i;
- if (TZ_MAX_LEAPS <= leapcnt) {
- error(_("too many leap seconds"));
- exit(EXIT_FAILURE);
- }
if (rolling && (lo_time != min_time || hi_time != max_time)) {
error(_("Rolling leap seconds not supported with -r"));
exit(EXIT_FAILURE);
}
+ leap = growalloc(leap, sizeof *leap, leapcnt, &leap_alloc);
for (i = 0; i < leapcnt; ++i)
- if (t <= trans[i])
+ if (t <= leap[i].trans)
break;
- memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans);
- memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr);
- memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll);
- trans[i] = t;
- corr[i] = correction;
- roll[i] = rolling;
+ memmove(&leap[i + 1], &leap[i], (leapcnt - i) * sizeof *leap);
+ leap[i].trans = t;
+ leap[i].corr = correction;
+ leap[i].roll = rolling;
++leapcnt;
}
static void
adjleap(void)
{
- register int i;
+ register ptrdiff_t i;
register zic_t last = 0;
register zic_t prevtrans = 0;
@@ -3645,18 +3850,18 @@ adjleap(void)
** propagate leap seconds forward
*/
for (i = 0; i < leapcnt; ++i) {
- if (trans[i] - prevtrans < 28 * SECSPERDAY) {
+ if (leap[i].trans - prevtrans < 28 * SECSPERDAY) {
error(_("Leap seconds too close together"));
exit(EXIT_FAILURE);
}
- prevtrans = trans[i];
- trans[i] = tadd(trans[i], last);
- last = corr[i] += last;
+ prevtrans = leap[i].trans;
+ leap[i].trans = tadd(prevtrans, last);
+ last = leap[i].corr += last;
}
if (0 <= leapexpires) {
leapexpires = oadd(leapexpires, last);
- if (! (leapcnt == 0 || (trans[leapcnt - 1] < leapexpires))) {
+ if (! (leapcnt == 0 || (leap[leapcnt - 1].trans < leapexpires))) {
error(_("last Leap time does not precede Expires time"));
exit(EXIT_FAILURE);
}
@@ -3714,7 +3919,8 @@ lowerit(char a)
}
/* case-insensitive equality */
-ATTRIBUTE_PURE_114833 static bool
+ATTRIBUTE_PURE_114833
+static bool
ciequal(register const char *ap, register const char *bp)
{
while (lowerit(*ap) == lowerit(*bp++))
@@ -3723,7 +3929,8 @@ ciequal(register const char *ap, register const char *bp)
return false;
}
-ATTRIBUTE_PURE_114833 static bool
+ATTRIBUTE_PURE_114833
+static bool
itsabbr(register const char *abbr, register const char *word)
{
if (lowerit(*abbr) != lowerit(*word))
@@ -3739,7 +3946,8 @@ itsabbr(register const char *abbr, register const char *word)
/* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
-ATTRIBUTE_PURE_114833 static bool
+ATTRIBUTE_PURE_114833
+static bool
ciprefix(char const *abbr, char const *word)
{
do
@@ -3849,7 +4057,9 @@ time_overflow(void)
exit(EXIT_FAILURE);
}
-ATTRIBUTE_PURE_114833 static zic_t
+/* Return T1 + T2, but diagnose any overflow and exit. */
+ATTRIBUTE_PURE_114833_HACK
+static zic_t
oadd(zic_t t1, zic_t t2)
{
#ifdef ckd_add
@@ -3863,25 +4073,41 @@ oadd(zic_t t1, zic_t t2)
time_overflow();
}
-ATTRIBUTE_PURE_114833 static zic_t
+/* Return T1 + T2, but diagnose any overflow and exit.
+ This is like oadd, except the result must fit in min_time..max_time range,
+ which on oddball machines can be a smaller range than ZIC_MIN..ZIC_MAX. */
+ATTRIBUTE_PURE_114833_HACK
+static zic_t
tadd(zic_t t1, zic_t t2)
{
-#ifdef ckd_add
- zic_t sum;
- if (!ckd_add(&sum, t1, t2) && min_time <= sum && sum <= max_time)
+ zic_t sum = oadd(t1, t2);
+ if (min_time <= sum && sum <= max_time)
return sum;
+ time_overflow();
+}
+
+/* Return T1 * T2, but diagnose any overflow and exit. */
+ATTRIBUTE_PURE_114833_HACK
+static zic_t
+omul(zic_t t1, zic_t t2)
+{
+#ifdef ckd_mul
+ zic_t product;
+ if (!ckd_mul(&product, t1, t2))
+ return product;
#else
- if (t1 < 0 ? min_time - t1 <= t2 : t2 <= max_time - t1)
- return t1 + t2;
+ if (t2 < 0
+ ? ZIC_MAX / t2 <= t1 && (t2 == -1 || t1 <= ZIC_MIN / t2)
+ : t2 == 0 || (ZIC_MIN / t2 <= t1 && t1 <= ZIC_MAX / t2))
+ return t1 * t2;
#endif
- if (t1 == min_time || t1 == max_time)
- return t1;
time_overflow();
}
/*
** Given a rule, and a year, compute the date (in seconds since January 1,
** 1970, 00:00 LOCAL time) in that year that the rule refers to.
+** Do not count leap seconds. On error, diagnose and exit.
*/
static zic_t
@@ -3892,10 +4118,6 @@ rpytime(const struct rule *rp, zic_t wantedy)
register zic_t t, y;
int yrem;
- if (wantedy == ZIC_MIN)
- return min_time;
- if (wantedy == ZIC_MAX)
- return max_time;
m = TM_JANUARY;
y = EPOCH_YEAR;
@@ -3953,11 +4175,7 @@ rpytime(const struct rule *rp, zic_t wantedy)
will not work with pre-2004 versions of zic"));
}
}
- if (dayoff < min_time / SECSPERDAY)
- return min_time;
- if (dayoff > max_time / SECSPERDAY)
- return max_time;
- t = (zic_t) dayoff * SECSPERDAY;
+ t = omul(dayoff, SECSPERDAY);
return tadd(t, rp->r_tod);
}
@@ -3972,7 +4190,7 @@ newabbr(const char *string)
cp = string;
mp = NULL;
- while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
+ while (is_alpha(*cp) || is_digit(*cp)
|| *cp == '-' || *cp == '+')
++cp;
if (noise && cp - string < 3)
@@ -3984,7 +4202,7 @@ mp = _("time zone abbreviation differs from POSIX standard");
if (mp != NULL)
warning("%s (%s)", mp, string);
}
- i = strlen(string) + 1;
+ i = strnlen(string, TZ_MAX_CHARS - charcnt) + 1;
if (charcnt + i > TZ_MAX_CHARS) {
error(_("too many, or too long, time zone abbreviations"));
exit(EXIT_FAILURE);
@@ -4000,13 +4218,10 @@ mp = _("time zone abbreviation differs from POSIX standard");
static void
mkdirs(char const *argname, bool ancestors)
{
- /*
- * If -D was specified, do not create directories. A subsequent
- * file operation will fail and produce an appropriate error
- * message.
- */
- if (Dflag)
- return;
+ /* If -D was specified, do not create directories.
+ If a file operation's parent directory is missing,
+ the operation will fail and be diagnosed. */
+ if (!skip_mkdir) {
char *name = xstrdup(argname);
char *cp = name;
@@ -4032,7 +4247,7 @@ mkdirs(char const *argname, bool ancestors)
** not check first whether it already exists, as that
** is checked anyway if the mkdir fails.
*/
- if (mkdir(name, MKDIR_UMASK) != 0) {
+ if (mkdir(name, MKDIR_PERMS) < 0) {
/* Do not report an error if err == EEXIST, because
some other process might have made the directory
in the meantime. Likewise for ENOSYS, because
@@ -4054,63 +4269,5 @@ mkdirs(char const *argname, bool ancestors)
*cp++ = '/';
}
free(name);
+ }
}
-
-#include <grp.h>
-#include <pwd.h>
-
-static void
-setgroup(gid_t *flag, const char *name)
-{
- struct group *gr;
-
- if (*flag != (gid_t)-1) {
- fprintf(stderr, _("multiple -g flags specified"));
- exit(EXIT_FAILURE);
- }
-
- gr = getgrnam(name);
- if (gr == 0) {
- char *ep;
- unsigned long ul;
-
- ul = strtoul(name, &ep, 10);
- if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
- *flag = ul;
- return;
- }
- fprintf(stderr, _("group `%s' not found"), name);
- exit(EXIT_FAILURE);
- }
- *flag = gr->gr_gid;
-}
-
-static void
-setuser(uid_t *flag, const char *name)
-{
- struct passwd *pw;
-
- if (*flag != (gid_t)-1) {
- fprintf(stderr, _("multiple -u flags specified"));
- exit(EXIT_FAILURE);
- }
-
- pw = getpwnam(name);
- if (pw == 0) {
- char *ep;
- unsigned long ul;
-
- ul = strtoul(name, &ep, 10);
- if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
- *flag = ul;
- return;
- }
- fprintf(stderr, _("user `%s' not found"), name);
- exit(EXIT_FAILURE);
- }
- *flag = pw->pw_uid;
-}
-
-/*
-** UNIX was a registered trademark of The Open Group in 2003.
-*/