Import tzcode 2024b

This commit is contained in:
Dag-Erling Smørgrav 2024-09-06 14:22:49 +02:00
parent 378c74faf3
commit e66ca70de4
26 changed files with 1276 additions and 954 deletions

View file

@ -23,10 +23,10 @@ such as renaming, adding or removing zones, please read
"Theory and pragmatics of the tz code and data"
<https://www.iana.org/time-zones/repository/theory.html>.
It is also good to browse the mailing list archives
<https://mm.icann.org/pipermail/tz/> for examples of patches that tend
to work well. Additions to data should contain commentary citing
reliable sources as justification. Citations should use "https:" URLs
if available.
<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.
For changes that fix sensitive security-related bugs, please see the
distribution's 'SECURITY' file.
@ -63,12 +63,16 @@ If you use Git the following workflow may be helpful:
* Edit source files. Include commentary that justifies the
changes by citing reliable sources.
* Debug the changes, e.g.:
* Debug the changes locally, e.g.:
make check
make install
make TOPDIR=$PWD/tz clean check install
./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.
* For each separable change, commit it in the new branch, e.g.:
git add northamerica

412
Makefile
View file

@ -3,17 +3,17 @@
# 2009-05-17 by Arthur David Olson.
# Request POSIX conformance; this must be the first non-comment line.
.POSIX:
# On older platforms you may need to scrounge for a POSIX-conforming 'make'.
# For example, on Solaris 10 (2005), use /usr/sfw/bin/gmake or
# /usr/xpg4/bin/make, not /usr/ccs/bin/make.
# 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'.
# To affect how this Makefile works, you can run a shell script like this:
#
# #!/bin/sh
# make CC='gcc -std=gnu11' "$@"
# make CC='gcc -std=gnu23' "$@"
#
# This example script is appropriate for a pre-2017 GNU/Linux system
# where a non-default setting is needed to support this package's use of C99.
# 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.
#
# Alternatively, you can simply edit this Makefile to tailor the following
# macro definitions.
@ -53,7 +53,7 @@ DATAFORM= main
LOCALTIME= Factory
# The POSIXRULES macro controls interpretation of POSIX-2017.1-like TZ
# 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:
@ -132,8 +132,9 @@ LIBDIR = $(TOPDIR)/$(USRDIR)/lib
# Types to try, as an alternative to time_t.
TIME_T_ALTERNATIVES = $(TIME_T_ALTERNATIVES_HEAD) $(TIME_T_ALTERNATIVES_TAIL)
TIME_T_ALTERNATIVES_HEAD = int_least64_t
TIME_T_ALTERNATIVES_TAIL = int_least32_t uint_least32_t uint_least64_t
TIME_T_ALTERNATIVES_HEAD = int_least64_t.ck
TIME_T_ALTERNATIVES_TAIL = int_least32_t.ck uint_least32_t.ck \
uint_least64_t.ck
# What kind of TZif data files to generate. (TZif is the binary time
# zone data format that zic generates; see Internet RFC 8536.)
@ -219,6 +220,7 @@ LDLIBS=
# than what POSIX specifies, assuming local time is UT.
# For example, N is 252460800 on AmigaOS.
# -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)
@ -229,7 +231,7 @@ LDLIBS=
# where LDLIBS also needs to contain -lintl on some hosts;
# -DHAVE_GETTEXT=0 to avoid using gettext
# -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares
# ctime_r and asctime_r incompatibly with the POSIX standard
# 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_LINK=0 if your system lacks a link function
@ -261,8 +263,11 @@ LDLIBS=
# -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers
# with external linkage, e.g., applications cannot define 'localtime'.
# -Dssize_t=long on hosts like MS-Windows that lack ssize_t
# -DSUPPORT_C89 if the tzcode library should support C89 callers+
# However, this might trigger latent bugs in C99-or-later callers.
# -DSUPPORT_C89=0 if the tzcode library should not support C89 callers
# Although -DSUPPORT_C89=0 might work around latent bugs in callers,
# it does not conform to POSIX.
# -DSUPPORT_POSIX2008 if the library should support older POSIX callers+
# However, this might cause problems in POSIX.1-2024-or-later callers.
# -DSUPPRESS_TZDIR to not prepend TZDIR to file names; this has
# security implications and is not recommended for general use
# -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires;
@ -274,7 +279,7 @@ LDLIBS=
# -DTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory;
# the default is system-supplied, typically "/usr/lib/locale"
# -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified
# DST transitions for POSIX.1-2017-style TZ strings lacking them,
# 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.
# This mishandles some past timestamps, as US DST rules have changed.
@ -302,23 +307,25 @@ LDLIBS=
#
# * Options marked "*" can be omitted if your compiler is C23 compatible.
# * Options marked "+" are obsolescent and are planned to be removed
# once the code assumes C99 or later, say in the year 2029.
# once the code assumes C99 or later (say in the year 2029)
# and POSIX.1-2024 or later (say in the year 2034).
#
# Select instrumentation via "make GCC_INSTRUMENT='whatever'".
GCC_INSTRUMENT = \
-fsanitize=undefined -fsanitize-address-use-after-scope \
-fsanitize-undefined-trap-on-error -fstack-protector
# Omit -fanalyzer from GCC_DEBUG_FLAGS, as it makes GCC too slow.
GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \
$(GCC_INSTRUMENT) \
-Wall -Wextra \
-Walloc-size-larger-than=100000 -Warray-bounds=2 \
-Wbad-function-cast -Wbidi-chars=any,ucn -Wcast-align=strict -Wdate-time \
-Wdeclaration-after-statement -Wdouble-promotion \
-Wduplicated-branches -Wduplicated-cond \
-Wduplicated-branches -Wduplicated-cond -Wflex-array-member-not-at-end \
-Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \
-Wimplicit-fallthrough=5 -Winit-self -Wlogical-op \
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
-Wmissing-declarations -Wmissing-prototypes \
-Wmissing-variable-declarations -Wnested-externs \
-Wnull-dereference \
-Wold-style-definition -Woverlength-strings -Wpointer-arith \
-Wshadow -Wshift-overflow=2 -Wstrict-overflow \
@ -327,10 +334,9 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
-Wsuggest-attribute=const -Wsuggest-attribute=format \
-Wsuggest-attribute=malloc \
-Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \
-Wtrampolines -Wundef -Wuninitialized -Wunused-macros -Wuse-after-free=3 \
-Wtrampolines -Wundef -Wunused-macros -Wuse-after-free=3 \
-Wvariadic-macros -Wvla -Wwrite-strings \
-Wno-address -Wno-format-nonliteral -Wno-sign-compare \
-Wno-type-limits
-Wno-format-nonliteral -Wno-sign-compare
#
# If your system has a "GMT offset" field in its "struct tm"s
# (or if you decide to add such a field in your system's "time.h" file),
@ -341,9 +347,8 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
# Similarly, if your system has a "zone abbreviation" field, define
# -DTM_ZONE=tm_zone
# and define NO_TM_ZONE to suppress any guessing.
# Although these two fields are not required by POSIX.1-2017,
# POSIX 202x/D4 requires them and they are widely available
# on GNU/Linux and BSD systems.
# Although POSIX.1-2024 requires these fields and they are widely available
# on GNU/Linux and BSD systems, some older systems lack them.
#
# The next batch of options control support for external variables
# exported by tzcode. In practice these variables are less useful
@ -353,7 +358,9 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
# # -DHAVE_TZNAME=0 # do not support "tzname"
# # -DHAVE_TZNAME=1 # support "tzname", which is defined by system library
# # -DHAVE_TZNAME=2 # support and define "tzname"
# # to the "CFLAGS=" line. "tzname" is required by POSIX.1-1988 and later.
# # to the "CFLAGS=" line. Although "tzname" is required by POSIX.1-1988
# # and later, its contents are unspecified if you use a geographical TZ
# # and the variable is planned to be removed in a future POSIX edition.
# # If not defined, the code attempts to guess HAVE_TZNAME from other macros.
# # Warning: unless time_tz is also defined, HAVE_TZNAME=1 can cause
# # crashes when combined with some platforms' standard libraries,
@ -364,7 +371,9 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
# # -DUSG_COMPAT=1 # support, and variables are defined by system library
# # -DUSG_COMPAT=2 # support and define variables
# # to the "CFLAGS=" line; "timezone" and "daylight" are inspired by Unix
# # Systems Group code and are required by POSIX.1-2008 and later (with XSI).
# # Systems Group code and are required by POSIX.1-2008 and later (with XSI),
# # although their contents are unspecified if you use a geographical TZ
# # and the variables are planned to be removed in a future edition of POSIX.
# # If not defined, the code attempts to guess USG_COMPAT from other macros.
# #
# # To support the external variable "altzone", add
@ -428,18 +437,13 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
# The name of a POSIX-like library archiver, its flags, C compiler,
# linker flags, and 'make' utility. Ordinarily the defaults suffice.
# The commented-out values are the defaults specified by POSIX.1-202x/D4.
# The commented-out values are the defaults specified by POSIX.1-2024.
#AR = ar
#ARFLAGS = -rv
#CC = c17
#LDFLAGS =
#MAKE = make
# For leap seconds, this Makefile uses LEAPSECONDS='-L leapseconds' in
# submake command lines. The default is no leap seconds.
LEAPSECONDS=
# Where to fetch leap-seconds.list from.
leaplist_URI = \
https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list
@ -461,7 +465,7 @@ ZFLAGS=
# How to use zic to install TZif files.
ZIC_INSTALL= $(ZIC) -d '$(DESTDIR)$(TZDIR)' $(LEAPSECONDS)
ZIC_INSTALL= $(ZIC) -d '$(DESTDIR)$(TZDIR)'
# The name of a POSIX-compliant 'awk' on your system.
# mawk 1.3.3 and Solaris 10 /usr/bin/awk do not work.
@ -480,6 +484,7 @@ KSHELL= /bin/bash
# Name of curl <https://curl.haxx.se/>, used for HTML validation
# and to fetch leap-seconds.list from upstream.
# Set CURL=: to disable use of the Internet.
CURL= curl
# Name of GNU Privacy Guard <https://gnupg.org/>, used to sign distributions.
@ -533,21 +538,28 @@ OK_LINE= '^'$(OK_CHAR)'*$$'
# Flags to give 'tar' when making a distribution.
# Try to use flags appropriate for GNU tar.
GNUTARFLAGS= --format=pax --pax-option='delete=atime,delete=ctime' \
GNUTARFLAGS= --format=pax --pax-option=delete=atime,delete=ctime \
--numeric-owner --owner=0 --group=0 \
--mode=go+u,go-w --sort=name
TARFLAGS= `if tar $(GNUTARFLAGS) --version >/dev/null 2>&1; \
then echo $(GNUTARFLAGS); \
else :; \
fi`
SETUP_TAR= \
export LC_ALL=C && \
if tar $(GNUTARFLAGS) --version >/dev/null 2>&1; then \
TAR='tar $(GNUTARFLAGS)'; \
else \
TAR=tar; \
fi
# Flags to give 'gzip' when making a distribution.
GZIPFLAGS= -9n
# When comparing .tzs files, use GNU diff's -F'^TZ=' option if supported.
# This makes it easier to see which Zone has been affected.
DIFF_TZS= diff -u$$(! diff -u -F'^TZ=' - - <>/dev/null >&0 2>&1 \
|| echo ' -F^TZ=')
SETUP_DIFF_TZS = \
if diff -u -F'^TZ=' - - <>/dev/null >&0 2>&1; then \
DIFF_TZS='diff -u -F^TZ='; \
else \
DIFF_TZS='diff -u'; \
fi
# ':' on typical hosts; 'ranlib' on the ancient hosts that still need ranlib.
RANLIB= :
@ -561,8 +573,8 @@ RANLIB= :
TZCOBJS= zic.o
TZDOBJS= zdump.o localtime.o asctime.o strftime.o
DATEOBJS= date.o localtime.o strftime.o asctime.o
TZDOBJS= zdump.o localtime.o strftime.o
DATEOBJS= date.o localtime.o strftime.o
LIBSRCS= localtime.c asctime.c difftime.c strftime.c
LIBOBJS= localtime.o asctime.o difftime.o strftime.o
HEADERS= tzfile.h private.h
@ -579,8 +591,7 @@ MANTXTS= newctime.3.txt newstrftime.3.txt newtzset.3.txt \
COMMON= calendars CONTRIBUTING LICENSE Makefile \
NEWS README SECURITY theory.html version
WEB_PAGES= tz-art.html tz-how-to.html tz-link.html
CHECK_WEB_PAGES=check_theory.html check_tz-art.html \
check_tz-how-to.html check_tz-link.html
CHECK_WEB_PAGES=theory.ck tz-art.ck tz-how-to.ck tz-link.ck
DOCS= $(MANS) date.1 $(MANTXTS) $(WEB_PAGES)
PRIMARY_YDATA= africa antarctica asia australasia \
europe northamerica southamerica
@ -641,8 +652,7 @@ install: all $(DATA) $(REDO) $(MANS)
'$(DESTDIR)$(MANDIR)/man3' '$(DESTDIR)$(MANDIR)/man5' \
'$(DESTDIR)$(MANDIR)/man8'
$(ZIC_INSTALL) -l $(LOCALTIME) \
`case '$(POSIXRULES)' in ?*) echo '-p';; esac \
` $(POSIXRULES) \
-p $(POSIXRULES) \
-t '$(DESTDIR)$(TZDEFAULT)'
cp -f $(TABDATA) '$(DESTDIR)$(TZDIR)/.'
cp tzselect '$(DESTDIR)$(BINDIR)/.'
@ -665,10 +675,10 @@ INSTALL: ALL install date.1
# and append "-dirty" if the contents do not already end in "-dirty".
version: $(VERSION_DEPS)
{ (type git) >/dev/null 2>&1 && \
V=`git describe --match '[0-9][0-9][0-9][0-9][a-z]*' \
--abbrev=7 --dirty` || \
if test '$(VERSION)' = unknown && V=`cat $@`; then \
case $$V in *-dirty);; *) V=$$V-dirty;; esac; \
V=$$(git describe --match '[0-9][0-9][0-9][0-9][a-z]*' \
--abbrev=7 --dirty) || \
if test '$(VERSION)' = unknown && read -r V <$@; then \
V=$${V%-dirty}-dirty; \
else \
V='$(VERSION)'; \
fi; } && \
@ -678,7 +688,7 @@ version: $(VERSION_DEPS)
# These files can be tailored by setting BACKWARD, PACKRATDATA, PACKRATLIST.
vanguard.zi main.zi rearguard.zi: $(DSTDATA_ZI_DEPS)
$(AWK) \
-v DATAFORM=`expr $@ : '\(.*\).zi'` \
-v DATAFORM=$(@:.zi=) \
-v PACKRATDATA='$(PACKRATDATA)' \
-v PACKRATLIST='$(PACKRATLIST)' \
-f ziguard.awk \
@ -687,7 +697,7 @@ vanguard.zi main.zi rearguard.zi: $(DSTDATA_ZI_DEPS)
# This file has a version comment that attempts to capture any tailoring
# via BACKWARD, DATAFORM, PACKRATDATA, PACKRATLIST, and REDO.
tzdata.zi: $(DATAFORM).zi version zishrink.awk
version=`sed 1q version` && \
read -r version <version && \
LC_ALL=C $(AWK) \
-v dataform='$(DATAFORM)' \
-v deps='$(DSTDATA_ZI_DEPS) zishrink.awk' \
@ -708,7 +718,7 @@ tzdir.h:
mv $@.out $@
version.h: version
VERSION=`cat version` && printf '%s\n' \
read -r VERSION <version && printf '%s\n' \
'static char const PKGVERSION[]="($(PACKAGE)) ";' \
"static char const TZVERSION[]=\"$$VERSION\";" \
'static char const REPORT_BUGS_TO[]="$(BUGEMAIL)";' \
@ -748,12 +758,11 @@ commit-leap-seconds.list: fetch-leap-seconds.list
git commit --author="$$author" --date="$$date" -m'make $@' \
leap-seconds.list
# Arguments to pass to submakes of install_data.
# Arguments to pass to submakes.
# They can be overridden by later submake arguments.
INSTALLARGS = \
BACKWARD='$(BACKWARD)' \
DESTDIR='$(DESTDIR)' \
LEAPSECONDS='$(LEAPSECONDS)' \
PACKRATDATA='$(PACKRATDATA)' \
PACKRATLIST='$(PACKRATLIST)' \
TZDEFAULT='$(TZDEFAULT)' \
@ -762,16 +771,11 @@ INSTALLARGS = \
INSTALL_DATA_DEPS = zic leapseconds tzdata.zi
# 'make install_data' installs one set of TZif files.
install_data: $(INSTALL_DATA_DEPS)
posix_only: $(INSTALL_DATA_DEPS)
$(ZIC_INSTALL) tzdata.zi
posix_only: $(INSTALL_DATA_DEPS)
$(MAKE) $(INSTALLARGS) LEAPSECONDS= install_data
right_only: $(INSTALL_DATA_DEPS)
$(MAKE) $(INSTALLARGS) LEAPSECONDS='-L leapseconds' \
install_data
$(ZIC_INSTALL) -L leapseconds tzdata.zi
# In earlier versions of this makefile, the other two directories were
# subdirectories of $(TZDIR). However, this led to configuration errors.
@ -802,8 +806,7 @@ ZDS = dummy.zd
# Rule used only by submakes invoked by the $(TZS_NEW) rule.
# It is separate so that GNU 'make -j' can run instances in parallel.
$(ZDS): zdump
./zdump -i $(TZS_CUTOFF_FLAG) '$(wd)/'$$(expr $@ : '\(.*\).zd') \
>$@
./zdump -i $(TZS_CUTOFF_FLAG) "$$PWD/$(@:.zd=)" >$@
TZS_NEW_DEPS = tzdata.zi zdump zic
$(TZS_NEW): $(TZS_NEW_DEPS)
@ -812,20 +815,19 @@ $(TZS_NEW): $(TZS_NEW_DEPS)
$(zic) -d tzs$(TZS_YEAR).dir tzdata.zi
$(AWK) '/^L/{print "Link\t" $$2 "\t" $$3}' \
tzdata.zi | LC_ALL=C sort >$@.out
wd=`pwd` && \
x=`$(AWK) '/^Z/{print "tzs$(TZS_YEAR).dir/" $$2 ".zd"}' \
x=$$($(AWK) '/^Z/{print "tzs$(TZS_YEAR).dir/" $$2 ".zd"}' \
tzdata.zi \
| LC_ALL=C sort -t . -k 2,2` && \
| LC_ALL=C sort -t . -k 2,2) && \
set x $$x && \
shift && \
ZDS=$$* && \
$(MAKE) wd="$$wd" TZS_CUTOFF_FLAG="$(TZS_CUTOFF_FLAG)" \
$(MAKE) TZS_CUTOFF_FLAG="$(TZS_CUTOFF_FLAG)" \
ZDS="$$ZDS" $$ZDS && \
sed 's,^TZ=".*\.dir/,TZ=",' $$ZDS >>$@.out
rm -fr tzs$(TZS_YEAR).dir
mv $@.out $@
# If $(TZS) exists but 'make check_tzs' fails, a maintainer should inspect the
# If $(TZS) exists but 'make tzs.ck' fails, a maintainer should inspect the
# failed output and fix the inconsistency, perhaps by running 'make force_tzs'.
$(TZS):
touch $@
@ -842,7 +844,7 @@ date: $(DATEOBJS)
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DATEOBJS) $(LDLIBS)
tzselect: tzselect.ksh version
VERSION=`cat version` && sed \
read -r VERSION <version && sed \
-e "s'#!/bin/bash'#!"'$(KSHELL)'\' \
-e s\''\(AWK\)=[^}]*'\''\1=\'\''$(AWK)\'\'\' \
-e s\''\(PKGVERSION\)=.*'\''\1=\'\''($(PACKAGE)) \'\'\' \
@ -853,11 +855,11 @@ tzselect: tzselect.ksh version
chmod +x $@.out
mv $@.out $@
check: check_back check_mild
check_mild: check_character_set check_white_space check_links \
check_name_lengths check_now \
check_slashed_abbrs check_sorted \
check_tables check_web check_ziguard check_zishrink check_tzs
check: check_mild back.ck
check_mild: check_web check_zishrink \
character-set.ck white-space.ck links.ck mainguard.ck \
name-lengths.ck now.ck slashed-abbrs.ck sorted.ck \
tables.ck ziguard.ck tzs.ck
# True if UTF8_LOCALE does not work;
# otherwise, false but with LC_ALL set to $(UTF8_LOCALE).
@ -865,9 +867,9 @@ UTF8_LOCALE_MISSING = \
{ test ! '$(UTF8_LOCALE)' \
|| ! printf 'A\304\200B\n' \
| LC_ALL='$(UTF8_LOCALE)' grep -q '^A.B$$' >/dev/null 2>&1 \
|| { LC_ALL='$(UTF8_LOCALE)'; export LC_ALL; false; }; }
|| { export LC_ALL='$(UTF8_LOCALE)'; false; }; }
check_character_set: $(ENCHILADA)
character-set.ck: $(ENCHILADA)
$(UTF8_LOCALE_MISSING) || { \
sharp='#' && \
! grep -Env $(SAFE_LINE) $(MANS) date.1 $(MANTXTS) \
@ -882,48 +884,55 @@ check_character_set: $(ENCHILADA)
}
touch $@
check_white_space: $(ENCHILADA)
white-space.ck: $(ENCHILADA)
$(UTF8_LOCALE_MISSING) || { \
patfmt=' \t|[\f\r\v]' && pat=`printf "$$patfmt\\n"` && \
enchilada='$(ENCHILADA)' && \
patfmt=' \t|[\f\r\v]' && pat=$$(printf "$$patfmt\\n") && \
! grep -En "$$pat|[$s]\$$" \
$$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list); \
$${enchilada%leap-seconds.list*} \
$${enchilada#*leap-seconds.list}; \
}
touch $@
PRECEDES_FILE_NAME = ^(Zone|Link[$s]+[^$s]+)[$s]+
FILE_NAME_COMPONENT_TOO_LONG = $(PRECEDES_FILE_NAME)[^$s]*[^/$s]{15}
check_name_lengths: $(TDATA_TO_CHECK) backzone
! grep -En '$(FILE_NAME_COMPONENT_TOO_LONG)' \
name-lengths.ck: $(TDATA_TO_CHECK) backzone
:;! grep -En '$(FILE_NAME_COMPONENT_TOO_LONG)' \
$(TDATA_TO_CHECK) backzone
touch $@
mainguard.ck: main.zi
test '$(PACKRATLIST)' || \
cat $(TDATA) $(PACKRATDATA) | diff -u - main.zi
touch $@
PRECEDES_STDOFF = ^(Zone[$s]+[^$s]+)?[$s]+
STDOFF = [-+]?[0-9:.]+
RULELESS_SAVE = (-|$(STDOFF)[sd]?)
RULELESS_SLASHED_ABBRS = \
$(PRECEDES_STDOFF)$(STDOFF)[$s]+$(RULELESS_SAVE)[$s]+[^$s]*/
check_slashed_abbrs: $(TDATA_TO_CHECK)
! grep -En '$(RULELESS_SLASHED_ABBRS)' $(TDATA_TO_CHECK)
slashed-abbrs.ck: $(TDATA_TO_CHECK)
:;! grep -En '$(RULELESS_SLASHED_ABBRS)' $(TDATA_TO_CHECK)
touch $@
CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; }
check_sorted: backward backzone
sorted.ck: backward backzone
$(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} !/./ {g++}' \
backward | LC_ALL=C sort -cu
$(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu
$(AWK) '/^Zone.*\// {print $$2}' backzone | LC_ALL=C sort -cu
touch $@
check_back: checklinks.awk $(TDATA_TO_CHECK)
back.ck: checklinks.awk $(TDATA_TO_CHECK)
$(AWK) \
-v DATAFORM=$(DATAFORM) \
-v backcheck=backward \
-f checklinks.awk $(TDATA_TO_CHECK)
touch $@
check_links: checklinks.awk tzdata.zi
links.ck: checklinks.awk tzdata.zi
$(AWK) \
-v DATAFORM=$(DATAFORM) \
-f checklinks.awk tzdata.zi
@ -932,26 +941,36 @@ check_links: checklinks.awk tzdata.zi
# Check timestamps from now through 28 years from now, to make sure
# that zonenow.tab contains all sequences of planned timestamps,
# without any duplicate sequences. In theory this might require
# 2800 years but that would take a long time to check.
CHECK_NOW_TIMESTAMP = `./date +%s`
# 2800+ years but that would take a long time to check.
CHECK_NOW_TIMESTAMP = $$(./date +%s)
CHECK_NOW_FUTURE_YEARS = 28
CHECK_NOW_FUTURE_SECS = $(CHECK_NOW_FUTURE_YEARS) '*' 366 '*' 24 '*' 60 '*' 60
check_now: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab
rm -fr $@.dir
mkdir $@.dir
./zic -d $@.dir tzdata.zi
CHECK_NOW_FUTURE_SECS = $(CHECK_NOW_FUTURE_YEARS) * 366 * 24 * 60 * 60
now.ck: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab
rm -fr $@d
mkdir $@d
./zic -d $@d tzdata.zi
now=$(CHECK_NOW_TIMESTAMP) && \
future=`expr $(CHECK_NOW_FUTURE_SECS) + $$now` && \
future=$$(($(CHECK_NOW_FUTURE_SECS) + $$now)) && \
./zdump -i -t $$now,$$future \
$$(find $$PWD/$@.dir/????*/ -type f) \
>$@.dir/zdump.tab
$$(find "$$PWD/$@d"/????*/ -type f) \
>$@d/zdump-now.tab && \
./zdump -i -t 0,$$future \
$$(find "$$PWD/$@d" -name Etc -prune \
-o -type f ! -name '*.tab' -print) \
>$@d/zdump-1970.tab
$(AWK) \
-v zdump_table=$@.dir/zdump.tab \
-v zdump_table=$@d/zdump-now.tab \
-f checknow.awk zonenow.tab
rm -fr $@.dir
$(AWK) \
'BEGIN {print "-\t-\tUTC"} /^Zone/ {print "-\t-\t" $$2}' \
$(PRIMARY_YDATA) backward factory | \
$(AWK) \
-v zdump_table=$@d/zdump-1970.tab \
-f checknow.awk
rm -fr $@d
touch $@
check_tables: checktab.awk $(YDATA) backward zone.tab zone1970.tab
tables.ck: checktab.awk $(YDATA) backward zone.tab zone1970.tab
for tab in $(ZONETABLES); do \
test "$$tab" = zone.tab && links='$(BACKWARD)' || links=''; \
$(AWK) -f checktab.awk -v zone_table=$$tab $(YDATA) $$links \
@ -959,26 +978,24 @@ check_tables: checktab.awk $(YDATA) backward zone.tab zone1970.tab
done
touch $@
check_tzs: $(TZS) $(TZS_NEW)
tzs.ck: $(TZS) $(TZS_NEW)
if test -s $(TZS); then \
$(DIFF_TZS) $(TZS) $(TZS_NEW); \
$(SETUP_DIFF_TZS) && $$DIFF_TZS $(TZS) $(TZS_NEW); \
else \
cp $(TZS_NEW) $(TZS); \
fi
touch $@
check_web: $(CHECK_WEB_PAGES)
check_theory.html: theory.html
check_tz-art.html: tz-art.html
check_tz-how-to.html: tz-how-to.html
check_tz-link.html: tz-link.html
check_theory.html check_tz-art.html check_tz-how-to.html check_tz-link.html:
$(CURL) -sS --url https://validator.w3.org/nu/ -F out=gnu \
-F file=@$$(expr $@ : 'check_\(.*\)') -o $@.out && \
.SUFFIXES: .ck .html
.html.ck:
{ ! ($(CURL) --version) >/dev/null 2>&1 || \
$(CURL) -sS --url https://validator.w3.org/nu/ -F out=gnu \
-F file=@$<; } >$@.out && \
test ! -s $@.out || { cat $@.out; exit 1; }
mv $@.out $@
check_ziguard: rearguard.zi vanguard.zi ziguard.awk
ziguard.ck: rearguard.zi vanguard.zi ziguard.awk
$(AWK) -v DATAFORM=rearguard -f ziguard.awk vanguard.zi | \
diff -u rearguard.zi -
$(AWK) -v DATAFORM=vanguard -f ziguard.awk rearguard.zi | \
@ -987,36 +1004,35 @@ check_ziguard: rearguard.zi vanguard.zi ziguard.awk
# Check that zishrink.awk does not alter the data, and that ziguard.awk
# preserves main-format data.
check_zishrink: check_zishrink_posix check_zishrink_right
check_zishrink_posix check_zishrink_right: \
check_zishrink: zishrink-posix.ck zishrink-right.ck
zishrink-posix.ck zishrink-right.ck: \
zic leapseconds $(PACKRATDATA) $(PACKRATLIST) \
$(TDATA) $(DATAFORM).zi tzdata.zi
rm -fr $@.dir $@-t.dir $@-shrunk.dir
mkdir $@.dir $@-t.dir $@-shrunk.dir
rm -fr $@d t-$@d shrunk-$@d
mkdir $@d t-$@d shrunk-$@d
case $@ in \
*_right) leap='-L leapseconds';; \
*right*) leap='-L leapseconds';; \
*) leap=;; \
esac && \
$(ZIC) $$leap -d $@.dir $(DATAFORM).zi && \
$(ZIC) $$leap -d $@-shrunk.dir tzdata.zi && \
$(ZIC) $$leap -d $@d $(DATAFORM).zi && \
$(ZIC) $$leap -d shrunk-$@d tzdata.zi && \
case $(DATAFORM),$(PACKRATLIST) in \
main,) \
$(ZIC) $$leap -d $@-t.dir $(TDATA) && \
$(ZIC) $$leap -d t-$@d $(TDATA) && \
$(AWK) '/^Rule/' $(TDATA) | \
$(ZIC) $$leap -d $@-t.dir - $(PACKRATDATA) && \
diff -r $@.dir $@-t.dir;; \
$(ZIC) $$leap -d t-$@d - $(PACKRATDATA) && \
diff -r $@d t-$@d;; \
esac
diff -r $@.dir $@-shrunk.dir
rm -fr $@.dir $@-t.dir $@-shrunk.dir
diff -r $@d shrunk-$@d
rm -fr $@d t-$@d shrunk-$@d
touch $@
clean_misc:
rm -fr check_*.dir typecheck_*.dir
rm -f *.o *.out $(TIME_T_ALTERNATIVES) \
check_* core typecheck_* \
rm -fr *.ckd *.dir
rm -f *.ck *.core *.o *.out core core.* \
date tzdir.h tzselect version.h zdump zic libtz.a
clean: clean_misc
rm -fr *.dir tzdb-*/
rm -fr tzdb-*/
rm -f *.zi $(TZS_NEW)
maintainer-clean: clean
@ -1027,7 +1043,7 @@ maintainer-clean: clean
names:
@echo $(ENCHILADA)
public: check check_public $(CHECK_TIME_T_ALTERNATIVES) \
public: check public.ck $(CHECK_TIME_T_ALTERNATIVES) \
tarballs signatures
date.1.txt: date.1
@ -1041,7 +1057,7 @@ zdump.8.txt: zdump.8
zic.8.txt: zic.8
$(MANTXTS): workman.sh
LC_ALL=C sh workman.sh `expr $@ : '\(.*\)\.txt$$'` >$@.out
LC_ALL=C sh workman.sh $(@:.txt=) >$@.out
mv $@.out $@
# Set file timestamps deterministically if possible,
@ -1054,13 +1070,13 @@ SET_TIMESTAMP_N = sh -c '\
n=$$0 dest=$$1; shift; \
<"$$dest" && \
if test $$n != 0 && \
lsout=`ls -nt --time-style="+%s" "$$@" 2>/dev/null`; then \
lsout=$$(ls -nt --time-style="+%s" "$$@" 2>/dev/null); then \
set x $$lsout && \
timestamp=`expr $$7 + $$n` && \
timestamp=$$(($$7 + $$n)) && \
echo "+ touch -md @$$timestamp $$dest" && \
touch -md @$$timestamp "$$dest"; \
else \
newest=`ls -t "$$@" | sed 1q` && \
newest=$$(ls -t "$$@" | sed 1q) && \
echo "+ touch -mr $$newest $$dest" && \
touch -mr "$$newest" "$$dest"; \
fi'
@ -1083,15 +1099,15 @@ SET_TIMESTAMP_DEP = $(SET_TIMESTAMP_N) 1
set-timestamps.out: $(EIGHT_YARDS)
rm -f $@
if (type git) >/dev/null 2>&1 && \
files=`git ls-files $(EIGHT_YARDS)` && \
files=$$(git ls-files $(EIGHT_YARDS)) && \
touch -md @1 test.out; then \
rm -f test.out && \
for file in $$files; do \
if git diff --quiet $$file; then \
time=`TZ=UTC0 git log -1 \
time=$$(TZ=UTC0 git log -1 \
--format='tformat:%cd' \
--date='format:%Y-%m-%dT%H:%M:%SZ' \
$$file` && \
$$file) && \
echo "+ touch -md $$time $$file" && \
touch -md $$time $$file; \
else \
@ -1100,8 +1116,8 @@ set-timestamps.out: $(EIGHT_YARDS)
done; \
fi
$(SET_TIMESTAMP_DEP) leapseconds $(LEAP_DEPS)
for file in `ls $(MANTXTS) | sed 's/\.txt$$//'`; do \
$(SET_TIMESTAMP_DEP) $$file.txt $$file workman.sh || \
for file in $(MANTXTS); do \
$(SET_TIMESTAMP_DEP) $$file $${file%.txt} workman.sh || \
exit; \
done
$(SET_TIMESTAMP_DEP) version $(VERSION_DEPS)
@ -1114,30 +1130,29 @@ set-tzs-timestamp.out: $(TZS)
# The zics below ensure that each data file can stand on its own.
# We also do an all-files run to catch links to links.
check_public: $(VERSION_DEPS)
rm -fr public.dir
mkdir public.dir
ln $(VERSION_DEPS) public.dir
cd public.dir \
public.ck: $(VERSION_DEPS)
rm -fr $@d
mkdir $@d
ln $(VERSION_DEPS) $@d
cd $@d \
&& $(MAKE) CFLAGS='$(GCC_DEBUG_FLAGS)' TZDIR='$(TZDIR)' ALL
for i in $(TDATA_TO_CHECK) public.dir/tzdata.zi \
public.dir/vanguard.zi public.dir/main.zi \
public.dir/rearguard.zi; \
for i in $(TDATA_TO_CHECK) \
tzdata.zi vanguard.zi main.zi rearguard.zi; \
do \
public.dir/zic -v -d public.dir/zoneinfo $$i 2>&1 || exit; \
$@d/zic -v -d $@d/zoneinfo $@d/$$i || exit; \
done
public.dir/zic -v -d public.dir/zoneinfo-all $(TDATA_TO_CHECK)
$@d/zic -v -d $@d/zoneinfo-all $(TDATA_TO_CHECK)
:
: Also check 'backzone' syntax.
rm public.dir/main.zi
cd public.dir && $(MAKE) PACKRATDATA=backzone main.zi
public.dir/zic -d public.dir/zoneinfo main.zi
rm public.dir/main.zi
cd public.dir && \
rm $@d/main.zi
cd $@d && $(MAKE) PACKRATDATA=backzone main.zi
$@d/zic -d $@d/zoneinfo main.zi
rm $@d/main.zi
cd $@d && \
$(MAKE) PACKRATDATA=backzone PACKRATLIST=zone.tab main.zi
public.dir/zic -d public.dir/zoneinfo main.zi
$@d/zic -d $@d/zoneinfo main.zi
:
rm -fr public.dir
rm -fr $@d
touch $@
# Check that the code works under various alternative
@ -1145,46 +1160,47 @@ check_public: $(VERSION_DEPS)
check_time_t_alternatives: $(TIME_T_ALTERNATIVES)
$(TIME_T_ALTERNATIVES_TAIL): $(TIME_T_ALTERNATIVES_HEAD)
$(TIME_T_ALTERNATIVES): $(VERSION_DEPS)
rm -fr $@.dir
mkdir $@.dir
ln $(VERSION_DEPS) $@.dir
rm -fr $@d
mkdir $@d
ln $(VERSION_DEPS) $@d
case $@ in \
int*32_t) range=-2147483648,2147483648;; \
*32_t*) range=-2147483648,2147483648;; \
u*) range=0,4294967296;; \
*) range=-4294967296,4294967296;; \
esac && \
wd=`pwd` && \
zones=`$(AWK) '/^[^#]/ { print $$3 }' <zone1970.tab` && \
wd=$$PWD && \
zones=$$($(AWK) '/^[^#]/ { print $$3 }' <zone1970.tab) && \
if test $@ = $(TIME_T_ALTERNATIVES_HEAD); then \
range_target=; \
else \
range_target=to$$range.tzs; \
fi && \
(cd $@.dir && \
$(MAKE) TOPDIR="$$wd/$@.dir" \
CFLAGS='$(CFLAGS) -Dtime_tz='"'$@'" \
(cd $@d && \
$(MAKE) TOPDIR="$$wd/$@d" \
CFLAGS='$(CFLAGS) -Dtime_tz='"'$(@:.ck=)'" \
REDO='$(REDO)' \
D=$$wd/$@.dir \
D="$$wd/$@d" \
TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
install $$range_target) && \
test $@ = $(TIME_T_ALTERNATIVES_HEAD) || { \
(cd $(TIME_T_ALTERNATIVES_HEAD).dir && \
$(MAKE) TOPDIR="$$wd/$@.dir" \
(cd $(TIME_T_ALTERNATIVES_HEAD)d && \
$(MAKE) TOPDIR="$$wd/$@d" \
TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
D=$$wd/$@.dir \
D="$$wd/$@d" \
to$$range.tzs) && \
$(DIFF_TZS) $(TIME_T_ALTERNATIVES_HEAD).dir/to$$range.tzs \
$@.dir/to$$range.tzs && \
$(SETUP_DIFF_TZS) && \
$$DIFF_TZS $(TIME_T_ALTERNATIVES_HEAD)d/to$$range.tzs \
$@d/to$$range.tzs && \
if diff -q Makefile Makefile 2>/dev/null; then \
quiet_option='-q'; \
else \
quiet_option=''; \
fi && \
diff $$quiet_option -r $(TIME_T_ALTERNATIVES_HEAD).dir/etc \
$@.dir/etc && \
diff $$quiet_option -r $(TIME_T_ALTERNATIVES_HEAD)d/etc \
$@d/etc && \
diff $$quiet_option -r \
$(TIME_T_ALTERNATIVES_HEAD).dir/usr/share \
$@.dir/usr/share; \
$(TIME_T_ALTERNATIVES_HEAD)d/usr/share \
$@d/usr/share; \
}
touch $@
@ -1199,7 +1215,7 @@ ALL_ASC = $(TRADITIONAL_ASC) $(REARGUARD_ASC) \
tarballs rearguard_tarballs tailored_tarballs traditional_tarballs \
signatures rearguard_signatures traditional_signatures: \
version set-timestamps.out rearguard.zi vanguard.zi
VERSION=`cat version` && \
read -r VERSION <version && \
$(MAKE) AWK='$(AWK)' VERSION="$$VERSION" $@_version
# These *_version rules are intended for use if VERSION is set by some
@ -1218,15 +1234,15 @@ rearguard_signatures_version: $(REARGUARD_ASC)
traditional_signatures_version: $(TRADITIONAL_ASC)
tzcode$(VERSION).tar.gz: set-timestamps.out
LC_ALL=C && export LC_ALL && \
tar $(TARFLAGS) -cf - \
$(SETUP_TAR) && \
$$TAR -cf - \
$(COMMON) $(DOCS) $(SOURCES) | \
gzip $(GZIPFLAGS) >$@.out
mv $@.out $@
tzdata$(VERSION).tar.gz: set-timestamps.out
LC_ALL=C && export LC_ALL && \
tar $(TARFLAGS) -cf - $(TZDATA_DIST) | \
$(SETUP_TAR) && \
$$TAR -cf - $(TZDATA_DIST) | \
gzip $(GZIPFLAGS) >$@.out
mv $@.out $@
@ -1251,9 +1267,9 @@ tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out
: The dummy pacificnew pacifies TZUpdater 2.3.1 and earlier.
$(CREATE_EMPTY) $@.dir/pacificnew
touch -mr version $@.dir/version
LC_ALL=C && export LC_ALL && \
$(SETUP_TAR) && \
(cd $@.dir && \
tar $(TARFLAGS) -cf - \
$$TAR -cf - \
$(TZDATA_DIST) pacificnew | \
gzip $(GZIPFLAGS)) >$@.out
mv $@.out $@
@ -1269,9 +1285,14 @@ tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out
rm -fr $@.dir
mkdir $@.dir
: The dummy pacificnew pacifies TZUpdater 2.3.1 and earlier.
if test $(DATAFORM) = vanguard; then \
pacificnew=; \
else \
pacificnew=pacificnew; \
fi && \
cd $@.dir && \
$(CREATE_EMPTY) $(PRIMARY_YDATA) $(NDATA) backward \
`test $(DATAFORM) = vanguard || echo pacificnew`
$$pacificnew
(grep '^#' tzdata.zi && echo && cat $(DATAFORM).zi) \
>$@.dir/etcetera
touch -mr tzdata.zi $@.dir/etcetera
@ -1291,9 +1312,9 @@ tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out
test -f $@.dir/$$file || links="$$links $$file"; \
done && \
ln $$links $@.dir
LC_ALL=C && export LC_ALL && \
$(SETUP_TAR) && \
(cd $@.dir && \
tar $(TARFLAGS) -cf - * | gzip $(GZIPFLAGS)) >$@.out
$$TAR -cf - * | gzip $(GZIPFLAGS)) >$@.out
mv $@.out $@
tzdb-$(VERSION).tar.lz: set-timestamps.out set-tzs-timestamp.out
@ -1301,8 +1322,8 @@ tzdb-$(VERSION).tar.lz: set-timestamps.out set-tzs-timestamp.out
mkdir tzdb-$(VERSION)
ln $(ENCHILADA) tzdb-$(VERSION)
$(SET_TIMESTAMP) tzdb-$(VERSION) tzdb-$(VERSION)/*
LC_ALL=C && export LC_ALL && \
tar $(TARFLAGS) -cf - tzdb-$(VERSION) | lzip -9 >$@.out
$(SETUP_TAR) && \
$$TAR -cf - tzdb-$(VERSION) | lzip -9 >$@.out
mv $@.out $@
tzcode$(VERSION).tar.gz.asc: tzcode$(VERSION).tar.gz
@ -1313,22 +1334,21 @@ $(ALL_ASC):
$(GPG) --armor --detach-sign $?
TYPECHECK_CFLAGS = $(CFLAGS) -DTYPECHECK -D__time_t_defined -D_TIME_T
typecheck: typecheck_long_long typecheck_unsigned
typecheck_long_long typecheck_unsigned: $(VERSION_DEPS)
rm -fr $@.dir
mkdir $@.dir
ln $(VERSION_DEPS) $@.dir
cd $@.dir && \
typecheck: long-long.ck unsigned.ck
long-long.ck unsigned.ck: $(VERSION_DEPS)
rm -fr $@d
mkdir $@d
ln $(VERSION_DEPS) $@d
cd $@d && \
case $@ in \
*_long_long) i="long long";; \
*_unsigned ) i="unsigned" ;; \
long-long.*) i="long long";; \
unsigned.* ) i="unsigned" ;; \
esac && \
typecheck_cflags='' && \
$(MAKE) \
CFLAGS="$(TYPECHECK_CFLAGS) \"-Dtime_t=$$i\"" \
TOPDIR="`pwd`" \
TOPDIR="$$PWD" \
install
$@.dir/zdump -i -c 1970,1971 Europe/Rome
$@d/zdump -i -c 1970,1971 Europe/Rome
touch $@
zonenames: tzdata.zi
@ -1347,7 +1367,7 @@ zic.o: private.h tzfile.h tzdir.h version.h
.PHONY: check_web check_zishrink
.PHONY: clean clean_misc commit-leap-seconds.list dummy.zd
.PHONY: fetch-leap-seconds.list force_tzs
.PHONY: install install_data maintainer-clean names
.PHONY: install maintainer-clean names
.PHONY: posix_only posix_right public
.PHONY: rearguard_signatures rearguard_signatures_version
.PHONY: rearguard_tarballs rearguard_tarballs_version

124
NEWS
View file

@ -1,5 +1,125 @@
News for the tz database
Release 2024b - 2024-09-04 12:27:47 -0700
Briefly:
Improve historical data for Mexico, Mongolia, and Portugal.
System V names are now obsolescent.
The main data form now uses %z.
The code now conforms to RFC 8536 for early timestamps.
Support POSIX.1-2024, which removes asctime_r and ctime_r.
Assume POSIX.2-1992 or later for shell scripts.
SUPPORT_C89 now defaults to 1.
Changes to past timestamps
Asia/Choibalsan is now an alias for Asia/Ulaanbaatar rather than
being a separate Zone with differing behavior before April 2008.
This seems better given our wildly conflicting information about
Mongolia's time zone history. (Thanks to Heitor David Pinto.)
Historical transitions for Mexico have been updated based on
official Mexican decrees. The affected timestamps occur during
the years 1921-1927, 1931, 1945, 1949-1970, and 1981-1997.
The affected zones are America/Bahia_Banderas, America/Cancun,
America/Chihuahua, America/Ciudad_Juarez, America/Hermosillo,
America/Mazatlan, America/Merida, America/Mexico_City,
America/Monterrey, America/Ojinaga, and America/Tijuana.
(Thanks to Heitor David Pinto.)
Historical transitions for Portugal, represented by Europe/Lisbon,
Atlantic/Azores, and Atlantic/Madeira, have been updated based on a
close reading of old Portuguese legislation, replacing previous data
mainly originating from Whitman and Shanks & Pottenger. These
changes affect a few transitions in 1917-1921, 1924, and 1940
throughout these regions by a few hours or days, and various
timestamps between 1977 and 1993 depending on the region. In
particular, the Azores and Madeira did not observe DST from 1977 to
1981. Additionally, the adoption of standard zonal time in former
Portuguese colonies have been adjusted: Africa/Maputo in 1909, and
Asia/Dili by 22 minutes at the start of 1912.
(Thanks to Tim Parenti.)
Changes to past tm_isdst flags
The period from 1966-04-03 through 1966-10-02 in Portugal is now
modeled as DST, to more closely reflect how contemporaneous changes
in law entered into force.
Changes to data
Names present only for compatibility with UNIX System V
(last released in the 1990s) have been moved to 'backward'.
These names, which for post-1970 timestamps mostly just duplicate
data of geographical names, were confusing downstream uses.
Names moved to 'backward' are now links to geographical names.
This affects behavior for TZ='EET' for some pre-1981 timestamps,
for TZ='CET' for some pre-1947 timestamps, and for TZ='WET' for
some pre-1996 timestamps. Also, TZ='MET' now behaves like
TZ='CET' and so uses the abbreviation "CET" rather than "MET".
Those needing the previous TZDB behavior, which does not match any
real-world clocks, can find the old entries in 'backzone'.
(Problem reported by Justin Grant.)
The main source files' time zone abbreviations now use %z,
supported by zic since release 2015f and used in vanguard form
since release 2022b. For example, America/Sao_Paulo now contains
the zone continuation line "-3:00 Brazil %z", which is less error
prone than the old "-3:00 Brazil -03/-02". This does not change
the represented data: the generated TZif files are unchanged.
Rearguard form still avoids %z, to support obsolescent parsers.
Asia/Almaty has been removed from zonenow.tab as it now agrees
with Asia/Tashkent for future timestamps, due to Kazakhstan's
2024-02-29 time zone change. Similarly, America/Scoresbysund
has been removed, as it now agrees with America/Nuuk due to
its 2024-03-31 time zone change.
Changes to code
localtime.c now always uses a TZif file's time type 0 to handle
timestamps before the file's first transition. Formerly,
localtime.c sometimes inferred a different time type, in order to
handle problematic data generated by zic 2018e or earlier. As it
is now safe to assume more recent versions of zic, there is no
longer a pressing need to fail to conform RFC 8536 section 3.2,
which requires using time type 0 in this situation. This change
does not affect behavior when reading TZif files generated by zic
2018f and later.
POSIX.1-2024 removes asctime_r and ctime_r and does not let
libraries define them, so remove them except when needed to
conform to earlier POSIX. These functions are dangerous as they
can overrun user buffers. If you still need them, add
-DSUPPORT_POSIX2008 to CFLAGS.
The SUPPORT_C89 option now defaults to 1 instead of 0, fixing a
POSIX-conformance bug introduced in 2023a.
tzselect now supports POSIX.1-2024 proleptic TZ strings. Also, it
assumes POSIX.2-1992 or later, as practical porting targets now
all support that, and it uses some features from POSIX.1-2024 if
available.
Changes to build procedure
'make check' no longer requires curl and Internet access.
The build procedure now assumes POSIX.2-1992 or later, to simplify
maintenance. To build on Solaris 10, the only extant system still
defaulting to pre-POSIX, prepend /usr/xpg4/bin to PATH.
Changes to documentation
The documentation now reflects POSIX.1-2024.
Changes to commentary
Commentary about historical transitions in Portugal and her former
colonies has been expanded with links to many relevant legislation.
(Thanks to Tim Parenti.)
Release 2024a - 2024-02-01 09:28:56 -0800
Briefly:
@ -161,7 +281,7 @@ Release 2023d - 2023-12-21 20:02:24 -0800
* It uses the special .POSIX target.
* It quotes special characters more carefully.
* It no longer mishandles builds in an ISO 8859 locale.
Due to the CC changes, TZDIR is now #defined in a file tzfile.h
Due to the CC changes, TZDIR is now #defined in a file tzdir.h
built by 'make', not in a $(CC) -D option. Also, TZDEFAULT is
now treated like TZDIR as they have similar roles.
@ -283,7 +403,7 @@ Release 2023a - 2023-03-22 12:39:33 -0700
To improve tzselect diagnostics, zone1970.tab's comments column is
now limited to countries that have multiple timezones.
Note that leap seconds are planned to be discontinued by 2035.
Note that there are plans to discontinue leap seconds by 2035.
Release 2022g - 2022-11-29 08:58:31 -0800

View file

@ -1,4 +1,4 @@
/* asctime and asctime_r a la POSIX and ISO C, except pad years before 1000. */
/* asctime a la ISO C. */
/*
** This file is in the public domain, so clarified as of
@ -25,8 +25,8 @@
** leading zeroes to get the newline in the traditional place.
** The -4 ensures that we get four characters of output even if
** we call a strftime variant that produces fewer characters for some years.
** The ISO C and POSIX standards prohibit padding the year,
** but many implementations pad anyway; most likely the standards are buggy.
** This conforms to recent ISO C and POSIX standards, which say behavior
** is undefined when the year is less than 1000 or greater than 9999.
*/
static char const ASCTIME_FMT[] = "%s %s%3d %.2d:%.2d:%.2d %-4s\n";
/*
@ -60,6 +60,18 @@ static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1];
static char buf_ctime[sizeof buf_asctime];
#endif
/* Publish asctime_r and ctime_r only when supporting older POSIX. */
#if SUPPORT_POSIX2008
# define asctime_static
#else
# define asctime_static static
# undef asctime_r
# undef ctime_r
# define asctime_r static_asctime_r
# define ctime_r static_ctime_r
#endif
asctime_static
char *
asctime_r(struct tm const *restrict timeptr, char *restrict buf)
{
@ -116,6 +128,7 @@ asctime(register const struct tm *timeptr)
return asctime_r(timeptr, buf_asctime);
}
asctime_static
char *
ctime_r(const time_t *timep, char *buf)
{

View file

@ -106,7 +106,7 @@ static char const UNSPEC[] = "-00";
for ttunspecified to work without crashing. */
enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 };
/* Limit to time zone abbreviation length in POSIX.1-2017-style TZ strings.
/* Limit to time zone abbreviation length in proleptic TZ strings.
This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */
#ifndef TZNAME_MAXIMUM
# define TZNAME_MAXIMUM 255
@ -130,11 +130,6 @@ struct state {
char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"),
2 * (TZNAME_MAXIMUM + 1))];
struct lsinfo lsis[TZ_MAX_LEAPS];
/* The time type to use for early times or if no transitions.
It is always zero for recent tzdb releases.
It might be nonzero for data from tzdb 2018e or earlier. */
int defaulttype;
};
enum r_type {
@ -187,8 +182,9 @@ static int lcl_is_set;
** objects: a broken-down time structure and an array of char.
** Thanks to Paul Eggert for noting this.
**
** This requirement was removed in C99, so support it only if requested,
** as support is more likely to lead to bugs in badly written programs.
** Although this requirement was removed in C99 it is still present in POSIX.
** Follow the requirement if SUPPORT_C89, even though this is more likely to
** trigger latent bugs in programs.
*/
#if SUPPORT_C89
@ -710,58 +706,6 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
if (sp->typecnt == 0)
return EINVAL;
/* Infer sp->defaulttype from the data. Although this default
type is always zero for data from recent tzdb releases,
things are trickier for data from tzdb 2018e or earlier.
The first set of heuristics work around bugs in 32-bit data
generated by tzdb 2013c or earlier. The workaround is for
zones like Australia/Macquarie where timestamps before the
first transition have a time type that is not the earliest
standard-time type. See:
https://mm.icann.org/pipermail/tz/2013-May/019368.html */
/*
** If type 0 does not specify local time, or is unused in transitions,
** it's the type to use for early times.
*/
for (i = 0; i < sp->timecnt; ++i)
if (sp->types[i] == 0)
break;
i = i < sp->timecnt && ! ttunspecified(sp, 0) ? -1 : 0;
/*
** Absent the above,
** if there are transition times
** and the first transition is to a daylight time
** find the standard type less than and closest to
** the type of the first transition.
*/
if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
i = sp->types[0];
while (--i >= 0)
if (!sp->ttis[i].tt_isdst)
break;
}
/* The next heuristics are for data generated by tzdb 2018e or
earlier, for zones like EST5EDT where the first transition
is to DST. */
/*
** If no result yet, find the first standard type.
** If there is none, punt to type zero.
*/
if (i < 0) {
i = 0;
while (sp->ttis[i].tt_isdst)
if (++i >= sp->typecnt) {
i = 0;
break;
}
}
/* A simple 'sp->defaulttype = 0;' would suffice here if we
didn't have to worry about 2018e-or-earlier data. Even
simpler would be to remove the defaulttype member and just
use 0 in its place. */
sp->defaulttype = i;
return 0;
}
@ -807,7 +751,7 @@ is_digit(char c)
** Return a pointer to that character.
*/
ATTRIBUTE_REPRODUCIBLE static const char *
ATTRIBUTE_PURE_114833 static const char *
getzname(register const char *strp)
{
register char c;
@ -828,7 +772,7 @@ getzname(register const char *strp)
** We don't do any checking here; checking is done later in common-case code.
*/
ATTRIBUTE_REPRODUCIBLE static const char *
ATTRIBUTE_PURE_114833 static const char *
getqzname(register const char *strp, const int delim)
{
register int c;
@ -1080,7 +1024,7 @@ transtime(const int year, register const struct rule *const rulep,
}
/*
** Given a POSIX.1-2017-style TZ string, fill in the rule tables as
** Given a POSIX.1 proleptic TZ string, fill in the rule tables as
** appropriate.
*/
@ -1183,11 +1127,13 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
do {
int_fast32_t yearsecs
= year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
time_t janfirst1 = janfirst;
yearbeg--;
if (increment_overflow_time(&janfirst, -yearsecs)) {
if (increment_overflow_time(&janfirst1, -yearsecs)) {
janoffset = -yearsecs;
break;
}
janfirst = janfirst1;
} while (atlo < janfirst
&& EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
@ -1313,7 +1259,7 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
/*
** Transitions from DST to DDST
** will effectively disappear since
** POSIX.1-2017 provides for only one
** proleptic TZ strings have only one
** DST offset.
*/
if (isdst && !sp->ttis[j].tt_ttisstd) {
@ -1342,7 +1288,6 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
sp->timecnt = 0;
init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
}
sp->defaulttype = 0;
sp->charcnt = charcnt;
cp = sp->chars;
memcpy(cp, stdname, stdlen);
@ -1378,7 +1323,6 @@ zoneinit(struct state *sp, char const *name)
sp->goback = sp->goahead = false;
init_ttinfo(&sp->ttis[0], 0, false, 0);
strcpy(sp->chars, utc);
sp->defaulttype = 0;
return 0;
} else {
int err = tzload(name, sp, true);
@ -1465,8 +1409,8 @@ tzfree(timezone_t sp)
}
/*
** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
** ctime_r are obsolescent and have potential security problems that
** NetBSD 6.1.4 has ctime_rz, but omit it because C23 deprecates ctime and
** POSIX.1-2024 removes ctime_r. Both have potential security problems that
** ctime_rz would share. Callers can instead use localtime_rz + strftime.
**
** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
@ -1484,8 +1428,7 @@ tzfree(timezone_t sp)
**
** If successful and SETNAME is nonzero,
** set the applicable parts of tzname, timezone and altzone;
** however, it's OK to omit this step
** if the timezone is compatible with POSIX.1-2017
** however, it's OK to omit this step for proleptic TZ strings
** since in that case tzset should have already done this step correctly.
** SETNAME's type is int_fast32_t for compatibility with gmtsub,
** but it is actually a boolean and its value should be 0 or 1.
@ -1553,7 +1496,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
return result;
}
if (sp->timecnt == 0 || t < sp->ats[0]) {
i = sp->defaulttype;
i = 0;
} else {
register int lo = 1;
register int hi = sp->timecnt;
@ -2285,7 +2228,7 @@ mktime(struct tm *tmp)
}
#if STD_INSPIRED
/* This function is obsolescent and may disapper in future releases.
/* This function is obsolescent and may disappear in future releases.
Callers can instead use mktime. */
time_t
timelocal(struct tm *tmp)
@ -2303,7 +2246,7 @@ timelocal(struct tm *tmp)
# define EXTERN_TIMEOFF static
#endif
/* This function is obsolescent and may disapper in future releases.
/* This function is obsolescent and may disappear in future releases.
Callers can instead use mktime_z with a fixed-offset zone. */
EXTERN_TIMEOFF time_t
timeoff(struct tm *tmp, long offset)

View file

@ -9,16 +9,16 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
.el .ds - \-
.B #include <time.h>
.PP
.BR "extern char *tzname[];" " /\(** (optional) \(**/"
.PP
.B [[deprecated]] char *ctime(time_t const *clock);
.PP
/* Only in POSIX.1-2017 and earlier. */
.B char *ctime_r(time_t const *clock, char *buf);
.PP
.B double difftime(time_t time1, time_t time0);
.PP
.B [[deprecated]] char *asctime(struct tm const *tm);
.PP
/* Only in POSIX.1-2017 and earlier. */
.B "char *asctime_r(struct tm const *restrict tm,"
.B " char *restrict result);"
.PP
@ -112,17 +112,6 @@ The
function
corrects for the time zone and any time zone adjustments
(such as Daylight Saving Time in the United States).
After filling in the
.q "tm"
structure,
.B localtime
sets the
.BR tm_isdst 'th
element of
.B tzname
to a pointer to a string that's the time zone abbreviation to be used with
.BR localtime 's
return value.
.PP
The
.B gmtime
@ -191,9 +180,19 @@ are determined.
The
.B mktime
function
returns the specified calendar time;
returns the specified calendar time.
If the calendar time cannot be represented,
it returns \-1.
it returns \-1 without updating the structure.
To distinguish failure from a valid \-1 return,
you can set
.B tm_wday
or
.B tm_yday
to a negative value before calling
.BR mktime ;
if that value is still negative when
.B mktime
returns, the calendar time could not be represented.
.PP
The
.B difftime
@ -213,6 +212,13 @@ and
functions
are like their unsuffixed counterparts, except that they accept an
additional argument specifying where to store the result if successful.
The
.B ctime_r
and
.B asctime_r
functions are present only on systems supporting POSIX.1-2017 and earlier,
as they are removed in POSIX.1-2024 and user code can define these
functions with other meanings.
.PP
The
.B localtime_rz
@ -275,21 +281,43 @@ from UT, with positive values indicating east
of the Prime Meridian.
The field's name is derived from Greenwich Mean Time, a precursor of UT.
.PP
In
In platforms conforming to POSIX.1-2024 the
.B "struct tm"
the
.B tm_zone
and
.B tm_gmtoff
fields exist, and are filled in, only if arrangements to do
so were made when the library containing these functions was
created.
Similarly, the
.B tzname
variable is optional; also, there is no guarantee that
.B tzname
will
continue to exist in this form in future releases of this code.
fields exist, and are filled in.
For
.B localtime_rz
and
.B mktime_rz
the storage lifetime of the strings addressed by
.B tm_zone
extends until the corresponding
.B timezone_t
object is freed via
.BR tzfree .
For the other functions the lifetime extends until the
.I TZ
environment variable changes state and
.B tzset
is then called.
.PP
As a side effect, the
.BR ctime ,
.B localtime
and
.B mktime
functions also behave as if
.B tzset
were called.
The
.B ctime_r
and
.B localtime_r
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
/etc/localtime local timezone file
@ -303,11 +331,11 @@ continue to exist in this form in future releases of this code.
If /usr/share/zoneinfo/GMT is absent,
UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present.
.SH SEE ALSO
getenv(3),
newstrftime(3),
newtzset(3),
time(2),
tzfile(5)
.BR getenv (3),
.BR newstrftime (3),
.BR newtzset (3),
.BR time (2),
.BR tzfile (5).
.SH NOTES
The return values of
.BR asctime ,
@ -317,20 +345,6 @@ and
.B localtime
point to static data
overwritten by each call.
The
.B tzname
variable (once set) and the
.B tm_zone
field of a returned
.B "struct tm"
both point to an array of characters that
can be freed or overwritten by later calls to the functions
.BR localtime ,
.BR tzfree ,
and
.BR tzset ,
if these functions affect the timezone information that specifies the
abbreviation in question.
The remaining functions and data are thread-safe.
.PP
The

View file

@ -7,16 +7,16 @@ NAME
SYNOPSIS
#include <time.h>
extern char *tzname[]; /* (optional) */
[[deprecated]] char *ctime(time_t const *clock);
/* Only in POSIX.1-2017 and earlier. */
char *ctime_r(time_t const *clock, char *buf);
double difftime(time_t time1, time_t time0);
[[deprecated]] char *asctime(struct tm const *tm);
/* Only in POSIX.1-2017 and earlier. */
char *asctime_r(struct tm const *restrict tm,
char *restrict result);
@ -68,9 +68,7 @@ DESCRIPTION
The localtime and gmtime functions return pointers to "tm" structures,
described below. The localtime function corrects for the time zone and
any time zone adjustments (such as Daylight Saving Time in the United
States). After filling in the "tm" structure, localtime sets the
tm_isdst'th element of tzname to a pointer to a string that's the time
zone abbreviation to be used with localtime's return value.
States).
The gmtime function converts to Coordinated Universal Time.
@ -96,15 +94,22 @@ DESCRIPTION
set to represent the specified calendar time, but with their values
forced to their normal ranges; the final value of tm_mday is not set
until tm_mon and tm_year are determined. The mktime function returns
the specified calendar time; If the calendar time cannot be
represented, it returns -1.
the specified calendar time. If the calendar time cannot be
represented, it returns -1 without updating the structure. To
distinguish failure from a valid -1 return, you can set tm_wday or
tm_yday to a negative value before calling mktime; if that value is
still negative when mktime returns, the calendar time could not be
represented.
The difftime function returns the difference between two calendar
times, (time1 - time0), expressed in seconds.
The ctime_r, localtime_r, gmtime_r, and asctime_r functions are like
their unsuffixed counterparts, except that they accept an additional
argument specifying where to store the result if successful.
argument specifying where to store the result if successful. The
ctime_r and asctime_r functions are present only on systems supporting
POSIX.1-2017 and earlier, as they are removed in POSIX.1-2024 and user
code can define these functions with other meanings.
The localtime_rz and mktime_z functions are like their unsuffixed
counterparts, except that they accept an extra initial zone argument
@ -136,11 +141,17 @@ DESCRIPTION
The field's name is derived from Greenwich Mean Time, a precursor of
UT.
In struct tm the tm_zone and tm_gmtoff fields exist, and are filled in,
only if arrangements to do so were made when the library containing
these functions was created. Similarly, the tzname variable is
optional; also, there is no guarantee that tzname will continue to
exist in this form in future releases of this code.
In platforms conforming to POSIX.1-2024 the struct tm the tm_zone and
tm_gmtoff fields exist, and are filled in. For localtime_rz and
mktime_rz the storage lifetime of the strings addressed by tm_zone
extends until the corresponding timezone_t object is freed via tzfree.
For the other functions the lifetime extends until the TZ environment
variable changes state and tzset is then called.
As a side effect, the ctime, localtime and mktime functions also behave
as if tzset were called. The ctime_r and localtime_r functions might
(or might not) also behave this way. This is for compatibility with
older platforms, as required by POSIX.
FILES
/etc/localtime local timezone file
@ -152,16 +163,12 @@ FILES
/usr/share/zoneinfo/GMT0 if present.
SEE ALSO
getenv(3), newstrftime(3), newtzset(3), time(2), tzfile(5)
getenv(3), newstrftime(3), newtzset(3), time(2), tzfile(5).
NOTES
The return values of asctime, ctime, gmtime, and localtime point to
static data overwritten by each call. The tzname variable (once set)
and the tm_zone field of a returned struct tm both point to an array of
characters that can be freed or overwritten by later calls to the
functions localtime, tzfree, and tzset, if these functions affect the
timezone information that specifies the abbreviation in question. The
remaining functions and data are thread-safe.
static data overwritten by each call. The remaining functions and data
are thread-safe.
The asctime, asctime_r, ctime, and ctime_r functions behave strangely
for years before 1000 or after 9999. The 1989 and 1999 editions of the

View file

@ -91,11 +91,11 @@ as specified by brackets in the description.
If a bracketed member name is followed by
.q + ,
.B strftime
can use the named member even though POSIX.1-2017 does not list it;
can use the named member even though POSIX.1-2024 does not list it;
if the name is followed by
.q \*- ,
.B strftime
ignores the member even though POSIX.1-2017 lists it
ignores the member even though POSIX.1-2024 lists it
which means portable code should set it.
For portability,
.BI * timeptr
@ -137,8 +137,8 @@ is replaced by the locale's appropriate date and time representation.
.IR tm_hour ,
.IR tm_min ,
.IR tm_sec ,
.IR tm_gmtoff +,
.IR tm_zone +,
.IR tm_gmtoff ,
.IR tm_zone ,
.IR tm_isdst \*-].
.TP
%D
@ -326,8 +326,8 @@ is replaced by the locale's appropriate time representation.
.IR tm_hour ,
.IR tm_min ,
.IR tm_sec ,
.IR tm_gmtoff +,
.IR tm_zone +,
.IR tm_gmtoff ,
.IR tm_zone ,
.IR tm_isdst \*-].
.TP
%x
@ -355,7 +355,7 @@ is replaced by the year without century as a decimal number [00,99].
%Z
is replaced by the time zone abbreviation,
or by the empty string if this is not determinable.
.RI [ tm_zone +,
.RI [ tm_zone ,
.IR tm_isdst \*-]
.TP
%z
@ -369,7 +369,7 @@ but local time is indeterminate; by convention this is used for
locations while uninhabited, and corresponds to a zero offset when the
time zone abbreviation begins with
.q "\*-" .
.RI [ tm_gmtoff +,
.RI [ tm_gmtoff ,
.IR tm_zone +,
.IR tm_isdst \*-]
.TP
@ -398,7 +398,7 @@ also behaves as if
were called.
This is for compatibility with older platforms, as required by POSIX;
it is not needed for
.BR tzset 's
.BR strftime 's
own use.
.SH "RETURN VALUE"
If the conversion is successful,
@ -428,11 +428,11 @@ conversion and the number of seconds since the Epoch cannot be represented
in a
.c time_t .
.SH SEE ALSO
date(1),
getenv(3),
newctime(3),
newtzset(3),
time(2),
tzfile(5)
.BR date (1),
.BR getenv (3),
.BR newctime (3),
.BR newtzset (3),
.BR time (2),
.BR tzfile (5).
.SH BUGS
There is no conversion specification for the phase of the moon.

View file

@ -26,9 +26,9 @@ DESCRIPTION
which are then copied into the array. The characters depend on the
values of zero or more members of *timeptr as specified by brackets in
the description. If a bracketed member name is followed by "+",
strftime can use the named member even though POSIX.1-2017 does not
strftime can use the named member even though POSIX.1-2024 does not
list it; if the name is followed by "-", strftime ignores the member
even though POSIX.1-2017 lists it which means portable code should set
even though POSIX.1-2024 lists it which means portable code should set
it. For portability, *timeptr should be initialized as if by a
successful call to gmtime, localtime, mktime, timegm, or similar
functions.
@ -48,7 +48,7 @@ DESCRIPTION
%c is replaced by the locale's appropriate date and time
representation. [tm_year, tm_yday, tm_mon, tm_mday, tm_wday,
tm_hour, tm_min, tm_sec, tm_gmtoff+, tm_zone+, tm_isdst-].
tm_hour, tm_min, tm_sec, tm_gmtoff, tm_zone, tm_isdst-].
%D is equivalent to %m/%d/%y. [tm_year, tm_mon, tm_mday]
@ -139,7 +139,7 @@ DESCRIPTION
%X is replaced by the locale's appropriate time representation.
[tm_year-, tm_yday-, tm_mon-, tm_mday-, tm_wday-, tm_hour,
tm_min, tm_sec, tm_gmtoff+, tm_zone+, tm_isdst-].
tm_min, tm_sec, tm_gmtoff, tm_zone, tm_isdst-].
%x is replaced by the locale's appropriate date representation.
[tm_year, tm_yday, tm_mon, tm_mday, tm_wday, tm_hour-, tm_min-,
@ -152,7 +152,7 @@ DESCRIPTION
[00,99]. [tm_year]
%Z is replaced by the time zone abbreviation, or by the empty
string if this is not determinable. [tm_zone+, tm_isdst-]
string if this is not determinable. [tm_zone, tm_isdst-]
%z is replaced by the offset from the Prime Meridian in the format
+HHMM or -HHMM (ISO 8601) as appropriate, with positive values
@ -161,7 +161,7 @@ DESCRIPTION
-0000 is used when the time is Universal Time but local time is
indeterminate; by convention this is used for locations while
uninhabited, and corresponds to a zero offset when the time zone
abbreviation begins with "-". [tm_gmtoff+, tm_zone+, tm_isdst-]
abbreviation begins with "-". [tm_gmtoff, tm_zone+, tm_isdst-]
%% is replaced by a single %.
@ -171,7 +171,7 @@ DESCRIPTION
As a side effect, strftime also behaves as if tzset were called. This
is for compatibility with older platforms, as required by POSIX; it is
not needed for tzset's own use.
not needed for strftime's own use.
RETURN VALUE
If the conversion is successful, strftime returns the number of bytes
@ -194,7 +194,7 @@ ERRORS
since the Epoch cannot be represented in a time_t.
SEE ALSO
date(1), getenv(3), newctime(3), newtzset(3), time(2), tzfile(5)
date(1), getenv(3), newctime(3), newtzset(3), time(2), tzfile(5).
BUGS
There is no conversion specification for the phase of the moon.

View file

@ -15,6 +15,14 @@ tzset \- initialize time conversion information
.PP
.B void tzset(void);
.PP
/\(** Optional and obsolescent: \(**/
.br
.B extern char *tzname[];
.br
.B extern long timezone;
.br
.B extern int daylight;
.PP
.B cc ... \*-ltz
.fi
.SH DESCRIPTION
@ -165,7 +173,7 @@ describes when the change back happens. Each
.I time
field describes when, in current local time, the change to the other
time is made.
As an extension to POSIX.1-2017, daylight saving is assumed to be in effect
Daylight saving is assumed to be in effect
all year if it begins January 1 at 00:00 and ends December 31 at
24:00 plus the difference between daylight saving and standard time,
leaving no room for standard time in the calendar.
@ -212,11 +220,7 @@ The
.I time
has the same format as
.I offset
except that POSIX.1-2017 does not allow a leading sign (\c
.q "\*-"
or
.q "+" ).
As an extension to POSIX.1-2017, the hours part of
except that the hours part of
.I time
can range from \-167 through 167; this allows for unusual rules such
as
@ -229,8 +233,7 @@ is not given, is
.LP
Here are some examples of
.I TZ
values that directly specify the timezone; they use some of the
extensions to POSIX.1-2017.
values that directly specify the timezone.
.TP
.B EST5
stands for US Eastern Standard
@ -346,6 +349,22 @@ if the implied call to
fails,
.B tzset
falls back on UT.
.PP
As a side effect, the
.B tzset
function sets some external variables if the platform defines them.
It sets
.BR tzname [0]
and
.BR tzname [1]
to pointers to strings that are time zone abbreviations to be used with
standard and daylight saving time, respectively.
It also sets
.B timezone
to be the number of seconds that standard time is west of the Prime Meridian,
and
.B daylight
to be zero if daylight saving time is never in effect, non-zero otherwise.
.SH "RETURN VALUE"
If successful, the
.B tzalloc
@ -384,8 +403,29 @@ and
If /usr/share/zoneinfo/GMT is absent,
UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present.
.SH SEE ALSO
getenv(3),
newctime(3),
newstrftime(3),
time(2),
tzfile(5)
.BR getenv (3),
.BR newctime (3),
.BR newstrftime (3),
.BR time (2),
.BR tzfile (5).
.SH NOTES
Portable code should not rely on the contents of the external variables
.BR tzname ,
.B timezone
and
.B daylight
as their contents are unspecified (and do not make sense in general)
when a geographical TZ is used.
In multithreaded applications behavior is undefined if one thread accesses
one of these variables while another thread invokes
.BR tzset .
A future version of POSIX is planned to remove these variables;
callers can instead use the
.I tm_gmtoff
and
.I tm_zone
members of
.B struct tm,
or use
.B strftime
with "%z" or "%Z".

View file

@ -12,6 +12,11 @@ SYNOPSIS
void tzset(void);
/* Optional and obsolescent: */
extern char *tzname[];
extern long timezone;
extern int daylight;
cc ... -ltz
DESCRIPTION
@ -88,12 +93,11 @@ DESCRIPTION
standard to daylight saving time occurs and the second
date describes when the change back happens. Each time
field describes when, in current local time, the change
to the other time is made. As an extension to
POSIX.1-2017, daylight saving is assumed to be in effect
all year if it begins January 1 at 00:00 and ends
December 31 at 24:00 plus the difference between daylight
saving and standard time, leaving no room for standard
time in the calendar.
to the other time is made. Daylight saving is assumed to
be in effect all year if it begins January 1 at 00:00 and
ends December 31 at 24:00 plus the difference between
daylight saving and standard time, leaving no room for
standard time in the calendar.
The format of date is one of the following:
@ -114,15 +118,13 @@ DESCRIPTION
is the first week in which the d'th day occurs.
Day zero is Sunday.
The time has the same format as offset except that
POSIX.1-2017 does not allow a leading sign ("-" or "+").
As an extension to POSIX.1-2017, the hours part of time
can range from -167 through 167; this allows for unusual
rules such as "the Saturday before the first Sunday of
March". The default, if time is not given, is 02:00:00.
The time has the same format as offset except that the
hours part of time can range from -167 through 167; this
allows for unusual rules such as "the Saturday before the
first Sunday of March". The default, if time is not
given, is 02:00:00.
Here are some examples of TZ values that directly specify the timezone;
they use some of the extensions to POSIX.1-2017.
Here are some examples of TZ values that directly specify the timezone.
EST5 stands for US Eastern Standard Time (EST), 5 hours behind UT,
without daylight saving.
@ -183,6 +185,14 @@ DESCRIPTION
getenv fails, tzset acts like tzalloc(nullptr); if the implied call to
tzalloc fails, tzset falls back on UT.
As a side effect, the tzset function sets some external variables if
the platform defines them. It sets tzname[0] and tzname[1] to pointers
to strings that are time zone abbreviations to be used with standard
and daylight saving time, respectively. It also sets timezone to be
the number of seconds that standard time is west of the Prime Meridian,
and daylight to be zero if daylight saving time is never in effect,
non-zero otherwise.
RETURN VALUE
If successful, the tzalloc function returns a nonnull pointer to the
newly allocated object. Otherwise, it returns a null pointer and sets
@ -208,6 +218,16 @@ FILES
/usr/share/zoneinfo/GMT0 if present.
SEE ALSO
getenv(3), newctime(3), newstrftime(3), time(2), tzfile(5)
getenv(3), newctime(3), newstrftime(3), time(2), tzfile(5).
NOTES
Portable code should not rely on the contents of the external variables
tzname, timezone and daylight as their contents are unspecified (and do
not make sense in general) when a geographical TZ is used. In
multithreaded applications behavior is undefined if one thread accesses
one of these variables while another thread invokes tzset. A future
version of POSIX is planned to remove these variables; callers can
instead use the tm_gmtoff and tm_zone members of struct tm, or use
strftime with "%z" or "%Z".
Time Zone Database newtzset(3)

114
private.h
View file

@ -19,19 +19,22 @@
/* PORT_TO_C89 means the code should work even if the underlying
compiler and library support only C89 plus C99's 'long long'
and perhaps a few other extensions to C89. SUPPORT_C89 means the
tzcode library should support C89 callers in addition to the usual
support for C99-and-later callers; however, C89 support can trigger
latent bugs in C99-and-later callers. These macros are obsolescent,
and the plan is to remove them along with any code needed only when
they are nonzero. A good time to do that might be in the year 2029
and perhaps a few other extensions to C89.
This macro is obsolescent, and the plan is to remove it along with
associated code. A good time to do that might be in the year 2029
because RHEL 7 (whose GCC defaults to C89) extended life cycle
support (ELS) is scheduled to end on 2028-06-30. */
#ifndef PORT_TO_C89
# define PORT_TO_C89 0
#endif
/* SUPPORT_C89 means the tzcode library should support C89 callers
in addition to the usual support for C99-and-later callers.
This defaults to 1 as POSIX requires, even though that can trigger
latent bugs in callers. */
#ifndef SUPPORT_C89
# define SUPPORT_C89 0
# define SUPPORT_C89 1
#endif
#ifndef __STDC_VERSION__
@ -69,10 +72,6 @@
** You can override these in your C compiler options, e.g. '-DHAVE_GETTEXT=1'.
*/
#ifndef HAVE_DECL_ASCTIME_R
# define HAVE_DECL_ASCTIME_R 1
#endif
#if !defined HAVE__GENERIC && defined __has_extension
# if !__has_extension(c_generic_selections)
# define HAVE__GENERIC 0
@ -236,6 +235,31 @@
# include <unistd.h> /* for R_OK, and other POSIX goodness */
#endif /* HAVE_UNISTD_H */
/* SUPPORT_POSIX2008 means the tzcode library should support
POSIX.1-2017-and-earlier callers in addition to the usual support for
POSIX.1-2024-and-later callers; however, this can be
incompatible with POSIX.1-2024-and-later callers.
This macro is obsolescent, and the plan is to remove it
along with any code needed only when it is nonzero.
A good time to do that might be in the year 2034.
This macro's name is SUPPORT_POSIX2008 because _POSIX_VERSION == 200809
in POSIX.1-2017, a minor revision of POSIX.1-2008. */
#ifndef SUPPORT_POSIX2008
# if defined _POSIX_VERSION && _POSIX_VERSION <= 200809
# define SUPPORT_POSIX2008 1
# else
# define SUPPORT_POSIX2008 0
# endif
#endif
#ifndef HAVE_DECL_ASCTIME_R
# if SUPPORT_POSIX2008
# define HAVE_DECL_ASCTIME_R 1
# else
# define HAVE_DECL_ASCTIME_R 0
# endif
#endif
#ifndef HAVE_STRFTIME_L
# if _POSIX_VERSION < 200809
# define HAVE_STRFTIME_L 0
@ -460,14 +484,6 @@ typedef unsigned long uintmax_t;
# define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r)
#endif
#if 3 <= __GNUC__
# define ATTRIBUTE_MALLOC __attribute__((malloc))
# define ATTRIBUTE_FORMAT(spec) __attribute__((format spec))
#else
# define ATTRIBUTE_MALLOC /* empty */
# define ATTRIBUTE_FORMAT(spec) /* empty */
#endif
#if (defined __has_c_attribute \
&& (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__))
# define HAVE___HAS_C_ATTRIBUTE true
@ -535,24 +551,27 @@ typedef unsigned long uintmax_t;
# endif
#endif
#ifndef ATTRIBUTE_REPRODUCIBLE
# if 3 <= __GNUC__
# define ATTRIBUTE_REPRODUCIBLE __attribute__((pure))
# else
# define ATTRIBUTE_REPRODUCIBLE /* empty */
# endif
# define ATTRIBUTE_REPRODUCIBLE /* empty */
#endif
#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(unsequenced)
# define ATTRIBUTE_UNSEQUENCED [[unsequenced]]
# endif
/* GCC attributes that are useful in tzcode.
__attribute__((pure)) is stricter than [[reproducible]],
so the latter is an adequate substitute in non-GCC C23 platforms. */
#if __GNUC__ < 3
# define ATTRIBUTE_FORMAT(spec) /* empty */
# define ATTRIBUTE_PURE ATTRIBUTE_REPRODUCIBLE
#else
# define ATTRIBUTE_FORMAT(spec) __attribute__((format spec))
# define ATTRIBUTE_PURE __attribute__((pure))
#endif
#ifndef ATTRIBUTE_UNSEQUENCED
# if 3 <= __GNUC__
# define ATTRIBUTE_UNSEQUENCED __attribute__((const))
# else
# define ATTRIBUTE_UNSEQUENCED /* empty */
# endif
/* Avoid GCC bug 114833 <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114833>.
Remove this macro and its uses when the bug is fixed in a GCC release,
because only the latest GCC matters for $(GCC_DEBUG_FLAGS). */
#ifdef GCC_LINT
# define ATTRIBUTE_PURE_114833 ATTRIBUTE_PURE
#else
# define ATTRIBUTE_PURE_114833 /* empty */
#endif
#if (__STDC_VERSION__ < 199901 && !defined restrict \
@ -604,12 +623,8 @@ typedef time_tz tz_time_t;
# undef asctime
# define asctime tz_asctime
# undef asctime_r
# define asctime_r tz_asctime_r
# undef ctime
# define ctime tz_ctime
# undef ctime_r
# define ctime_r tz_ctime_r
# undef difftime
# define difftime tz_difftime
# undef gmtime
@ -654,6 +669,12 @@ typedef time_tz tz_time_t;
# define tzfree tz_tzfree
# undef tzset
# define tzset tz_tzset
# if SUPPORT_POSIX2008
# undef asctime_r
# define asctime_r tz_asctime_r
# undef ctime_r
# define ctime_r tz_ctime_r
# endif
# if HAVE_STRFTIME_L
# undef strftime_l
# define strftime_l tz_strftime_l
@ -679,10 +700,12 @@ typedef time_tz tz_time_t;
# define DEPRECATED_IN_C23 ATTRIBUTE_DEPRECATED
# endif
DEPRECATED_IN_C23 char *asctime(struct tm const *);
char *asctime_r(struct tm const *restrict, char *restrict);
DEPRECATED_IN_C23 char *ctime(time_t const *);
#if SUPPORT_POSIX2008
char *asctime_r(struct tm const *restrict, char *restrict);
char *ctime_r(time_t const *, char *);
ATTRIBUTE_UNSEQUENCED double difftime(time_t, time_t);
#endif
double difftime(time_t, time_t);
size_t strftime(char *restrict, size_t, char const *restrict,
struct tm const *restrict);
# if HAVE_STRFTIME_L
@ -713,7 +736,7 @@ void tzset(void);
time_t timegm(struct tm *);
#endif
#if !HAVE_DECL_ASCTIME_R && !defined asctime_r
#if !HAVE_DECL_ASCTIME_R && !defined asctime_r && SUPPORT_POSIX2008
extern char *asctime_r(struct tm const *restrict, char *restrict);
#endif
@ -798,10 +821,10 @@ timezone_t tzalloc(char const *);
void tzfree(timezone_t);
# if STD_INSPIRED
# if TZ_TIME_T || !defined posix2time_z
ATTRIBUTE_REPRODUCIBLE time_t posix2time_z(timezone_t, time_t);
ATTRIBUTE_PURE time_t posix2time_z(timezone_t, time_t);
# endif
# if TZ_TIME_T || !defined time2posix_z
ATTRIBUTE_REPRODUCIBLE time_t time2posix_z(timezone_t, time_t);
ATTRIBUTE_PURE time_t time2posix_z(timezone_t, time_t);
# endif
# endif
#endif
@ -973,8 +996,9 @@ enum {
/* How many years to generate (in zic.c) or search through (in localtime.c).
This is two years larger than the obvious 400, to avoid edge cases.
E.g., suppose a non-POSIX.1-2017 rule applies from 2012 on with transitions
in March and September, plus one-off transitions in November 2013.
E.g., suppose a rule applies from 2012 on with transitions
in March and September, plus one-off transitions in November 2013,
and suppose the rule cannot be expressed as a proleptic TZ string.
If zic looked only at the last 400 years, it would set max_year=2413,
with the intent that the 400 years 2014 through 2413 will be repeated.
The last transition listed in the tzfile would be in 2413-09,

View file

@ -89,13 +89,15 @@ 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: <a
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.
Because the database's scope encompasses real-world changes to civil
timekeeping, its model for describing time is more complex than the
standard and daylight saving times supported by POSIX.1-2017.
Edition), 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.
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
@ -159,7 +161,7 @@ among the following goals:
</ul>
<p>
Names normally have the form
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.
@ -187,7 +189,7 @@ in decreasing order of importance:
href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> letters,
'<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.1-2017
href="https://pubs.opengroup.org/onlinepubs/9699919799/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>'.
@ -378,7 +380,8 @@ nowadays distributions typically use it
and no great weight should be attached to whether a link
is defined in <code>backward</code> or in some other file.
The source file <code>etcetera</code> defines names that may be useful
on platforms that do not support POSIX.1-2017-style <code>TZ</code> strings;
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>,
@ -425,8 +428,8 @@ in decreasing order of importance:
In other words, in the C locale the POSIX extended regular
expression <code>[-+[:alnum:]]{3,6}</code> should match the
abbreviation.
This guarantees that all abbreviations could have been specified by a
POSIX.1-2017 <code>TZ</code> string.
This guarantees that all abbreviations could have been specified
explicitly by a POSIX proleptic <code>TZ</code> string.
</p>
</li>
<li>
@ -578,6 +581,11 @@ in decreasing order of importance:
some sense undefined; this notation is derived
from <a href="https://datatracker.ietf.org/doc/html/rfc3339">Internet
<abbr title="Request For Comments">RFC</abbr> 3339</a>.
(The abbreviation 'Z' that
<a href="https://datatracker.ietf.org/doc/html/rfc9557">Internet
<abbr>RFC</abbr> 9557</a> uses for this concept
would violate the POSIX requirement
of at least three characters in an abbreviation.)
</li>
</ul>
@ -775,7 +783,7 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes
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
provide only limited support for date and time localization
such as that required by POSIX.1-2017.
such as that required by POSIX.
If <abbr>DST</abbr> is not used a different time zone
can often do the trick; for example, in Kenya a <code>TZ</code> setting
like <code>&lt;-03&gt;3</code> or <code>America/Cayenne</code> starts
@ -866,29 +874,62 @@ Code compatible with this package is already
<a href="tz-link.html#tzdb">part of many platforms</a>, where the
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
<code>zic</code> supplied with this package instead of using the
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>
<h3 id="POSIX">POSIX.1-2017 properties and limitations</h3>
<p>
In POSIX, time display in a process is controlled by the
environment variable <code>TZ</code>, which can have two forms:
</p>
<ul>
<li>
A <dfn>proleptic <code>TZ</code></dfn> value
like <code>CET-1CEST,M3.5.0,M10.5.0/3</code> uses a complex
notation that specifies a single standard time along with daylight
saving rules that apply to all years past, present, and future.
</li>
<li>
A <dfn>geographical <code>TZ</code></dfn> value
like <code>Europe/Berlin</code> names a location that stands for
civil time near that location, which can have more than
one standard time and more than one set of daylight saving rules,
to record timekeeping practice more accurately.
These names are defined by the <code><abbr>tz</abbr></code> database.
</li>
</ul>
<h3 id="POSIX.1-2017">POSIX.1-2017 properties and limitations</h3>
<p>
Some platforms support only the features required by POSIX.1-2017,
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.
</p>
<ul>
<li>
POSIX.1-2017 does not require support for geographical <code>TZ</code>,
and there is no convenient and efficient way to determine
the <abbr>UT</abbr> offset and time zone abbreviation of arbitrary
timestamps, particularly for timezones
that do not fit into the POSIX model.
</li>
<li>
<p>
In POSIX.1-2017, time display in a process is controlled by the
environment variable <code>TZ</code>.
Unfortunately, the POSIX.1-2017
<code>TZ</code> string takes a form that is hard to describe and
is error-prone in practice.
Also, POSIX.1-2017 <code>TZ</code> strings cannot deal with daylight
The proleptic <code>TZ</code> string,
which is all that POSIX.1-2017 requires,
has a format that is hard to describe and is error-prone in practice.
Also, proleptic <code>TZ</code> strings cannot deal with daylight
saving time rules not based on the Gregorian calendar (as in
Morocco), or with situations where more than two time zone
abbreviations or <abbr>UT</abbr> offsets are used in an area.
</p>
<p>
The POSIX.1-2017 <code>TZ</code> string takes the following form:
A proleptic <code>TZ</code> string has the following format:
</p>
<p>
@ -955,7 +996,7 @@ an older <code>zic</code>.
</dl>
<p>
Here is an example POSIX.1-2017 <code>TZ</code> string for New
Here is an example proleptic <code>TZ</code> string for New
Zealand after 2007.
It says that standard time (<abbr>NZST</abbr>) is 12 hours ahead
of <abbr>UT</abbr>, and that daylight saving time
@ -966,26 +1007,46 @@ an older <code>zic</code>.
<pre><code>TZ='NZST-12NZDT,M9.5.0,M4.1.0/3'</code></pre>
<p>
This POSIX.1-2017 <code>TZ</code> string is hard to remember, and
This proleptic <code>TZ</code> string is hard to remember, and
mishandles some timestamps before 2008.
With this package you can use this instead:
With this package you can use a geographical <code>TZ</code> instead:
</p>
<pre><code>TZ='Pacific/Auckland'</code></pre>
</li>
</ul>
<p>
POSIX.1-2017 also has the limitations of POSIX.1-2024,
discussed in the next section.
</p>
<h3 id="POSIX.1-2024">POSIX.1-2024 properties and limitations</h3>
<p>
POSIX.1-2024 extends POSIX.1-2017 in the following significant ways:
</p>
<ul>
<li>
POSIX does not define the <abbr>DST</abbr> transitions
for <code>TZ</code> values like
"<code>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
time conversion package, and when
<abbr>US</abbr> time conversion rules changed (as in the United
States in 1987 and again in 2007), all packages that
interpreted <code>TZ</code> values had to be updated
to ensure proper results.
POSIX.1-2024 requires support for geographical <code>TZ</code>.
Earlier POSIX editions require support only for proleptic <code>TZ</code>.
</li>
<li>
POSIX.1-2024 requires <code>struct tm</code>
to have a <abbr>UT</abbr> offset member <code>tm_gmtoff</code>
and a time zone abbreviation member <code>tm_zone</code>.
Earlier POSIX editions lack this requirement.
</li>
<li>
DST transition times can range from &minus;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.
</li>
</ul>
<p>
However POSIX.1-2024, like earlier POSIX editions, has some limitations:
<ul>
<li>
The <code>TZ</code> environment variable is process-global, which
makes it hard to write efficient, thread-safe applications that
@ -1003,16 +1064,34 @@ an older <code>zic</code>.
handling daylight saving time shifts &ndash; as might be required to
limit phone calls to off-peak hours.
</li>
<li>
POSIX.1-2017 provides no convenient and efficient way to determine
the <abbr>UT</abbr> offset and time zone abbreviation of arbitrary
timestamps, particularly for timezones
that do not fit into the POSIX model.
</li>
<li>
POSIX requires that <code>time_t</code> clock counts exclude leap
seconds.
</li>
<li>
POSIX does not define the <abbr>DST</abbr> transitions
for <code>TZ</code> values like
"<code>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
time conversion package, and when
<abbr>US</abbr> time conversion rules changed (as in the United
States in 1987 and again in 2007), all packages that
interpreted <code>TZ</code> values had to be updated
to ensure proper results.
</li>
</ul>
<h3 id="POSIX-extensions">Extensions to POSIX in the
<code><abbr>tz</abbr></code> code</h3>
<p>
The <code><abbr>tz</abbr></code> code defines some properties
left unspecified by POSIX, and attempts to support some
extensions to POSIX.
</p>
<ul>
<li>
The <code><abbr>tz</abbr></code> code attempts to support all the
<code>time_t</code> implementations allowed by POSIX.
@ -1026,21 +1105,14 @@ an older <code>zic</code>.
and 40-bit integers are also used occasionally.
Although earlier POSIX versions allowed <code>time_t</code> to be a
floating-point type, this was not supported by any practical system,
and POSIX.1-2013 and the <code><abbr>tz</abbr></code> code both
and POSIX.1-2013+ and the <code><abbr>tz</abbr></code> code both
require <code>time_t</code> to be an integer type.
</li>
</ul>
<h3 id="POSIX-extensions">Extensions to POSIX.1-2017 in the
<code><abbr>tz</abbr></code> code</h3>
<ul>
<li>
<p>
The <code>TZ</code> environment variable is used in generating
the name of a file from which time-related information is read
(or is interpreted à la POSIX.1-2017); <code>TZ</code> is no longer
constrained to be a string containing abbreviations
and numeric data as described <a href="#POSIX">above</a>.
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>,
a timezone information format that contains binary data; see
<a href="https://datatracker.ietf.org/doc/html/8536">Internet
@ -1053,10 +1125,11 @@ an older <code>zic</code>.
abbreviations are used.
</p>
<p>
It was recognized that allowing the <code>TZ</code> environment
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
certain form) to operate incorrectly; consideration was given to using
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.
In the end, however, it was decided to continue using
@ -1069,15 +1142,6 @@ an older <code>zic</code>.
assume pre-POSIX <code>TZ</code> values.
</p>
</li>
<li>
The code supports platforms with a <abbr>UT</abbr> offset member
in <code>struct tm</code>, e.g., <code>tm_gmtoff</code>,
or with a time zone abbreviation member in
<code>struct tm</code>, e.g., <code>tm_zone</code>. As noted
in <a href="https://austingroupbugs.net/view.php?id=1533">Austin
Group defect 1533</a>, a future version of POSIX is planned to
require <code>tm_gmtoff</code> and <code>tm_zone</code>.
</li>
<li>
Functions <code>tzalloc</code>, <code>tzfree</code>,
<code>localtime_rz</code>, and <code>mktime_z</code> for
@ -1088,7 +1152,7 @@ an older <code>zic</code>.
and <code>localtime_rz</code> and <code>mktime_z</code> are
like <code>localtime_r</code> and <code>mktime</code> with an
extra <code>timezone_t</code> argument.
The functions were inspired by <a href="https://netbsd.org/">NetBSD</a>.
The functions were inspired by <a href="https://netbsd.org">NetBSD</a>.
</li>
<li>
Negative <code>time_t</code> values are supported, on systems
@ -1116,6 +1180,7 @@ The vestigial <abbr>API</abbr>s are:
<li>
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
the <code>tm_zone</code> member if available; otherwise,
use <code>strftime</code>'s <code>"%Z"</code> conversion
@ -1124,6 +1189,7 @@ The vestigial <abbr>API</abbr>s are:
<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
the <code>tm_gmtoff</code> member if available; otherwise,
subtract values returned by <code>localtime</code>
@ -1278,13 +1344,13 @@ between now and the future time.
<p>
Leap seconds were introduced in 1972 to accommodate the
difference between atomic time and the less regular rotation of the earth.
Unfortunately they caused so many problems with civil
timekeeping that they
are <a href="https://www.bipm.org/en/cgpm-2022/resolution-4">planned
to be discontinued by 2035</a>, with some as-yet-undetermined
mechanism replacing them, perhaps after the year 2135.
Despite their impending obsolescence, a record of leap seconds is still
needed to resolve timestamps from 1972 through 2035.
Unfortunately they have caused so many problems with civil
timekeeping that there are
<a href="https://www.bipm.org/en/cgpm-2022/resolution-4">plans
to discontinue them by 2035</a>.
Even if these plans come to fruition, a record of leap seconds will still be
needed to resolve timestamps from 1972 through 2035,
and there may also be a need to record whatever mechanism replaces them.
</p>
<p>
@ -1374,6 +1440,12 @@ href='https://www.esa.int/Applications/Navigation/Telling_time_on_the_Moon'>cons
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>
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>

View file

@ -228,6 +228,11 @@ of the 1999-11 <em>Atlantic Monthly</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>
Cory Doctorow, <a
href="https://craphound.com/est/download/"><em>Eastern Standard Tribe</em></a>,
2004. The world splinters into tribes characterized by their timezones.
</li>
</ul>
<h2>Music</h2>
<ul>

View file

@ -81,10 +81,11 @@ C Library</a> (used in
title="Berkeley Software Distribution">BSD</abbr></a>,
<a href="https://netbsd.org">Net<abbr>BSD</abbr></a>,
<a href="https://www.openbsd.org">Open<abbr>BSD</abbr></a>,
<a href="https://www.chromium.org/chromium-os/">Chromium OS</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>,
@ -112,9 +113,9 @@ eastern time but with different <abbr>DST</abbr> rules in 1975;
and other entries represent smaller regions like Starke County,
Indiana, which switched from central to eastern time in 1991
and switched back in 2006.
To use the database on an extended <a
To use the database on a <a
href="https://en.wikipedia.org/wiki/POSIX"><abbr
title="Portable Operating System Interface">POSIX</abbr>.1-2017</a>
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,
e.g., <code><abbr>TZ</abbr>="America/New_York"</code>.</p>
@ -192,9 +193,10 @@ After obtaining the code and data files, see the
<code>README</code> file for what to do next.
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 timezone information format (<dfn><abbr>TZif</abbr></dfn>)
specified by <a href="https://datatracker.ietf.org/doc/html/8536">Internet
<abbr>RFC</abbr> 8536</a>.
are in a special format specified by
<a href="https://datatracker.ietf.org/doc/html/8536">The
Time Zone Information Format (<abbr>TZif</abbr>)</a>
(Internet <abbr title="Request For Comments">RFC</abbr> 8536).
The code also lets
you read a <abbr>TZif</abbr> file and interpret timestamps for that
location.</p>
@ -205,13 +207,11 @@ location.</p>
<p>
The <code><abbr>tz</abbr></code> code and data
are by no means authoritative. If you find errors, please
send changes to <a href="mailto:tz@iana.org"><code>tz@iana.org</code></a>,
the time zone mailing list. You can also <a
href="https://mm.icann.org/mailman/listinfo/tz">subscribe</a> to it
and browse the <a
href="https://mm.icann.org/pipermail/tz/">archive of old
messages</a>.
<a href="https://tzdata-meta.timtimeonline.com/">Metadata for mailing list
email changes to <a href="mailto:tz@iana.org"><code>tz@iana.org</code></a>,
the time zone mailing list. 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.
<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>.
</p>
@ -226,7 +226,7 @@ the process by tailoring the generic instructions in
the <code><abbr>tz</abbr> README</code> file and installing the latest
data yourself. System-specific instructions for installing the
latest <code><abbr>tz</abbr></code> data have also been published
for <a href="https://developer.ibm.com/articles/au-aix-olson-time-zone/"><abbr>AIX</abbr></a>,
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>,
<a
@ -248,7 +248,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://wiki.gnome.org/Apps/Gedit">gedit</a>, and
<a href="https://gedit-technology.github.io/apps/gedit/">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
@ -261,8 +261,8 @@ Studio Code</a>.
<p>
For further information about updates, please see
<a href="https://datatracker.ietf.org/doc/html/rfc6557">Procedures for
Maintaining the Time Zone Database</a> (Internet <abbr
title="Request For Comments">RFC</abbr> 6557). More detail can be
Maintaining the Time Zone Database</a> (Internet <abbr>RFC</abbr> 6557).
More detail can be
found in <a href="theory.html">Theory and pragmatics of the
<code><abbr>tz</abbr></code> code and data</a>.
<a href="https://a0.github.io/a0-tzmigration/">A0 TimeZone Migration</a>
@ -400,7 +400,7 @@ variant <a href="https://datatracker.ietf.org/doc/html/rfc6321">xCal</a>
title="Extensible Markup Language">XML</abbr></a> format, and a variant
<a href="https://datatracker.ietf.org/doc/html/rfc7265">jCal</a>
(Internet <abbr>RFC</abbr> 7265)
uses <a href="https://www.json.org"><abbr
uses <a href="https://www.json.org/json-en.html"><abbr
title="JavaScript Object Notation">JSON</abbr></a> format.</li>
</ul>
</section>
@ -413,7 +413,7 @@ distributions you can generally work around compatibility problems by
running the command <code>make rearguard_tarballs</code> and compiling
from the resulting tarballs instead.</p>
<ul>
<li><a href="https://sourceforge.net/projects/vzic/">Vzic</a> is a <a
<li><a href="https://github.com/libical/vzic">Vzic</a> is a <a
href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a>
program that compiles
<code><abbr>tz</abbr></code> source into iCalendar-compatible VTIMEZONE files.
@ -440,11 +440,9 @@ transition in the <code><abbr>tz</abbr></code> database.</li>
<li>The <a href="https://howardhinnant.github.io/date/tz.html">Time Zone
Database Parser</a> is a
<a href="https://en.wikipedia.org/wiki/C++">C++</a> parser and
runtime library with <a
href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0355r7.html">API</a>
adopted by
<a href="https://en.wikipedia.org/wiki/C++20">C++20</a>,
the current iteration of the C++ standard.
runtime library with a <a
href="https://en.cppreference.com/w/cpp/chrono"><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>
<li><a id="ICU" href="https://icu.unicode.org">International Components for
@ -467,8 +465,8 @@ freely available under the <abbr>MIT</abbr> license.</li>
<li>The <a
href="https://www.oracle.com/java/technologies/javase/tzupdater-readme.html">TZUpdater
tool</a> compiles <code><abbr>tz</abbr></code> source into the format used by
<a href="https://openjdk.java.net/">OpenJDK</a> and
<a href="https://jdk.java.net/">Oracle JDK</a>.
<a href="https://openjdk.org">OpenJDK</a> and
<a href="https://jdk.java.net">Oracle JDK</a>.
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>
@ -490,7 +488,7 @@ 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
<a href="https://github.com/MenoData/Time4J/">Time4J: Advanced date,
<a href="https://github.com/MenoData/Time4J">Time4J: Advanced date,
time and interval library for Java</a> compile
<code><abbr>tz</abbr></code> source into a binary format.
Time4A is available under the Apache License and Time4J is
@ -516,7 +514,7 @@ many of which also support runtimes lacking the <code>timeZone</code> option.
href="https://github.com/formatjs/date-time-format-timezone"><code>Intl.DateTimeFormat</code>
timezone polyfill</a>
is freely available under a <abbr>BSD</abbr>-style license.</li>
<li>The <a href="https://date-fns.org/">date-fns</a>
<li>The <a href="https://date-fns.org">date-fns</a>
library manipulates timezone-aware timestamps in browsers and
in <a href="https://nodejs.org/en/">Node.js</a>.
It is freely available under the <abbr>MIT</abbr> license.</li>
@ -552,9 +550,9 @@ 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
problematic <code>Date</code> objects</a> when working with dates and times.
<li><a href="https://github.com/JuliaTime/">JuliaTime</a> contains a
<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
<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;
<abbr>IANA</abbr> Time Zone Database for Delphi/<abbr
@ -565,7 +563,7 @@ 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="http://pytz.sourceforge.net">pytz &ndash; World Timezone
<li><a href="https://pythonhosted.org/pytz/">pytz &ndash; 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.
@ -621,11 +619,11 @@ License.</li>
<a href="https://github.com/nayarsystems/posix_tz_db"><code>posix_tz_db</code>
package</a> contains Python code
to generate <abbr>CSV</abbr> and <abbr>JSON</abbr> tables that map
<code><abbr>tz</abbr></code> settings to POSIX.1-2017-like approximations.
<code><abbr>tz</abbr></code> settings to proleptic TZ approximations.
For example, it maps <code>"Africa/Cairo"</code>
to <code>"EET-2EEST,M4.5.5/0,M10.5.4/24"</code>,
an approximation valid for Cairo timestamps from 2023 on.
This can help porting to platforms that support only POSIX.1-2017.
This can help porting to platforms that support only proleptic TZ.
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
@ -649,7 +647,7 @@ that represent <code><abbr>tzdb</abbr></code> timezones.
Python is freely available under the
<a href="https://docs.python.org/3/license.html">Python Software Foundation
License</a>.
A companion <a id="pypi-tzdata" href="https://pypi.org/">PyPI</a> module
A companion <a id="pypi-tzdata" href="https://pypi.org">PyPI</a> module
<a href="https://pypi.org/project/tzdata/"><code>tzdata</code></a>
supplies TZif data if the underlying system data cannot be found;
it is freely available under the Apache License.</li>
@ -897,9 +895,10 @@ summarizes and cites historical <abbr>DST</abbr> regulations.</dd>
href="https://www.ptb.de/cms/en/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>The Interior Ministry periodically issues <a
href="ftp://ftp.cs.huji.ac.il/pub/tz/announcements"
hreflang="he">announcements (in Hebrew)</a>.</dd>
<dd><a
href="https://tz.cs.huji.ac.il">Israel Timezone Files</a>
lists official time-change announcements and laws since 1940,
almost all in Hebrew.</dd>
<dt>Malaysia</dt>
<dd>See Singapore <a href="#Singapore">below</a>.</dd>
<dt>Mexico</dt>
@ -1081,6 +1080,20 @@ In practice the two configurations also agree for timestamps before
1972 even though the historical situation is messy, partly because
neither <abbr>UTC</abbr> nor <abbr>TAI</abbr>
is well-defined for sufficiently old timestamps.</li>
<li><a href="https://kb.meinbergglobal.com/kb/time_sync/ntp/configuration/ntp_leap_second_file">The
<abbr>NTP</abbr> Leap Second File</a> covers the text file
<code>leap-seconds.list</code>, which lists the currently known leap seconds.
The <abbr>IERS</abbr> maintains this file, and a copy is distributed by
<code><abbr>tzdb</abbr></code> for use by <abbr>NTP</abbr> implementations like
<a href="https://www.ntp.org">classic
<code><abbr title="Network Time Protocol Daemon">ntpd</abbr></code></a>
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
example, <code>right/UTC</code> can be used
by <a href="https://chrony-project.org"><code>chrony</code></a>,
another <abbr>NTP</abbr> implementation.</li>
<li><a href="https://developers.google.com/time/smear">Leap Smear</a>
discusses how to gradually adjust <abbr>POSIX</abbr> clocks near a
leap second so that they disagree with <abbr>UTC</abbr> by at most a
@ -1088,7 +1101,7 @@ 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 <abbr>NTP</abbr> reference implementation, <a
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
@ -1111,11 +1124,18 @@ without Leap Seconds</a> gives pointers on this
contentious issue.
The General Conference on Weights and Measures
<a href="https://www.bipm.org/en/cgpm-2022/resolution-4">decided in 2022</a>
to discontinue the use of leap seconds by 2035, replacing them with an
as-yet-undetermined scheme some time after the year 2135.
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
decade until 2100, with leap smears after that gradually increasing in size.
However, there is still no consensus on whether this is the best way
to replace leap seconds.
</li>
</ul>
</section>
@ -1153,9 +1173,12 @@ headers.</li>
<li>
<a href="https://datatracker.ietf.org/doc/html/rfc3339">Date and Time
on the Internet: Timestamps</a> (Internet <abbr>RFC</abbr> 3339)
specifies an <abbr>ISO</abbr> 8601
profile for use in new Internet
protocols.</li>
specifies an <abbr>ISO</abbr> 8601 profile for use in new Internet protocols.
An extension, <a href="https://datatracker.ietf.org/doc/html/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>".
<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
@ -1173,8 +1196,8 @@ 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, the <abbr>POSIX</abbr>
<code><abbr>TZ</abbr></code> environment variable uses the opposite convention.
&minus;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
<code><abbr>TZ</abbr>="<abbr title="Hawaii Standard Time">HST</abbr>10"</code>

View file

@ -42,7 +42,7 @@ or
Fifteen bytes containing zeros reserved for future use.
.IP \(bu
Six four-byte integer values, in the following order:
.RS "\w' \(bu 'u"
.RS "\w'\(bu 'u"
.TP "\w' 'u"
.B tzh_ttisutcnt
The number of UT/local indicators stored in the file.
@ -66,6 +66,7 @@ in the file (must not be zero).
The number of bytes of time zone abbreviation strings
stored in the file.
.RE
.RE
.PP
The above header is followed by the following fields, whose lengths
depend on the contents of the header:
@ -85,7 +86,7 @@ described in the file is associated with the time period
starting with the same-indexed transition time
and continuing up to but not including the next transition time.
(The last time type is present only for consistency checking with the
POSIX.1-2017-style TZ string described below.)
proleptic TZ string described below.)
These values serve as indices into the next field.
.IP \(bu
.B tzh_typecnt
@ -134,8 +135,7 @@ Also, in realistic applications
is in the range [\-89999, 93599] (i.e., more than \-25 hours and less
than 26 hours); this allows easy support by implementations that
already support the POSIX-required range [\-24:59:59, 25:59:59].
.RS "\w' 'u"
.IP \(bu "\w'\(bu 'u"
.IP \(bu
.B tzh_charcnt
bytes that represent time zone designations,
which are null-terminated byte strings, each indexed by the
@ -187,12 +187,12 @@ must also be set.
The standard/wall and UT/local indicators were designed for
transforming a TZif file's transition times into transitions appropriate
for another time zone specified via
a POSIX.1-2017-style TZ string that lacks rules.
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.
POSIX does not specify this obsolete transformational behavior,
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
@ -217,12 +217,12 @@ identical in format except that
eight bytes are used for each transition time or leap second time.
(Leap second counts remain four bytes.)
After the second header and data comes a newline-enclosed string
in the style of the contents of a POSIX.1-2017 TZ environment variable,
in the style of the contents of a proleptic TZ,
for use in handling instants
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 POSIX.1-2017-style representation for such instants.
if there is no proleptic representation for such instants.
If nonempty, 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
@ -235,13 +235,14 @@ 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.
.SS Version 3 format
For version-3-format timezone files, the TZ string may
use two minor extensions to the POSIX.1-2017 TZ format, as described in
.BR newtzset (3).
First, the hours part of its transition times may be signed and range from
\-167 through 167 instead of the POSIX-required unsigned values
For version-3-format timezone files, a TZ string (see
.BR newtzset (3))
may use the following POSIX.1-2024 extensions to POSIX.1-2017:
First, as in TZ="<\*-02>2<\*-01>,M3.5.0/\*-1,M10.5.0/0",
the hours part of its transition times may be signed and range from
\-167 through 167 instead of being limited to unsigned values
from 0 through 24.
Second, DST is in effect all year if it starts
Second, as in TZ="XXX3EDT4,0/0,J365/23", DST is in effect all year if it starts
January 1 at 00:00 and ends December 31 at 24:00 plus the difference
between daylight saving and standard time.
.SS Version 4 format
@ -354,7 +355,8 @@ version 2+ data even if the reader's native timestamps have only
.IP \(bu
Some readers designed for version 2 might mishandle
timestamps after a version 3 or higher file's last transition, because
they cannot parse extensions to POSIX.1-2017 in the TZ-like string.
they cannot parse the POSIX.1-2024 extensions to POSIX.1-2017
in the proleptic TZ string.
As a partial workaround, a writer can output more transitions
than necessary, so that only far-future timestamps are
mishandled by version 2 readers.
@ -386,6 +388,18 @@ timestamps from the time type of the last transition.
As a partial workaround, a writer can output more transitions
than necessary.
.IP \(bu
Some stripped-down readers ignore everything but the footer,
and use its proleptic TZ string to calculate all timestamps.
Although this approach often works for current and future timestamps,
it obviously has problems with past timestamps,
and even for current timestamps it can fail for settings like
TZ="Africa/Casablanca". This corresponds to a TZif file
containing explicit transitions through the year 2087,
followed by a footer containing the TZ string
.q <+01>\*-1 ,
which should be used only for timestamps after the last
explicit transition.
.IP \(bu
Some readers do not use time type 0 for timestamps before
the first transition, in that they infer a time type using a
heuristic that does not always select time type 0.

View file

@ -24,276 +24,284 @@ DESCRIPTION
o Six four-byte integer values, in the following order:
tzh_ttisutcnt
The number of UT/local indicators stored in the file. (UT
is Universal Time.)
tzh_ttisutcnt
The number of UT/local indicators stored in the file. (UT is
Universal Time.)
tzh_ttisstdcnt
The number of standard/wall indicators stored in the file.
tzh_ttisstdcnt
The number of standard/wall indicators stored in the file.
tzh_leapcnt
The number of leap seconds for which data entries are stored
in the file.
tzh_leapcnt
The number of leap seconds for which data entries are stored
in the file.
tzh_timecnt
The number of transition times for which data entries are
stored in the file.
tzh_timecnt
The number of transition times for which data entries are
stored in the file.
tzh_typecnt
The number of local time types for which data entries are
stored in the file (must not be zero).
tzh_typecnt
The number of local time types for which data entries are
stored in the file (must not be zero).
tzh_charcnt
The number of bytes of time zone abbreviation strings stored
in the file.
tzh_charcnt
The number of bytes of time zone abbreviation strings stored
in the file.
The above header is followed by the following fields, whose lengths
depend on the contents of the header:
The above header is followed by the following fields, whose lengths
depend on the contents of the header:
o tzh_timecnt four-byte signed integer values sorted in ascending
order. These values are written in network byte order. Each is
used as a transition time (as returned by time(2)) at which the
rules for computing local time change.
o tzh_timecnt four-byte signed integer values sorted in ascending
order. These values are written in network byte order. Each is
used as a transition time (as returned by time(2)) at which the
rules for computing local time change.
o tzh_timecnt one-byte unsigned integer values; each one but the
last tells which of the different types of local time types
described in the file is associated with the time period
starting with the same-indexed transition time and continuing up
to but not including the next transition time. (The last time
type is present only for consistency checking with the
POSIX.1-2017-style TZ string described below.) These values
serve as indices into the next field.
o tzh_timecnt one-byte unsigned integer values; each one but the
last tells which of the different types of local time types
described in the file is associated with the time period starting
with the same-indexed transition time and continuing up to but not
including the next transition time. (The last time type is
present only for consistency checking with the proleptic TZ string
described below.) These values serve as indices into the next
field.
o tzh_typecnt ttinfo entries, each defined as follows:
o tzh_typecnt ttinfo entries, each defined as follows:
struct ttinfo {
int32_t tt_utoff;
unsigned char tt_isdst;
unsigned char tt_desigidx;
};
struct ttinfo {
int32_t tt_utoff;
unsigned char tt_isdst;
unsigned char tt_desigidx;
};
Each structure is written as a four-byte signed integer value
for tt_utoff, in network byte order, followed by a one-byte
boolean for tt_isdst and a one-byte value for tt_desigidx. In
each structure, tt_utoff gives the number of seconds to be added
to UT, tt_isdst tells whether tm_isdst should be set by
localtime(3) and tt_desigidx serves as an index into the array
of time zone abbreviation bytes that follow the ttinfo entries
in the file; if the designated string is "-00", the ttinfo entry
is a placeholder indicating that local time is unspecified. The
tt_utoff value is never equal to -2**31, to let 32-bit clients
negate it without overflow. Also, in realistic applications
tt_utoff is in the range [-89999, 93599] (i.e., more than -25
hours and less than 26 hours); this allows easy support by
implementations that already support the POSIX-required range
[-24:59:59, 25:59:59].
Each structure is written as a four-byte signed integer value for
tt_utoff, in network byte order, followed by a one-byte boolean
for tt_isdst and a one-byte value for tt_desigidx. In each
structure, tt_utoff gives the number of seconds to be added to UT,
tt_isdst tells whether tm_isdst should be set by localtime(3) and
tt_desigidx serves as an index into the array of time zone
abbreviation bytes that follow the ttinfo entries in the file; if
the designated string is "-00", the ttinfo entry is a placeholder
indicating that local time is unspecified. The tt_utoff value is
never equal to -2**31, to let 32-bit clients negate it without
overflow. Also, in realistic applications tt_utoff is in the
range [-89999, 93599] (i.e., more than -25 hours and less than 26
hours); this allows easy support by implementations that already
support the POSIX-required range [-24:59:59, 25:59:59].
o tzh_charcnt bytes that represent time zone designations, which
are null-terminated byte strings, each indexed by the
tt_desigidx values mentioned above. The byte strings can
overlap if one is a suffix of the other. The encoding of
these strings is not specified.
o tzh_charcnt bytes that represent time zone designations, which are
null-terminated byte strings, each indexed by the tt_desigidx
values mentioned above. The byte strings can overlap if one is a
suffix of the other. The encoding of these strings is not
specified.
o tzh_leapcnt pairs of four-byte values, written in network byte
order; the first value of each pair gives the nonnegative time
(as returned by time(2)) at which a leap second occurs or at
which the leap second table expires; the second is a signed
integer specifying the correction, which is the total number
of leap seconds to be applied during the time period starting
at the given time. The pairs of values are sorted in strictly
ascending order by time. Each pair denotes one leap second,
either positive or negative, except that if the last pair has
the same correction as the previous one, the last pair denotes
the leap second table's expiration time. Each leap second is
at the end of a UTC calendar month. The first leap second has
a nonnegative occurrence time, and is a positive leap second
if and only if its correction is positive; the correction for
each leap second after the first differs from the previous
leap second by either 1 for a positive leap second, or -1 for
a negative leap second. If the leap second table is empty,
the leap-second correction is zero for all timestamps;
otherwise, for timestamps before the first occurrence time,
the leap-second correction is zero if the first pair's
correction is 1 or -1, and is unspecified otherwise (which can
happen only in files truncated at the start).
o tzh_leapcnt pairs of four-byte values, written in network byte
order; the first value of each pair gives the nonnegative time (as
returned by time(2)) at which a leap second occurs or at which the
leap second table expires; the second is a signed integer
specifying the correction, which is the total number of leap
seconds to be applied during the time period starting at the given
time. The pairs of values are sorted in strictly ascending order
by time. Each pair denotes one leap second, either positive or
negative, except that if the last pair has the same correction as
the previous one, the last pair denotes the leap second table's
expiration time. Each leap second is at the end of a UTC calendar
month. The first leap second has a nonnegative occurrence time,
and is a positive leap second if and only if its correction is
positive; the correction for each leap second after the first
differs from the previous leap second by either 1 for a positive
leap second, or -1 for a negative leap second. If the leap second
table is empty, the leap-second correction is zero for all
timestamps; otherwise, for timestamps before the first occurrence
time, the leap-second correction is zero if the first pair's
correction is 1 or -1, and is unspecified otherwise (which can
happen only in files truncated at the start).
o tzh_ttisstdcnt standard/wall indicators, each stored as a one-
byte boolean; they tell whether the transition times
associated with local time types were specified as standard
time or local (wall clock) time.
o tzh_ttisstdcnt standard/wall indicators, each stored as a one-byte
boolean; they tell whether the transition times associated with
local time types were specified as standard time or local (wall
clock) time.
o tzh_ttisutcnt UT/local indicators, each stored as a one-byte
boolean; they tell whether the transition times associated
with local time types were specified as UT or local time. If
a UT/local indicator is set, the corresponding standard/wall
indicator must also be set.
o tzh_ttisutcnt UT/local indicators, each stored as a one-byte
boolean; they tell whether the transition times associated with
local time types were specified as UT or local time. If a
UT/local indicator is set, the corresponding standard/wall
indicator must also be set.
The standard/wall and UT/local indicators were designed for
transforming a TZif file's transition times into transitions
appropriate for another time zone specified via a
POSIX.1-2017-style 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. POSIX does not specify 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
and older timestamps need not be handled accurately.
The standard/wall and UT/local indicators were designed for
transforming a TZif file's transition times into transitions
appropriate 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. 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
and older timestamps need not be handled accurately.
The localtime(3) function normally uses the first ttinfo structure
in the file if either tzh_timecnt is zero or the time argument is
less than the first transition time recorded in the file.
The localtime(3) function normally uses the first ttinfo structure in
the file if either tzh_timecnt is zero or the time argument is less
than the first transition time recorded in the file.
Version 2 format
For version-2-format timezone files, the above header and data are
followed by a second header and data, identical in format except that
eight bytes are used for each transition time or leap second time.
(Leap second counts remain four bytes.) After the second header and
data comes a newline-enclosed string in the style of the contents of a
POSIX.1-2017 TZ environment variable, for use in handling instants
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 POSIX.1-2017-style representation
for such instants. If nonempty, 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 "WET0WEST,M3.5.0/1,M10.5.0"
then if a last transition time is in July, the transition's local time
type must specify a daylight-saving time abbreviated "WEST" that is one
hour east of UT. 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.
For version-2-format timezone files, the above header and data are
followed by a second header and data, identical in format except that
eight bytes are used for each transition time or leap second time.
(Leap second counts remain four bytes.) After the second header and
data comes a newline-enclosed string in the style of the contents of a
proleptic TZ, for use in handling instants 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.
If nonempty, 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 "WET0WEST,M3.5.0/1,M10.5.0" then if a last
transition time is in July, the transition's local time type must
specify a daylight-saving time abbreviated "WEST" that is one hour east
of UT. 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.
Version 3 format
For version-3-format timezone files, the TZ string may use two minor
extensions to the POSIX.1-2017 TZ format, as described in newtzset(3).
First, the hours part of its transition times may be signed and range
from -167 through 167 instead of the POSIX-required unsigned values
from 0 through 24. Second, DST is in effect all year if it starts
January 1 at 00:00 and ends December 31 at 24:00 plus the difference
For version-3-format timezone files, a TZ string (see newtzset(3)) may
use the following POSIX.1-2024 extensions to POSIX.1-2017: First, as in
TZ="<-02>2<-01>,M3.5.0/-1,M10.5.0/0", the hours part of its transition
times may be signed and range from -167 through 167 instead of being
limited to unsigned values from 0 through 24. Second, as in
TZ="XXX3EDT4,0/0,J365/23", DST is in effect all year if it starts
January 1 at 00:00 and ends December 31 at 24:00 plus the difference
between daylight saving and standard time.
Version 4 format
For version-4-format TZif files, the first leap second record can have
a correction that is neither +1 nor -1, to represent truncation of the
TZif file at the start. Also, if two or more leap second transitions
are present and the last entry's correction equals the previous one,
the last entry denotes the expiration of the leap second table instead
of a leap second; timestamps after this expiration are unreliable in
that future releases will likely add leap second entries after the
expiration, and the added leap seconds will change how post-expiration
For version-4-format TZif files, the first leap second record can have
a correction that is neither +1 nor -1, to represent truncation of the
TZif file at the start. Also, if two or more leap second transitions
are present and the last entry's correction equals the previous one,
the last entry denotes the expiration of the leap second table instead
of a leap second; timestamps after this expiration are unreliable in
that future releases will likely add leap second entries after the
expiration, and the added leap seconds will change how post-expiration
timestamps are treated.
Interoperability considerations
Future changes to the format may append more data.
Version 1 files are considered a legacy format and should not be
Version 1 files are considered a legacy format and should not be
generated, as they do not support transition times after the year 2038.
Readers that understand only Version 1 must ignore any data that
Readers that understand only Version 1 must ignore any data that
extends beyond the calculated end of the version 1 data block.
Other than version 1, writers should generate the lowest version number
needed by a file's data. For example, a writer should generate a
version 4 file only if its leap second table either expires or is
truncated at the start. Likewise, a writer not generating a version 4
file should generate a version 3 file only if TZ string extensions are
needed by a file's data. For example, a writer should generate a
version 4 file only if its leap second table either expires or is
truncated at the start. Likewise, a writer not generating a version 4
file should generate a version 3 file only if TZ string extensions are
necessary to accurately model transition times.
The sequence of time changes defined by the version 1 header and data
block should be a contiguous sub-sequence of the time changes defined
by the version 2+ header and data block, and by the footer. This
guideline helps obsolescent version 1 readers agree with current
readers about timestamps within the contiguous sub-sequence. It also
lets writers not supporting obsolescent readers use a tzh_timecnt of
The sequence of time changes defined by the version 1 header and data
block should be a contiguous sub-sequence of the time changes defined
by the version 2+ header and data block, and by the footer. This
guideline helps obsolescent version 1 readers agree with current
readers about timestamps within the contiguous sub-sequence. It also
lets writers not supporting obsolescent readers use a tzh_timecnt of
zero in the version 1 data block to save space.
When a TZif file contains a leap second table expiration 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
When a TZif file contains a leap second table expiration 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).
Time zone designations should consist of at least three (3) and no more
than six (6) ASCII characters from the set of alphanumerics, "-", and
"+". This is for compatibility with POSIX requirements for time zone
than six (6) ASCII characters from the set of alphanumerics, "-", and
"+". This is for compatibility with POSIX requirements for time zone
abbreviations.
When reading a version 2 or higher file, readers should ignore the
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.
Readers should calculate the total lengths of the headers and data
Readers should calculate the total lengths of the headers and data
blocks and check that they all fit within the actual file size, as part
of a validity check for the file.
When a positive leap second occurs, readers should append an extra
second to the local minute containing the second just before the leap
second. If this occurs when the UTC offset is not a multiple of 60
seconds, the leap second occurs earlier than the last second of the
local minute and the minute's remaining local seconds are numbered
When a positive leap second occurs, readers should append an extra
second to the local minute containing the second just before the leap
second. If this occurs when the UTC offset is not a multiple of 60
seconds, the leap second occurs earlier than the last second of the
local minute and the minute's remaining local seconds are numbered
through 60 instead of the usual 59; the UTC offset is unaffected.
Common interoperability issues
This section documents common problems in reading or writing TZif
files. Most of these are problems in generating TZif files for use by
This section documents common problems in reading or writing TZif
files. Most of these are problems in generating TZif files for use by
older readers. The goals of this section are:
o to help TZif writers output files that avoid common pitfalls in
o to help TZif writers output files that avoid common pitfalls in
older or buggy TZif readers,
o to help TZif readers avoid common pitfalls when reading files
o to help TZif readers avoid common pitfalls when reading files
generated by future TZif writers, and
o to help any future specification authors see what sort of problems
arise when the TZif format is changed.
When new versions of the TZif format have been defined, a design goal
has been that a reader can successfully use a TZif file even if the
file is of a later TZif version than what the reader was designed for.
When complete compatibility was not achieved, an attempt was made to
limit glitches to rarely used timestamps and allow simple partial
workarounds in writers designed to generate new-version data useful
even for older-version readers. This section attempts to document
these compatibility issues and workarounds, as well as to document
When new versions of the TZif format have been defined, a design goal
has been that a reader can successfully use a TZif file even if the
file is of a later TZif version than what the reader was designed for.
When complete compatibility was not achieved, an attempt was made to
limit glitches to rarely used timestamps and allow simple partial
workarounds in writers designed to generate new-version data useful
even for older-version readers. This section attempts to document
these compatibility issues and workarounds, as well as to document
other common bugs in readers.
Interoperability problems with TZif include the following:
o Some readers examine only version 1 data. As a partial
workaround, a writer can output as much version 1 data as
possible. However, a reader should ignore version 1 data, and
should use version 2+ data even if the reader's native timestamps
o Some readers examine only version 1 data. As a partial
workaround, a writer can output as much version 1 data as
possible. However, a reader should ignore version 1 data, and
should use version 2+ data even if the reader's native timestamps
have only 32 bits.
o Some readers designed for version 2 might mishandle timestamps
after a version 3 or higher file's last transition, because they
cannot parse extensions to POSIX.1-2017 in the TZ-like string. As
a partial workaround, a writer can output more transitions than
necessary, so that only far-future timestamps are mishandled by
version 2 readers.
o Some readers designed for version 2 might mishandle timestamps
after a version 3 or higher file's last transition, because they
cannot parse the POSIX.1-2024 extensions to POSIX.1-2017 in the
proleptic TZ string. As a partial workaround, a writer can output
more transitions than necessary, so that only far-future
timestamps are mishandled by version 2 readers.
o Some readers designed for version 2 do not support permanent
daylight saving time with transitions after 24:00 - e.g., a TZ
string "EST5EDT,0/0,J365/25" denoting permanent Eastern Daylight
Time (-04). As a workaround, a writer can substitute standard
time for two time zones east, e.g., "XXX3EDT4,0/0,J365/23" for a
time zone with a never-used standard time (XXX, -03) and negative
daylight saving time (EDT, -04) all year. Alternatively, as a
partial workaround a writer can substitute standard time for the
o Some readers designed for version 2 do not support permanent
daylight saving time with transitions after 24:00 - e.g., a TZ
string "EST5EDT,0/0,J365/25" denoting permanent Eastern Daylight
Time (-04). As a workaround, a writer can substitute standard
time for two time zones east, e.g., "XXX3EDT4,0/0,J365/23" for a
time zone with a never-used standard time (XXX, -03) and negative
daylight saving time (EDT, -04) all year. Alternatively, as a
partial workaround a writer can substitute standard time for the
next time zone east - e.g., "AST4" for permanent Atlantic Standard
Time (-04).
o Some readers designed for version 2 or 3, and that require strict
conformance to RFC 8536, reject version 4 files whose leap second
o Some readers designed for version 2 or 3, and that require strict
conformance to RFC 8536, reject version 4 files whose leap second
tables are truncated at the start or that end in expiration times.
o Some readers ignore the footer, and instead predict future
timestamps from the time type of the last transition. As a
partial workaround, a writer can output more transitions than
timestamps from the time type of the last transition. As a
partial workaround, a writer can output more transitions than
necessary.
o Some stripped-down readers ignore everything but the footer, and
use its proleptic TZ string to calculate all timestamps. Although
this approach often works for current and future timestamps, it
obviously has problems with past timestamps, and even for current
timestamps it can fail for settings like TZ="Africa/Casablanca".
This corresponds to a TZif file containing explicit transitions
through the year 2087, followed by a footer containing the TZ
string "<+01>-1", which should be used only for timestamps after
the last explicit transition.
o Some readers do not use time type 0 for timestamps before the
first transition, in that they infer a time type using a heuristic
that does not always select time type 0. As a partial workaround,

View file

@ -76,14 +76,16 @@ struct tzhead {
** If tzh_version is '2' or greater, the above is followed by a second instance
** of tzhead and a second instance of the data in which each coded transition
** time uses 8 rather than 4 chars,
** then a POSIX-TZ-environment-variable-style string for use in handling
** then a POSIX.1-2017 proleptic TZ string for use in handling
** instants after the last transition time stored in the file
** (with nothing between the newlines if there is no POSIX.1-2017
** representation for such instants).
**
** If tz_version is '3' or greater, the above is extended as follows.
** If tz_version is '3' or greater, the TZ string can be any POSIX.1-2024
** proleptic TZ string, which means the above is extended as follows.
** First, the TZ string's hour offset may range from -167
** through 167 as compared to the POSIX-required 0 through 24.
** through 167 as compared to the range 0 through 24 required
** by POSIX.1-2017 and earlier.
** Second, its DST start time may be January 1 at 00:00 and its stop
** time December 31 at 24:00 plus the difference between DST and
** standard time, indicating DST all year.

View file

@ -20,12 +20,6 @@ REPORT_BUGS_TO=tz@iana.org
# Korn Shell <http://www.kornshell.com/>
# MirBSD Korn Shell <http://www.mirbsd.org/mksh.htm>
#
# For portability to Solaris 10 /bin/sh (supported by Oracle through
# January 2027) this script avoids some POSIX features and common
# extensions, such as $(...), $((...)), ! CMD, unquoted ^, ${#ID},
# ${ID##PAT}, ${ID%%PAT}, and $10. Although some of these constructs
# work sometimes, it's simpler to avoid them entirely.
#
# This script also uses several features of POSIX awk.
# If your host lacks awk, or has an old awk that does not conform to POSIX,
# you can use any of the following free programs instead:
@ -45,7 +39,6 @@ set -f
# Specify default values for environment variables if they are unset.
: ${AWK=awk}
: ${PWD=`pwd`}
: ${TZDIR=$PWD}
# Output one argument as-is to standard output, with trailing newline.
@ -54,13 +47,6 @@ say() {
printf '%s\n' "$1"
}
# Check for awk POSIX compliance.
($AWK -v x=y 'BEGIN { exit 123 }') <>/dev/null >&0 2>&0
[ $? = 123 ] || {
say >&2 "$0: Sorry, your '$AWK' program is not POSIX compatible."
exit 1
}
coord=
location_limit=10
zonetabtype=zone1970
@ -117,8 +103,7 @@ then
else
doselect() {
# Field width of the prompt numbers.
print_nargs_length="BEGIN {print length(\"$#\");}"
select_width=`$AWK "$print_nargs_length"`
select_width=${##}
select_i=
@ -129,14 +114,14 @@ else
select_i=0
for select_word
do
select_i=`$AWK "BEGIN { print $select_i + 1 }"`
select_i=$(($select_i + 1))
printf >&2 "%${select_width}d) %s\\n" $select_i "$select_word"
done;;
*[!0-9]*)
echo >&2 'Please enter a number in range.';;
*)
if test 1 -le $select_i && test $select_i -le $#; then
shift `$AWK "BEGIN { print $select_i - 1 }"`
shift $(($select_i - 1))
select_result=$1
break
fi
@ -170,7 +155,7 @@ do
esac
done
shift `$AWK "BEGIN { print $OPTIND - 1 }"`
shift $(($OPTIND - 1))
case $# in
0) ;;
*) say >&2 "$0: $1: unknown argument"; exit 1
@ -178,11 +163,13 @@ esac
# translit=true to try transliteration.
# This is false if U+12345 CUNEIFORM SIGN URU TIMES KI has length 1
# which means awk (and presumably the shell) do not need transliteration.
if $AWK 'BEGIN { u12345 = "\360\222\215\205"; exit length(u12345) == 1 }'; then
translit=true
else
translit=false
# 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
# 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
fi
# Read into shell variable $1 the contents of file $2.
@ -192,10 +179,10 @@ fi
# if that does not work, fall back on 'cat'.
read_file() {
{ $translit && {
eval "$1=\`(iconv -f UTF-8 -t //TRANSLIT) 2>/dev/null <\"\$2\"\`" ||
eval "$1=\`(iconv -f UTF-8) 2>/dev/null <\"\$2\"\`"
eval "$1=\$( (iconv -f UTF-8 -t //TRANSLIT) 2>/dev/null <\"\$2\")" ||
eval "$1=\$( (iconv -f UTF-8) 2>/dev/null <\"\$2\")"
}; } ||
eval "$1=\`cat <\"\$2\"\`" || {
eval "$1=\$(cat <\"\$2\")" || {
say >&2 "$0: time zone files are not set up correctly"
exit 1
}
@ -403,7 +390,7 @@ while
echo >&2 \
'Please select a continent, ocean, "coord", "TZ", "time", or "now".'
quoted_continents=`
quoted_continents=$(
$AWK '
function handle_entry(entry) {
entry = substr(entry, 1, index(entry, "/") - 1)
@ -433,12 +420,12 @@ while
sort -u |
tr '\n' ' '
echo ''
`
)
eval '
doselect '"$quoted_continents"' \
"coord - I want to use geographical coordinates." \
"TZ - I want to specify the timezone using a POSIX.1-2017 TZ string." \
"TZ - I want to specify the timezone using a proleptic TZ string." \
"time - I know local time already." \
"now - Like \"time\", but configure only for timestamps from now on."
continent=$select_result
@ -462,16 +449,17 @@ while
case $continent in
TZ)
# Ask the user for a POSIX.1-2017 TZ string. Check that it conforms.
# Ask the user for a proleptic TZ string. Check that it conforms.
check_POSIX_TZ_string='
BEGIN {
tz = substr(ARGV[1], 2)
ARGV[1] = ""
tzname = ("(<[[:alnum:]+-][[:alnum:]+-][[:alnum:]+-]+>" \
"|[[:alpha:]][[:alpha:]][[:alpha:]]+)")
time = ("(2[0-4]|[0-1]?[0-9])" \
"(:[0-5][0-9](:[0-5][0-9])?)?")
offset = "[-+]?" time
sign = "[-+]?"
hhmm = "(:[0-5][0-9](:[0-5][0-9])?)?"
offset = sign "(2[0-4]|[0-1]?[0-9])" hhmm
time = sign "(16[0-7]|(1[0-5]|[0-9]?)[0-9])" hhmm
mdate = "M([1-9]|1[0-2])\\.[1-5]\\.[0-6]"
jdate = ("((J[1-9]|[0-9]|J?[1-9][0-9]" \
"|J?[1-2][0-9][0-9])|J?3[0-5][0-9]|J?36[0-5])")
@ -492,7 +480,7 @@ while
read tz
$AWK "$check_POSIX_TZ_string" ="$tz"
do
say >&2 "'$tz' is not a conforming POSIX.1-2017 timezone string."
say >&2 "'$tz' is not a conforming POSIX proleptic TZ string."
done
TZ_for_date=$tz;;
*)
@ -507,14 +495,14 @@ while
'74 degrees 3 minutes west.'
read coord
esac
distance_table=`
distance_table=$(
$AWK \
"$output_distances_or_times" \
="$coord" ="$TZ_COUNTRY_TABLE" ="$TZ_ZONE_TABLE" |
sort -n |
$AWK "{print} NR == $location_limit { exit }"
`
regions=`
)
regions=$(
$AWK '
BEGIN {
distance_table = substr(ARGV[1], 2)
@ -526,13 +514,13 @@ while
}
}
' ="$distance_table"
`
)
echo >&2 'Please select one of the following timezones,'
echo >&2 'listed roughly in increasing order' \
"of distance from $coord".
doselect $regions
region=$select_result
tz=`
tz=$(
$AWK '
BEGIN {
distance_table = substr(ARGV[1], 2)
@ -546,22 +534,22 @@ while
}
}
' ="$distance_table" ="$region"
`;;
);;
*)
case $continent in
now|time)
minute_format='%a %b %d %H:%M'
old_minute=`TZ=UTC0 date +"$minute_format"`
old_minute=$(TZ=UTC0 date +"$minute_format")
for i in 1 2 3
do
time_table_command=`
time_table_command=$(
$AWK \
-v output_times=1 \
"$output_distances_or_times" \
= = ="$TZ_ZONE_TABLE"
`
time_table=`eval "$time_table_command"`
new_minute=`TZ=UTC0 date +"$minute_format"`
)
time_table=$(eval "$time_table_command")
new_minute=$(TZ=UTC0 date +"$minute_format")
case $old_minute in
"$new_minute") break
esac
@ -569,11 +557,11 @@ while
done
echo >&2 "The system says Universal Time is $new_minute."
echo >&2 "Assuming that's correct, what is the local time?"
sorted_table=`say "$time_table" | sort -k2n -k2,5 -k1n` || {
sorted_table=$(say "$time_table" | sort -k2n -k2,5 -k1n) || {
say >&2 "$0: cannot sort time table"
exit 1
}
eval doselect `
eval doselect $(
$AWK '
BEGIN {
sorted_table = substr(ARGV[1], 2)
@ -590,10 +578,10 @@ while
}
}
' ="$sorted_table"
`
)
time=$select_result
continent_re='^'
zone_table=`
zone_table=$(
$AWK '
BEGIN {
time = substr(ARGV[1], 2)
@ -609,13 +597,13 @@ while
}
}
' ="$time" ="$time_table"
`
countries=`
)
countries=$(
$AWK \
"$output_country_list" \
="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" |
sort -f
`
)
;;
*)
continent_re="^$continent/"
@ -623,16 +611,16 @@ while
esac
# Get list of names of countries in the continent or ocean.
countries=`
countries=$(
$AWK \
"$output_country_list" \
="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" |
sort -f
`
)
# If all zone table entries have comments, and there are
# at most 22 entries, asked based on those comments.
# This fits the prompt onto old-fashioned 24-line screens.
regions=`
regions=$(
$AWK '
BEGIN {
TZ_ZONE_TABLE = substr(ARGV[1], 2)
@ -653,7 +641,7 @@ while
print comment[i]
}
' ="$zone_table"
`
)
# If there's more than one country, ask the user which one.
case $countries in
@ -669,7 +657,7 @@ while
# Get list of timezones in the country.
regions=`
regions=$(
$AWK '
BEGIN {
country = substr(ARGV[1], 2)
@ -696,7 +684,7 @@ while
}
}
' ="$country" ="$TZ_COUNTRY_TABLE" ="$zone_table"
`
)
# If there's more than one region, ask the user which one.
case $regions in
@ -707,7 +695,7 @@ while
esac
# Determine tz from country and region.
tz=`
tz=$(
$AWK '
BEGIN {
country = substr(ARGV[1], 2)
@ -735,7 +723,7 @@ while
}
}
' ="$country" ="$region" ="$TZ_COUNTRY_TABLE" ="$zone_table"
`
)
esac
# Make sure the corresponding zoneinfo file exists.
@ -754,14 +742,11 @@ while
extra_info=
for i in 1 2 3 4 5 6 7 8
do
TZdate=`LANG=C TZ="$TZ_for_date" date`
UTdate=`LANG=C TZ=UTC0 date`
if $AWK '
function getsecs(d) {
return match(d, /.*:[0-5][0-9]/) ? substr(d, RLENGTH - 1, 2) : ""
}
BEGIN { exit getsecs(ARGV[1]) != getsecs(ARGV[2]) }
' ="$TZdate" ="$UTdate"
TZdate=$(LANG=C TZ="$TZ_for_date" date)
UTdate=$(LANG=C TZ=UTC0 date)
TZsecsetc=${TZdate##*[0-5][0-9]:}
UTsecsetc=${UTdate##*[0-5][0-9]:}
if test "${TZsecsetc%%[!0-9]*}" = "${UTsecsetc%%[!0-9]*}"
then
extra_info="
Selected time is now: $TZdate.
@ -801,7 +786,7 @@ done
case $SHELL in
*csh) file=.login line="setenv TZ '$tz'";;
*) file=.profile line="TZ='$tz'; export TZ"
*) file=.profile line="export TZ='$tz'"
esac
test -t 1 && say >&2 "

View file

@ -1 +1 @@
2024a
2024b

View file

@ -7,8 +7,7 @@
if (type nroff && type perl) >/dev/null 2>&1; then
# Tell groff not to emit SGR escape sequences (ANSI color escapes).
GROFF_NO_SGR=1
export GROFF_NO_SGR
export GROFF_NO_SGR=1
echo ".am TH
.hy 0

View file

@ -152,7 +152,8 @@ tabbed columns line up.)
.nf
.sp
.if \n(.g .ft CR
.in +2
.if t .in +.5i
.if n .in +2
.nr w \w'1896-01-13 'u+\n(.i
.ta \w'1896-01-13\0\0'u +\w'12:01:26\0\0'u +\w'-103126\0\0'u +\w'HWT\0\0'u
TZ="Pacific/Honolulu"

10
zdump.c
View file

@ -89,7 +89,7 @@ static bool warned;
static bool errout;
static char const *abbr(struct tm const *);
ATTRIBUTE_REPRODUCIBLE static intmax_t delta(struct tm *, struct tm *);
static intmax_t delta(struct tm *, struct tm *);
static void dumptime(struct tm const *);
static time_t hunt(timezone_t, time_t, time_t, bool);
static void show(timezone_t, char *, time_t, bool);
@ -97,7 +97,7 @@ static void showextrema(timezone_t, char *, time_t, struct tm *, time_t);
static void showtrans(char const *, struct tm const *, time_t, char const *,
char const *);
static const char *tformat(void);
ATTRIBUTE_REPRODUCIBLE static time_t yeartot(intmax_t);
ATTRIBUTE_PURE_114833 static time_t yeartot(intmax_t);
/* Is C an ASCII digit? */
static bool
@ -134,7 +134,7 @@ 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_REPRODUCIBLE static ptrdiff_t
ATTRIBUTE_PURE_114833 static ptrdiff_t
sumsize(ptrdiff_t a, ptrdiff_t b)
{
#ifdef ckd_add
@ -162,7 +162,7 @@ xstrsize(char const *str)
/* Return a pointer to a newly allocated buffer of size SIZE, exiting
on failure. SIZE should be positive. */
ATTRIBUTE_MALLOC static void *
static void *
xmalloc(ptrdiff_t size)
{
void *p = malloc(size);
@ -932,7 +932,7 @@ showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi)
# include <stdarg.h>
/* A substitute for snprintf that is good enough for zdump. */
ATTRIBUTE_FORMAT((printf, 3, 4)) static int
static int
my_snprintf(char *s, size_t size, char const *format, ...)
{
int n;

42
zic.8
View file

@ -171,7 +171,7 @@ boundaries, particularly if
causes a TZif file to contain explicit entries for
.RI pre- hi
transitions rather than concisely representing them
with an extended POSIX.1-2017 TZ string.
with a proleptic TZ string.
Also see the
.B "\*-b slim"
option for another way to shrink output size.
@ -181,10 +181,10 @@ Generate redundant trailing explicit transitions for timestamps
that occur less than
.I hi
seconds since the Epoch, even though the transitions could be
more concisely represented via the extended POSIX.1-2017 TZ string.
more concisely represented via the proleptic TZ string.
This option does not affect the represented timestamps.
Although it accommodates nonstandard TZif readers
that ignore the extended POSIX.1-2017 TZ string,
that ignore the proleptic TZ string,
it increases the size of the altered output files.
.TP
.BI "\*-t " file
@ -245,10 +245,10 @@ for
.PP
The output file does not contain all the information about the
long-term future of a timezone, because the future cannot be summarized as
an extended POSIX.1-2017 TZ string. For example, as of 2023 this problem
a proleptic TZ string. For example, as of 2023 this problem
occurs for Morocco's daylight-saving rules, as these rules are based
on predictions for when Ramadan will be observed, something that
an extended POSIX.1-2017 TZ string cannot represent.
a proleptic TZ string cannot represent.
.PP
The output contains data that may not be handled properly by client
code designed for older
@ -558,12 +558,14 @@ begin the field with a minus sign if time must be subtracted from UT.
.TP
.B RULES
The name of the rules that apply in the timezone or,
alternatively, a field in the same format as a rule-line SAVE column,
alternatively, a field in the same format as a rule-line
.B SAVE
field,
giving the amount of time to be added to local standard time
and whether the resulting time is standard or daylight saving.
If this field is
Standard time applies if this field is
.B \*-
then standard time always applies.
or for timestamps occurring before any rule takes effect.
When an amount of time is given, only the sum of standard time and
this amount matters.
.TP
@ -571,9 +573,13 @@ this amount matters.
The format for time zone abbreviations.
The pair of characters
.B %s
is used to show where the
.q "variable part"
of the time zone abbreviation goes.
shows where to put the time zone abbreviation's variable part,
which is taken from the
.B LETTER/S
field of the corresponding rule;
any timestamps that precede the earliest rule use the
.B LETTER/S
of the earliest standard-time rule (which in this case must exist).
Alternatively, a format can use the pair of characters
.B %z
to stand for the UT offset in the form
@ -663,7 +669,7 @@ Rule US 1967 1973 - Apr lastSun 2:00 1:00 D
.ta \w'# Zone\0\0'u +\w'America/Menominee\0\0'u +\w'STDOFF\0\0'u +\w'RULES\0\0'u +\w'FORMAT\0\0'u
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Menominee \*-5:00 \*- EST 1973 Apr 29 2:00
\*-6:00 US C%sT
\*-6:00 US C%sT
.sp
.in
.fi
@ -767,16 +773,16 @@ or
if the leap second time given by the other fields should be interpreted as
local (wall clock) time.
.PP
Rolling leap seconds were implemented back when it was not
clear whether common practice was rolling or stationary,
with concerns that one would see
Rolling leap seconds would let one see
Times Square ball drops where there'd be a
.q "3... 2... 1... leap... Happy New Year"
countdown, placing the leap second at
midnight New York time rather than midnight UTC.
However, this countdown style does not seem to have caught on,
which means rolling leap seconds are not used in practice;
also, they are not supported if the
Although stationary leap seconds are the common practice,
rolling leap seconds can be useful in specialized applications
like SMPTE timecodes that may prefer to put leap second
discontinuities at the end of a local broadcast day.
However, rolling leap seconds are not supported if the
.B \*-r
option is used.
.PP

143
zic.8.txt
View file

@ -77,16 +77,16 @@ OPTIONS
due to the need to represent the timestamp range boundaries,
particularly if hi causes a TZif file to contain explicit
entries for pre-hi transitions rather than concisely
representing them with an extended POSIX.1-2017 TZ string. Also
see the -b slim option for another way to shrink output size.
representing them with a proleptic TZ string. Also see the -b
slim option for another way to shrink output size.
-R @hi Generate redundant trailing explicit transitions for timestamps
-R @hi Generate redundant trailing explicit transitions for timestamps
that occur less than hi seconds since the Epoch, even though the
transitions could be more concisely represented via the extended
POSIX.1-2017 TZ string. This option does not affect the
transitions could be more concisely represented via the
proleptic TZ string. This option does not affect the
represented timestamps. Although it accommodates nonstandard
TZif readers that ignore the extended POSIX.1-2017 TZ string, it
increases the size of the altered output files.
TZif readers that ignore the proleptic TZ string, it increases
the size of the altered output files.
-t file
When creating local time information, put the configuration link
@ -97,34 +97,33 @@ OPTIONS
The input specifies a link to a link, something not supported by
some older parsers, including zic itself through release 2022e.
A year that appears in a data file is outside the range of
A year that appears in a data file is outside the range of
representable years.
A time of 24:00 or more appears in the input. Pre-1998 versions
of zic prohibit 24:00, and pre-2007 versions prohibit times
of zic prohibit 24:00, and pre-2007 versions prohibit times
greater than 24:00.
A rule goes past the start or end of the month. Pre-2004
A rule goes past the start or end of the month. Pre-2004
versions of zic prohibit this.
A time zone abbreviation uses a %z format. Pre-2015 versions of
zic do not support this.
A timestamp contains fractional seconds. Pre-2018 versions of
A timestamp contains fractional seconds. Pre-2018 versions of
zic do not support this.
The input contains abbreviations that are mishandled by pre-2018
versions of zic due to a longstanding coding bug. These
abbreviations include "L" for "Link", "mi" for "min", "Sa" for
versions of zic due to a longstanding coding bug. These
abbreviations include "L" for "Link", "mi" for "min", "Sa" for
"Sat", and "Su" for "Sun".
The output file does not contain all the information about the
long-term future of a timezone, because the future cannot be
summarized as an extended POSIX.1-2017 TZ string. For example,
as of 2023 this problem occurs for Morocco's daylight-saving
rules, as these rules are based on predictions for when Ramadan
will be observed, something that an extended POSIX.1-2017 TZ
string cannot represent.
The output file does not contain all the information about the
long-term future of a timezone, because the future cannot be
summarized as a proleptic TZ string. For example, as of 2023
this problem occurs for Morocco's daylight-saving rules, as
these rules are based on predictions for when Ramadan will be
observed, something that a proleptic TZ string cannot represent.
The output contains data that may not be handled properly by
client code designed for older zic output formats. These
@ -309,24 +308,28 @@ FILES
RULES The name of the rules that apply in the timezone or,
alternatively, a field in the same format as a rule-line SAVE
column, giving the amount of time to be added to local standard
field, giving the amount of time to be added to local standard
time and whether the resulting time is standard or daylight
saving. If this field is - then standard time always applies.
When an amount of time is given, only the sum of standard time
and this amount matters.
saving. Standard time applies if this field is - or for
timestamps occurring before any rule takes effect. When an
amount of time is given, only the sum of standard time and this
amount matters.
FORMAT The format for time zone abbreviations. The pair of characters
%s is used to show where the "variable part" of the time zone
abbreviation goes. Alternatively, a format can use the pair of
characters %z to stand for the UT offset in the form +-hh,
+-hhmm, or +-hhmmss, using the shortest form that does not lose
information, where hh, mm, and ss are the hours, minutes, and
seconds east (+) or west (-) of UT. Alternatively, a slash (/)
separates standard and daylight abbreviations. To conform to
POSIX, a time zone abbreviation should contain only alphanumeric
ASCII characters, "+" and "-". By convention, the time zone
abbreviation "-00" is a placeholder that means local time is
unspecified.
FORMAT The format for time zone abbreviations. The pair of characters
%s shows where to put the time zone abbreviation's variable
part, which is taken from the LETTER/S field of the
corresponding rule; any timestamps that precede the earliest
rule use the LETTER/S of the earliest standard-time rule (which
in this case must exist). Alternatively, a format can use the
pair of characters %z to stand for the UT offset in the form
+-hh, +-hhmm, or +-hhmmss, using the shortest form that does not
lose information, where hh, mm, and ss are the hours, minutes,
and seconds east (+) or west (-) of UT. Alternatively, a slash
(/) separates standard and daylight abbreviations. To conform
to POSIX, a time zone abbreviation should contain only
alphanumeric ASCII characters, "+" and "-". By convention, the
time zone abbreviation "-00" is a placeholder that means local
time is unspecified.
UNTIL The time at which the UT offset or the rule(s) change for a
location. It takes the form of one to four fields YEAR [MONTH
@ -369,7 +372,7 @@ FILES
Rule US 1967 1973 - Apr lastSun 2:00 1:00 D
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Menominee -5:00 - EST 1973 Apr 29 2:00
-6:00 US C%sT
-6:00 US C%sT
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
@ -421,14 +424,14 @@ FILES
second time given by the other fields should be interpreted as local
(wall clock) time.
Rolling leap seconds were implemented back when it was not clear
whether common practice was rolling or stationary, with concerns that
one would see Times Square ball drops where there'd be a "3... 2...
1... leap... Happy New Year" countdown, placing the leap second at
midnight New York time rather than midnight UTC. However, this
countdown style does not seem to have caught on, which means rolling
leap seconds are not used in practice; also, they are not supported if
the -r option is used.
Rolling leap seconds would let one see Times Square ball drops where
there'd be a "3... 2... 1... leap... Happy New Year" countdown, placing
the leap second at midnight New York time rather than midnight UTC.
Although stationary leap seconds are the common practice, rolling leap
seconds can be useful in specialized applications like SMPTE timecodes
that may prefer to put leap second discontinuities at the end of a
local broadcast day. However, rolling leap seconds are not supported
if the -r option is used.
The expiration line, if present, has the form:
@ -442,7 +445,7 @@ FILES
in UTC for the leap second table.
EXTENDED EXAMPLE
Here is an extended example of zic input, intended to illustrate many
Here is an extended example of zic input, intended to illustrate many
of its features.
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
@ -463,29 +466,29 @@ EXTENDED EXAMPLE
Link Europe/Zurich Europe/Vaduz
In this example, the EU rules are for the European Union and for its
predecessor organization, the European Communities. The timezone is
named Europe/Zurich and it has the alias Europe/Vaduz. This example
says that Zurich was 34 minutes and 8 seconds east of UT until
1853-07-16 at 00:00, when the legal offset was changed to 7 degrees 26
minutes 22.50 seconds, which works out to 0:29:45.50; zic treats this
by rounding it to 0:29:46. After 1894-06-01 at 00:00 the UT offset
became one hour and Swiss daylight saving rules (defined with lines
beginning with "Rule Swiss") apply. From 1981 to the present, EU
daylight saving rules have applied, and the UTC offset has remained at
In this example, the EU rules are for the European Union and for its
predecessor organization, the European Communities. The timezone is
named Europe/Zurich and it has the alias Europe/Vaduz. This example
says that Zurich was 34 minutes and 8 seconds east of UT until
1853-07-16 at 00:00, when the legal offset was changed to 7 degrees 26
minutes 22.50 seconds, which works out to 0:29:45.50; zic treats this
by rounding it to 0:29:46. After 1894-06-01 at 00:00 the UT offset
became one hour and Swiss daylight saving rules (defined with lines
beginning with "Rule Swiss") apply. From 1981 to the present, EU
daylight saving rules have applied, and the UTC offset has remained at
one hour.
In 1941 and 1942, daylight saving time applied from the first Monday in
May at 01:00 to the first Monday in October at 02:00. The pre-1981 EU
daylight-saving rules have no effect here, but are included for
May at 01:00 to the first Monday in October at 02:00. The pre-1981 EU
daylight-saving rules have no effect here, but are included for
completeness. Since 1981, daylight saving has begun on the last Sunday
in March at 01:00 UTC. Until 1995 it ended the last Sunday in
September at 01:00 UTC, but this changed to the last Sunday in October
in March at 01:00 UTC. Until 1995 it ended the last Sunday in
September at 01:00 UTC, but this changed to the last Sunday in October
starting in 1996.
For purposes of display, "LMT" and "BMT" were initially used,
respectively. Since Swiss rules and later EU rules were applied, the
time zone abbreviation has been CET for standard time and CEST for
For purposes of display, "LMT" and "BMT" were initially used,
respectively. Since Swiss rules and later EU rules were applied, the
time zone abbreviation has been CET for standard time and CEST for
daylight saving time.
FILES
@ -496,15 +499,15 @@ FILES
Default timezone information directory.
NOTES
For areas with more than two types of local time, you may need to use
local standard time in the AT field of the earliest transition time's
rule to ensure that the earliest transition time recorded in the
For areas with more than two types of local time, you may need to use
local standard time in the AT field of the earliest transition time's
rule to ensure that the earliest transition time recorded in the
compiled file is correct.
If, for a particular timezone, a clock advance caused by the start of
daylight saving coincides with and is equal to a clock retreat caused
by a change in UT offset, zic produces a single transition to daylight
saving at the new UT offset without any change in local (wall clock)
If, for a particular timezone, a clock advance caused by the start of
daylight saving coincides with and is equal to a clock retreat caused
by a change in UT offset, zic produces a single transition to daylight
saving at the new UT offset without any change in local (wall clock)
time. To get separate transitions use multiple zone continuation lines
specifying transition instants using universal time.

31
zic.c
View file

@ -470,7 +470,7 @@ size_overflow(void)
memory_exhausted(_("size overflow"));
}
ATTRIBUTE_REPRODUCIBLE static ptrdiff_t
ATTRIBUTE_PURE_114833 static ptrdiff_t
size_sum(size_t a, size_t b)
{
#ifdef ckd_add
@ -484,7 +484,7 @@ size_sum(size_t a, size_t b)
size_overflow();
}
ATTRIBUTE_REPRODUCIBLE static ptrdiff_t
ATTRIBUTE_PURE_114833 static ptrdiff_t
size_product(ptrdiff_t nitems, ptrdiff_t itemsize)
{
#ifdef ckd_mul
@ -499,7 +499,7 @@ size_product(ptrdiff_t nitems, ptrdiff_t itemsize)
size_overflow();
}
ATTRIBUTE_REPRODUCIBLE static ptrdiff_t
ATTRIBUTE_PURE_114833 static ptrdiff_t
align_to(ptrdiff_t size, ptrdiff_t alignment)
{
ptrdiff_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits);
@ -523,7 +523,7 @@ memcheck(void *ptr)
return ptr;
}
ATTRIBUTE_MALLOC static void *
static void *
emalloc(size_t size)
{
return memcheck(malloc(size));
@ -535,7 +535,7 @@ erealloc(void *ptr, size_t size)
return memcheck(realloc(ptr, size));
}
ATTRIBUTE_MALLOC static char *
static char *
estrdup(char const *str)
{
return memcheck(strdup(str));
@ -1435,7 +1435,7 @@ 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. */
static bool
ATTRIBUTE_PURE_114833 static bool
same_parent_dirs(char const *a, char const *b)
{
for (; *a == *b; a++, b++)
@ -2982,10 +2982,10 @@ rule_cmp(struct rule const *a, struct rule const *b)
return a->r_dayofmonth - b->r_dayofmonth;
}
/* Store into RESULT a POSIX.1-2017 TZ string that represent the future
/* Store into RESULT a proleptic TZ string that represent the future
predictions for the zone ZPFIRST with ZONECOUNT entries. Return a
compatibility indicator (a TZDB release year) if successful, a
negative integer if no such TZ string exissts. */
negative integer if no such TZ string exists. */
static int
stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
{
@ -3177,8 +3177,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
if (noise) {
if (!*envvar)
warning("%s %s",
_("no POSIX.1-2017 environment variable"
" for zone"),
_("no proleptic TZ string for zone"),
zpfirst->z_name);
else if (compat != 0) {
/* Circa-COMPAT clients, and earlier clients, might
@ -3442,7 +3441,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
if (do_extend) {
/*
** If we're extending the explicitly listed observations for
** 400 years because we can't fill the POSIX.1-2017 TZ field,
** 400 years because we can't fill the proleptic TZ field,
** check whether we actually ended up explicitly listing
** observations through that period. If there aren't any
** near the end of the 400-year period, add a redundant
@ -3627,7 +3626,7 @@ lowerit(char a)
}
/* case-insensitive equality */
ATTRIBUTE_REPRODUCIBLE static bool
ATTRIBUTE_PURE_114833 static bool
ciequal(register const char *ap, register const char *bp)
{
while (lowerit(*ap) == lowerit(*bp++))
@ -3636,7 +3635,7 @@ ciequal(register const char *ap, register const char *bp)
return false;
}
ATTRIBUTE_REPRODUCIBLE static bool
ATTRIBUTE_PURE_114833 static bool
itsabbr(register const char *abbr, register const char *word)
{
if (lowerit(*abbr) != lowerit(*word))
@ -3652,7 +3651,7 @@ itsabbr(register const char *abbr, register const char *word)
/* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
ATTRIBUTE_REPRODUCIBLE static bool
ATTRIBUTE_PURE_114833 static bool
ciprefix(char const *abbr, char const *word)
{
do
@ -3762,7 +3761,7 @@ time_overflow(void)
exit(EXIT_FAILURE);
}
ATTRIBUTE_REPRODUCIBLE static zic_t
ATTRIBUTE_PURE_114833 static zic_t
oadd(zic_t t1, zic_t t2)
{
#ifdef ckd_add
@ -3776,7 +3775,7 @@ oadd(zic_t t1, zic_t t2)
time_overflow();
}
ATTRIBUTE_REPRODUCIBLE static zic_t
ATTRIBUTE_PURE_114833 static zic_t
tadd(zic_t t1, zic_t t2)
{
#ifdef ckd_add