1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-10-18 02:19:39 +00:00

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

412
Makefile
View File

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

124
NEWS
View File

@ -1,5 +1,125 @@
News for the tz database 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 Release 2024a - 2024-02-01 09:28:56 -0800
Briefly: Briefly:
@ -161,7 +281,7 @@ Release 2023d - 2023-12-21 20:02:24 -0800
* It uses the special .POSIX target. * It uses the special .POSIX target.
* It quotes special characters more carefully. * It quotes special characters more carefully.
* It no longer mishandles builds in an ISO 8859 locale. * 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 built by 'make', not in a $(CC) -D option. Also, TZDEFAULT is
now treated like TZDIR as they have similar roles. 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 To improve tzselect diagnostics, zone1970.tab's comments column is
now limited to countries that have multiple timezones. 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 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 ** 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. ** leading zeroes to get the newline in the traditional place.
** The -4 ensures that we get four characters of output even if ** The -4 ensures that we get four characters of output even if
** we call a strftime variant that produces fewer characters for some years. ** we call a strftime variant that produces fewer characters for some years.
** The ISO C and POSIX standards prohibit padding the year, ** This conforms to recent ISO C and POSIX standards, which say behavior
** but many implementations pad anyway; most likely the standards are buggy. ** 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"; 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]; static char buf_ctime[sizeof buf_asctime];
#endif #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 * char *
asctime_r(struct tm const *restrict timeptr, char *restrict buf) 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); return asctime_r(timeptr, buf_asctime);
} }
asctime_static
char * char *
ctime_r(const time_t *timep, char *buf) 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. */ for ttunspecified to work without crashing. */
enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 }; 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. */ This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */
#ifndef TZNAME_MAXIMUM #ifndef TZNAME_MAXIMUM
# define TZNAME_MAXIMUM 255 # define TZNAME_MAXIMUM 255
@ -130,11 +130,6 @@ struct state {
char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"), char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"),
2 * (TZNAME_MAXIMUM + 1))]; 2 * (TZNAME_MAXIMUM + 1))];
struct lsinfo lsis[TZ_MAX_LEAPS]; 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 { enum r_type {
@ -187,8 +182,9 @@ static int lcl_is_set;
** objects: a broken-down time structure and an array of char. ** objects: a broken-down time structure and an array of char.
** Thanks to Paul Eggert for noting this. ** Thanks to Paul Eggert for noting this.
** **
** This requirement was removed in C99, so support it only if requested, ** Although this requirement was removed in C99 it is still present in POSIX.
** as support is more likely to lead to bugs in badly written programs. ** Follow the requirement if SUPPORT_C89, even though this is more likely to
** trigger latent bugs in programs.
*/ */
#if SUPPORT_C89 #if SUPPORT_C89
@ -710,58 +706,6 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
if (sp->typecnt == 0) if (sp->typecnt == 0)
return EINVAL; 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; return 0;
} }
@ -807,7 +751,7 @@ is_digit(char c)
** Return a pointer to that character. ** Return a pointer to that character.
*/ */
ATTRIBUTE_REPRODUCIBLE static const char * ATTRIBUTE_PURE_114833 static const char *
getzname(register const char *strp) getzname(register const char *strp)
{ {
register char c; 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. ** 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) getqzname(register const char *strp, const int delim)
{ {
register int c; 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. ** appropriate.
*/ */
@ -1183,11 +1127,13 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
do { do {
int_fast32_t yearsecs int_fast32_t yearsecs
= year_lengths[isleap(yearbeg - 1)] * SECSPERDAY; = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
time_t janfirst1 = janfirst;
yearbeg--; yearbeg--;
if (increment_overflow_time(&janfirst, -yearsecs)) { if (increment_overflow_time(&janfirst1, -yearsecs)) {
janoffset = -yearsecs; janoffset = -yearsecs;
break; break;
} }
janfirst = janfirst1;
} while (atlo < janfirst } while (atlo < janfirst
&& EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg); && 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 ** Transitions from DST to DDST
** will effectively disappear since ** will effectively disappear since
** POSIX.1-2017 provides for only one ** proleptic TZ strings have only one
** DST offset. ** DST offset.
*/ */
if (isdst && !sp->ttis[j].tt_ttisstd) { 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; sp->timecnt = 0;
init_ttinfo(&sp->ttis[0], -stdoffset, false, 0); init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
} }
sp->defaulttype = 0;
sp->charcnt = charcnt; sp->charcnt = charcnt;
cp = sp->chars; cp = sp->chars;
memcpy(cp, stdname, stdlen); memcpy(cp, stdname, stdlen);
@ -1378,7 +1323,6 @@ zoneinit(struct state *sp, char const *name)
sp->goback = sp->goahead = false; sp->goback = sp->goahead = false;
init_ttinfo(&sp->ttis[0], 0, false, 0); init_ttinfo(&sp->ttis[0], 0, false, 0);
strcpy(sp->chars, utc); strcpy(sp->chars, utc);
sp->defaulttype = 0;
return 0; return 0;
} else { } else {
int err = tzload(name, sp, true); 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 ** NetBSD 6.1.4 has ctime_rz, but omit it because C23 deprecates ctime and
** ctime_r are obsolescent and have potential security problems that ** POSIX.1-2024 removes ctime_r. Both have potential security problems that
** ctime_rz would share. Callers can instead use localtime_rz + strftime. ** 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 ** 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, ** If successful and SETNAME is nonzero,
** set the applicable parts of tzname, timezone and altzone; ** set the applicable parts of tzname, timezone and altzone;
** however, it's OK to omit this step ** however, it's OK to omit this step for proleptic TZ strings
** if the timezone is compatible with POSIX.1-2017
** since in that case tzset should have already done this step correctly. ** since in that case tzset should have already done this step correctly.
** SETNAME's type is int_fast32_t for compatibility with gmtsub, ** 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. ** 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; return result;
} }
if (sp->timecnt == 0 || t < sp->ats[0]) { if (sp->timecnt == 0 || t < sp->ats[0]) {
i = sp->defaulttype; i = 0;
} else { } else {
register int lo = 1; register int lo = 1;
register int hi = sp->timecnt; register int hi = sp->timecnt;
@ -2285,7 +2228,7 @@ mktime(struct tm *tmp)
} }
#if STD_INSPIRED #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. */ Callers can instead use mktime. */
time_t time_t
timelocal(struct tm *tmp) timelocal(struct tm *tmp)
@ -2303,7 +2246,7 @@ timelocal(struct tm *tmp)
# define EXTERN_TIMEOFF static # define EXTERN_TIMEOFF static
#endif #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. */ Callers can instead use mktime_z with a fixed-offset zone. */
EXTERN_TIMEOFF time_t EXTERN_TIMEOFF time_t
timeoff(struct tm *tmp, long offset) timeoff(struct tm *tmp, long offset)

View File

@ -9,16 +9,16 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
.el .ds - \- .el .ds - \-
.B #include <time.h> .B #include <time.h>
.PP .PP
.BR "extern char *tzname[];" " /\(** (optional) \(**/"
.PP
.B [[deprecated]] char *ctime(time_t const *clock); .B [[deprecated]] char *ctime(time_t const *clock);
.PP .PP
/* Only in POSIX.1-2017 and earlier. */
.B char *ctime_r(time_t const *clock, char *buf); .B char *ctime_r(time_t const *clock, char *buf);
.PP .PP
.B double difftime(time_t time1, time_t time0); .B double difftime(time_t time1, time_t time0);
.PP .PP
.B [[deprecated]] char *asctime(struct tm const *tm); .B [[deprecated]] char *asctime(struct tm const *tm);
.PP .PP
/* Only in POSIX.1-2017 and earlier. */
.B "char *asctime_r(struct tm const *restrict tm," .B "char *asctime_r(struct tm const *restrict tm,"
.B " char *restrict result);" .B " char *restrict result);"
.PP .PP
@ -112,17 +112,6 @@ The
function function
corrects for the time zone and any time zone adjustments corrects for the time zone and any time zone adjustments
(such as Daylight Saving Time in the United States). (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 .PP
The The
.B gmtime .B gmtime
@ -191,9 +180,19 @@ are determined.
The The
.B mktime .B mktime
function function
returns the specified calendar time; returns the specified calendar time.
If the calendar time cannot be represented, 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 .PP
The The
.B difftime .B difftime
@ -213,6 +212,13 @@ and
functions functions
are like their unsuffixed counterparts, except that they accept an are like their unsuffixed counterparts, except that they accept an
additional argument specifying where to store the result if successful. 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 .PP
The The
.B localtime_rz .B localtime_rz
@ -275,21 +281,43 @@ from UT, with positive values indicating east
of the Prime Meridian. of the Prime Meridian.
The field's name is derived from Greenwich Mean Time, a precursor of UT. The field's name is derived from Greenwich Mean Time, a precursor of UT.
.PP .PP
In In platforms conforming to POSIX.1-2024 the
.B "struct tm" .B "struct tm"
the the
.B tm_zone .B tm_zone
and and
.B tm_gmtoff .B tm_gmtoff
fields exist, and are filled in, only if arrangements to do fields exist, and are filled in.
so were made when the library containing these functions was For
created. .B localtime_rz
Similarly, the and
.B tzname .B mktime_rz
variable is optional; also, there is no guarantee that the storage lifetime of the strings addressed by
.B tzname .B tm_zone
will extends until the corresponding
continue to exist in this form in future releases of this code. .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 .SH FILES
.ta \w'/usr/share/zoneinfo/posixrules\0\0'u .ta \w'/usr/share/zoneinfo/posixrules\0\0'u
/etc/localtime local timezone file /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, If /usr/share/zoneinfo/GMT is absent,
UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present. UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present.
.SH SEE ALSO .SH SEE ALSO
getenv(3), .BR getenv (3),
newstrftime(3), .BR newstrftime (3),
newtzset(3), .BR newtzset (3),
time(2), .BR time (2),
tzfile(5) .BR tzfile (5).
.SH NOTES .SH NOTES
The return values of The return values of
.BR asctime , .BR asctime ,
@ -317,20 +345,6 @@ and
.B localtime .B localtime
point to static data point to static data
overwritten by each call. 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. The remaining functions and data are thread-safe.
.PP .PP
The The

View File

@ -7,16 +7,16 @@ NAME
SYNOPSIS SYNOPSIS
#include <time.h> #include <time.h>
extern char *tzname[]; /* (optional) */
[[deprecated]] char *ctime(time_t const *clock); [[deprecated]] char *ctime(time_t const *clock);
/* Only in POSIX.1-2017 and earlier. */
char *ctime_r(time_t const *clock, char *buf); char *ctime_r(time_t const *clock, char *buf);
double difftime(time_t time1, time_t time0); double difftime(time_t time1, time_t time0);
[[deprecated]] char *asctime(struct tm const *tm); [[deprecated]] char *asctime(struct tm const *tm);
/* Only in POSIX.1-2017 and earlier. */
char *asctime_r(struct tm const *restrict tm, char *asctime_r(struct tm const *restrict tm,
char *restrict result); char *restrict result);
@ -68,9 +68,7 @@ DESCRIPTION
The localtime and gmtime functions return pointers to "tm" structures, The localtime and gmtime functions return pointers to "tm" structures,
described below. The localtime function corrects for the time zone and described below. The localtime function corrects for the time zone and
any time zone adjustments (such as Daylight Saving Time in the United any time zone adjustments (such as Daylight Saving Time in the United
States). After filling in the "tm" structure, localtime sets the States).
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.
The gmtime function converts to Coordinated Universal Time. The gmtime function converts to Coordinated Universal Time.
@ -96,15 +94,22 @@ DESCRIPTION
set to represent the specified calendar time, but with their values 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 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 until tm_mon and tm_year are determined. The mktime function returns
the specified calendar time; If the calendar time cannot be the specified calendar time. If the calendar time cannot be
represented, it returns -1. 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 The difftime function returns the difference between two calendar
times, (time1 - time0), expressed in seconds. times, (time1 - time0), expressed in seconds.
The ctime_r, localtime_r, gmtime_r, and asctime_r functions are like The ctime_r, localtime_r, gmtime_r, and asctime_r functions are like
their unsuffixed counterparts, except that they accept an additional 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 The localtime_rz and mktime_z functions are like their unsuffixed
counterparts, except that they accept an extra initial zone argument 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 The field's name is derived from Greenwich Mean Time, a precursor of
UT. UT.
In struct tm the tm_zone and tm_gmtoff fields exist, and are filled in, In platforms conforming to POSIX.1-2024 the struct tm the tm_zone and
only if arrangements to do so were made when the library containing tm_gmtoff fields exist, and are filled in. For localtime_rz and
these functions was created. Similarly, the tzname variable is mktime_rz the storage lifetime of the strings addressed by tm_zone
optional; also, there is no guarantee that tzname will continue to extends until the corresponding timezone_t object is freed via tzfree.
exist in this form in future releases of this code. 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 FILES
/etc/localtime local timezone file /etc/localtime local timezone file
@ -152,16 +163,12 @@ FILES
/usr/share/zoneinfo/GMT0 if present. /usr/share/zoneinfo/GMT0 if present.
SEE ALSO SEE ALSO
getenv(3), newstrftime(3), newtzset(3), time(2), tzfile(5) getenv(3), newstrftime(3), newtzset(3), time(2), tzfile(5).
NOTES NOTES
The return values of asctime, ctime, gmtime, and localtime point to The return values of asctime, ctime, gmtime, and localtime point to
static data overwritten by each call. The tzname variable (once set) static data overwritten by each call. The remaining functions and data
and the tm_zone field of a returned struct tm both point to an array of are thread-safe.
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.
The asctime, asctime_r, ctime, and ctime_r functions behave strangely 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 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 If a bracketed member name is followed by
.q + , .q + ,
.B strftime .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 if the name is followed by
.q \*- , .q \*- ,
.B strftime .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. which means portable code should set it.
For portability, For portability,
.BI * timeptr .BI * timeptr
@ -137,8 +137,8 @@ is replaced by the locale's appropriate date and time representation.
.IR tm_hour , .IR tm_hour ,
.IR tm_min , .IR tm_min ,
.IR tm_sec , .IR tm_sec ,
.IR tm_gmtoff +, .IR tm_gmtoff ,
.IR tm_zone +, .IR tm_zone ,
.IR tm_isdst \*-]. .IR tm_isdst \*-].
.TP .TP
%D %D
@ -326,8 +326,8 @@ is replaced by the locale's appropriate time representation.
.IR tm_hour , .IR tm_hour ,
.IR tm_min , .IR tm_min ,
.IR tm_sec , .IR tm_sec ,
.IR tm_gmtoff +, .IR tm_gmtoff ,
.IR tm_zone +, .IR tm_zone ,
.IR tm_isdst \*-]. .IR tm_isdst \*-].
.TP .TP
%x %x
@ -355,7 +355,7 @@ is replaced by the year without century as a decimal number [00,99].
%Z %Z
is replaced by the time zone abbreviation, is replaced by the time zone abbreviation,
or by the empty string if this is not determinable. or by the empty string if this is not determinable.
.RI [ tm_zone +, .RI [ tm_zone ,
.IR tm_isdst \*-] .IR tm_isdst \*-]
.TP .TP
%z %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 locations while uninhabited, and corresponds to a zero offset when the
time zone abbreviation begins with time zone abbreviation begins with
.q "\*-" . .q "\*-" .
.RI [ tm_gmtoff +, .RI [ tm_gmtoff ,
.IR tm_zone +, .IR tm_zone +,
.IR tm_isdst \*-] .IR tm_isdst \*-]
.TP .TP
@ -398,7 +398,7 @@ also behaves as if
were called. were called.
This is for compatibility with older platforms, as required by POSIX; This is for compatibility with older platforms, as required by POSIX;
it is not needed for it is not needed for
.BR tzset 's .BR strftime 's
own use. own use.
.SH "RETURN VALUE" .SH "RETURN VALUE"
If the conversion is successful, If the conversion is successful,
@ -428,11 +428,11 @@ conversion and the number of seconds since the Epoch cannot be represented
in a in a
.c time_t . .c time_t .
.SH SEE ALSO .SH SEE ALSO
date(1), .BR date (1),
getenv(3), .BR getenv (3),
newctime(3), .BR newctime (3),
newtzset(3), .BR newtzset (3),
time(2), .BR time (2),
tzfile(5) .BR tzfile (5).
.SH BUGS .SH BUGS
There is no conversion specification for the phase of the moon. 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 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 values of zero or more members of *timeptr as specified by brackets in
the description. If a bracketed member name is followed by "+", 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 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 it. For portability, *timeptr should be initialized as if by a
successful call to gmtime, localtime, mktime, timegm, or similar successful call to gmtime, localtime, mktime, timegm, or similar
functions. functions.
@ -48,7 +48,7 @@ DESCRIPTION
%c is replaced by the locale's appropriate date and time %c is replaced by the locale's appropriate date and time
representation. [tm_year, tm_yday, tm_mon, tm_mday, tm_wday, 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] %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. %X is replaced by the locale's appropriate time representation.
[tm_year-, tm_yday-, tm_mon-, tm_mday-, tm_wday-, tm_hour, [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. %x is replaced by the locale's appropriate date representation.
[tm_year, tm_yday, tm_mon, tm_mday, tm_wday, tm_hour-, tm_min-, [tm_year, tm_yday, tm_mon, tm_mday, tm_wday, tm_hour-, tm_min-,
@ -152,7 +152,7 @@ DESCRIPTION
[00,99]. [tm_year] [00,99]. [tm_year]
%Z is replaced by the time zone abbreviation, or by the empty %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 %z is replaced by the offset from the Prime Meridian in the format
+HHMM or -HHMM (ISO 8601) as appropriate, with positive values +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 -0000 is used when the time is Universal Time but local time is
indeterminate; by convention this is used for locations while indeterminate; by convention this is used for locations while
uninhabited, and corresponds to a zero offset when the time zone 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 %. %% is replaced by a single %.
@ -171,7 +171,7 @@ DESCRIPTION
As a side effect, strftime also behaves as if tzset were called. This 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 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 RETURN VALUE
If the conversion is successful, strftime returns the number of bytes 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. since the Epoch cannot be represented in a time_t.
SEE ALSO 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 BUGS
There is no conversion specification for the phase of the moon. There is no conversion specification for the phase of the moon.

View File

@ -15,6 +15,14 @@ tzset \- initialize time conversion information
.PP .PP
.B void tzset(void); .B void tzset(void);
.PP .PP
/\(** Optional and obsolescent: \(**/
.br
.B extern char *tzname[];
.br
.B extern long timezone;
.br
.B extern int daylight;
.PP
.B cc ... \*-ltz .B cc ... \*-ltz
.fi .fi
.SH DESCRIPTION .SH DESCRIPTION
@ -165,7 +173,7 @@ describes when the change back happens. Each
.I time .I time
field describes when, in current local time, the change to the other field describes when, in current local time, the change to the other
time is made. 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 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, 24:00 plus the difference between daylight saving and standard time,
leaving no room for standard time in the calendar. leaving no room for standard time in the calendar.
@ -212,11 +220,7 @@ The
.I time .I time
has the same format as has the same format as
.I offset .I offset
except that POSIX.1-2017 does not allow a leading sign (\c except that the hours part of
.q "\*-"
or
.q "+" ).
As an extension to POSIX.1-2017, the hours part of
.I time .I time
can range from \-167 through 167; this allows for unusual rules such can range from \-167 through 167; this allows for unusual rules such
as as
@ -229,8 +233,7 @@ is not given, is
.LP .LP
Here are some examples of Here are some examples of
.I TZ .I TZ
values that directly specify the timezone; they use some of the values that directly specify the timezone.
extensions to POSIX.1-2017.
.TP .TP
.B EST5 .B EST5
stands for US Eastern Standard stands for US Eastern Standard
@ -346,6 +349,22 @@ if the implied call to
fails, fails,
.B tzset .B tzset
falls back on UT. 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" .SH "RETURN VALUE"
If successful, the If successful, the
.B tzalloc .B tzalloc
@ -384,8 +403,29 @@ and
If /usr/share/zoneinfo/GMT is absent, If /usr/share/zoneinfo/GMT is absent,
UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present. UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present.
.SH SEE ALSO .SH SEE ALSO
getenv(3), .BR getenv (3),
newctime(3), .BR newctime (3),
newstrftime(3), .BR newstrftime (3),
time(2), .BR time (2),
tzfile(5) .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); void tzset(void);
/* Optional and obsolescent: */
extern char *tzname[];
extern long timezone;
extern int daylight;
cc ... -ltz cc ... -ltz
DESCRIPTION DESCRIPTION
@ -88,12 +93,11 @@ DESCRIPTION
standard to daylight saving time occurs and the second standard to daylight saving time occurs and the second
date describes when the change back happens. Each time date describes when the change back happens. Each time
field describes when, in current local time, the change field describes when, in current local time, the change
to the other time is made. As an extension to to the other time is made. Daylight saving is assumed to
POSIX.1-2017, daylight saving is assumed to be in effect be in effect all year if it begins January 1 at 00:00 and
all year if it begins January 1 at 00:00 and ends ends December 31 at 24:00 plus the difference between
December 31 at 24:00 plus the difference between daylight daylight saving and standard time, leaving no room for
saving and standard time, leaving no room for standard standard time in the calendar.
time in the calendar.
The format of date is one of the following: 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. is the first week in which the d'th day occurs.
Day zero is Sunday. Day zero is Sunday.
The time has the same format as offset except that The time has the same format as offset except that the
POSIX.1-2017 does not allow a leading sign ("-" or "+"). hours part of time can range from -167 through 167; this
As an extension to POSIX.1-2017, the hours part of time allows for unusual rules such as "the Saturday before the
can range from -167 through 167; this allows for unusual first Sunday of March". The default, if time is not
rules such as "the Saturday before the first Sunday of given, is 02:00:00.
March". The default, if time is not given, is 02:00:00.
Here are some examples of TZ values that directly specify the timezone; Here are some examples of TZ values that directly specify the timezone.
they use some of the extensions to POSIX.1-2017.
EST5 stands for US Eastern Standard Time (EST), 5 hours behind UT, EST5 stands for US Eastern Standard Time (EST), 5 hours behind UT,
without daylight saving. without daylight saving.
@ -183,6 +185,14 @@ DESCRIPTION
getenv fails, tzset acts like tzalloc(nullptr); if the implied call to getenv fails, tzset acts like tzalloc(nullptr); if the implied call to
tzalloc fails, tzset falls back on UT. 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 RETURN VALUE
If successful, the tzalloc function returns a nonnull pointer to the If successful, the tzalloc function returns a nonnull pointer to the
newly allocated object. Otherwise, it returns a null pointer and sets newly allocated object. Otherwise, it returns a null pointer and sets
@ -208,6 +218,16 @@ FILES
/usr/share/zoneinfo/GMT0 if present. /usr/share/zoneinfo/GMT0 if present.
SEE ALSO 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) 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 /* PORT_TO_C89 means the code should work even if the underlying
compiler and library support only C89 plus C99's 'long long' compiler and library support only C89 plus C99's 'long long'
and perhaps a few other extensions to C89. SUPPORT_C89 means the and perhaps a few other extensions to C89.
tzcode library should support C89 callers in addition to the usual
support for C99-and-later callers; however, C89 support can trigger This macro is obsolescent, and the plan is to remove it along with
latent bugs in C99-and-later callers. These macros are obsolescent, associated code. A good time to do that might be in the year 2029
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
because RHEL 7 (whose GCC defaults to C89) extended life cycle because RHEL 7 (whose GCC defaults to C89) extended life cycle
support (ELS) is scheduled to end on 2028-06-30. */ support (ELS) is scheduled to end on 2028-06-30. */
#ifndef PORT_TO_C89 #ifndef PORT_TO_C89
# define PORT_TO_C89 0 # define PORT_TO_C89 0
#endif #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 #ifndef SUPPORT_C89
# define SUPPORT_C89 0 # define SUPPORT_C89 1
#endif #endif
#ifndef __STDC_VERSION__ #ifndef __STDC_VERSION__
@ -69,10 +72,6 @@
** You can override these in your C compiler options, e.g. '-DHAVE_GETTEXT=1'. ** 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 !defined HAVE__GENERIC && defined __has_extension
# if !__has_extension(c_generic_selections) # if !__has_extension(c_generic_selections)
# define HAVE__GENERIC 0 # define HAVE__GENERIC 0
@ -236,6 +235,31 @@
# include <unistd.h> /* for R_OK, and other POSIX goodness */ # include <unistd.h> /* for R_OK, and other POSIX goodness */
#endif /* HAVE_UNISTD_H */ #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 #ifndef HAVE_STRFTIME_L
# if _POSIX_VERSION < 200809 # if _POSIX_VERSION < 200809
# define HAVE_STRFTIME_L 0 # 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) # define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r)
#endif #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 \ #if (defined __has_c_attribute \
&& (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__)) && (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__))
# define HAVE___HAS_C_ATTRIBUTE true # define HAVE___HAS_C_ATTRIBUTE true
@ -535,24 +551,27 @@ typedef unsigned long uintmax_t;
# endif # endif
#endif #endif
#ifndef ATTRIBUTE_REPRODUCIBLE #ifndef ATTRIBUTE_REPRODUCIBLE
# if 3 <= __GNUC__ # define ATTRIBUTE_REPRODUCIBLE /* empty */
# define ATTRIBUTE_REPRODUCIBLE __attribute__((pure))
# else
# define ATTRIBUTE_REPRODUCIBLE /* empty */
# endif
#endif #endif
#if HAVE___HAS_C_ATTRIBUTE /* GCC attributes that are useful in tzcode.
# if __has_c_attribute(unsequenced) __attribute__((pure)) is stricter than [[reproducible]],
# define ATTRIBUTE_UNSEQUENCED [[unsequenced]] so the latter is an adequate substitute in non-GCC C23 platforms. */
# endif #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 #endif
#ifndef ATTRIBUTE_UNSEQUENCED
# if 3 <= __GNUC__ /* Avoid GCC bug 114833 <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114833>.
# define ATTRIBUTE_UNSEQUENCED __attribute__((const)) Remove this macro and its uses when the bug is fixed in a GCC release,
# else because only the latest GCC matters for $(GCC_DEBUG_FLAGS). */
# define ATTRIBUTE_UNSEQUENCED /* empty */ #ifdef GCC_LINT
# endif # define ATTRIBUTE_PURE_114833 ATTRIBUTE_PURE
#else
# define ATTRIBUTE_PURE_114833 /* empty */
#endif #endif
#if (__STDC_VERSION__ < 199901 && !defined restrict \ #if (__STDC_VERSION__ < 199901 && !defined restrict \
@ -604,12 +623,8 @@ typedef time_tz tz_time_t;
# undef asctime # undef asctime
# define asctime tz_asctime # define asctime tz_asctime
# undef asctime_r
# define asctime_r tz_asctime_r
# undef ctime # undef ctime
# define ctime tz_ctime # define ctime tz_ctime
# undef ctime_r
# define ctime_r tz_ctime_r
# undef difftime # undef difftime
# define difftime tz_difftime # define difftime tz_difftime
# undef gmtime # undef gmtime
@ -654,6 +669,12 @@ typedef time_tz tz_time_t;
# define tzfree tz_tzfree # define tzfree tz_tzfree
# undef tzset # undef tzset
# define tzset tz_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 # if HAVE_STRFTIME_L
# undef strftime_l # undef strftime_l
# define strftime_l tz_strftime_l # define strftime_l tz_strftime_l
@ -679,10 +700,12 @@ typedef time_tz tz_time_t;
# define DEPRECATED_IN_C23 ATTRIBUTE_DEPRECATED # define DEPRECATED_IN_C23 ATTRIBUTE_DEPRECATED
# endif # endif
DEPRECATED_IN_C23 char *asctime(struct tm const *); 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 *); 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 *); 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, size_t strftime(char *restrict, size_t, char const *restrict,
struct tm const *restrict); struct tm const *restrict);
# if HAVE_STRFTIME_L # if HAVE_STRFTIME_L
@ -713,7 +736,7 @@ void tzset(void);
time_t timegm(struct tm *); time_t timegm(struct tm *);
#endif #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); extern char *asctime_r(struct tm const *restrict, char *restrict);
#endif #endif
@ -798,10 +821,10 @@ timezone_t tzalloc(char const *);
void tzfree(timezone_t); void tzfree(timezone_t);
# if STD_INSPIRED # if STD_INSPIRED
# if TZ_TIME_T || !defined posix2time_z # 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 # endif
# if TZ_TIME_T || !defined time2posix_z # 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 # endif
#endif #endif
@ -973,8 +996,9 @@ enum {
/* How many years to generate (in zic.c) or search through (in localtime.c). /* 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. 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 E.g., suppose a rule applies from 2012 on with transitions
in March and September, plus one-off transitions in November 2013. 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, 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. 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, 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 href="https://en.wikipedia.org/wiki/POSIX">POSIX</a>, an international
standard for <a standard for <a
href="https://en.wikipedia.org/wiki/Unix">UNIX</a>-like systems. 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 href="https://pubs.opengroup.org/onlinepubs/9699919799/"> The Open
Group Base Specifications Issue 7</a>, IEEE Std 1003.1-2017, 2018 Group Base Specifications Issue 7</a>, IEEE Std 1003.1-2017, 2018
Edition. Edition), POSIX.1-2024 requires support for the
Because the database's scope encompasses real-world changes to civil <code><abbr>tz</abbr></code> database, which has a
timekeeping, its model for describing time is more complex than the model for describing civil time that is more complex than the
standard and daylight saving times supported by POSIX.1-2017. standard and daylight saving times required by POSIX.1-2017.
A <code><abbr>tz</abbr></code> timezone corresponds to a ruleset that can 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 have more than two changes per year, these changes need not merely
flip back and forth between two alternatives, and the rules themselves flip back and forth between two alternatives, and the rules themselves
@ -159,7 +161,7 @@ among the following goals:
</ul> </ul>
<p> <p>
Names normally have the form Names normally have the format
<var>AREA</var><code>/</code><var>LOCATION</var>, where <var>AREA</var><code>/</code><var>LOCATION</var>, where
<var>AREA</var> is a continent or ocean, and <var>AREA</var> is a continent or ocean, and
<var>LOCATION</var> is a specific location within the area. <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, href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> letters,
'<code>.</code>', '<code>-</code>' and '<code>_</code>'. '<code>.</code>', '<code>-</code>' and '<code>_</code>'.
Do not use digits, as that might create an ambiguity with <a 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>. <code>TZ</code> strings</a>.
A file name component must not exceed 14 characters or start with A file name component must not exceed 14 characters or start with
'<code>-</code>'. '<code>-</code>'.
@ -378,7 +380,8 @@ nowadays distributions typically use it
and no great weight should be attached to whether a link and no great weight should be attached to whether a link
is defined in <code>backward</code> or in some other file. is defined in <code>backward</code> or in some other file.
The source file <code>etcetera</code> defines names that may be useful 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> no other source file other than <code>backward</code>
contains links to its zones. contains links to its zones.
One of <code>etcetera</code>'s names is <code>Etc/UTC</code>, One of <code>etcetera</code>'s names is <code>Etc/UTC</code>,
@ -425,8 +428,8 @@ in decreasing order of importance:
In other words, in the C locale the POSIX extended regular In other words, in the C locale the POSIX extended regular
expression <code>[-+[:alnum:]]{3,6}</code> should match the expression <code>[-+[:alnum:]]{3,6}</code> should match the
abbreviation. abbreviation.
This guarantees that all abbreviations could have been specified by a This guarantees that all abbreviations could have been specified
POSIX.1-2017 <code>TZ</code> string. explicitly by a POSIX proleptic <code>TZ</code> string.
</p> </p>
</li> </li>
<li> <li>
@ -578,6 +581,11 @@ in decreasing order of importance:
some sense undefined; this notation is derived some sense undefined; this notation is derived
from <a href="https://datatracker.ietf.org/doc/html/rfc3339">Internet from <a href="https://datatracker.ietf.org/doc/html/rfc3339">Internet
<abbr title="Request For Comments">RFC</abbr> 3339</a>. <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> </li>
</ul> </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 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 the scope of the <code><abbr>tz</abbr></code> code and data, which
provide only limited support for date and time localization 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 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 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 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 <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. primary use of this package is to update obsolete time-related files.
To do this, you may need to compile the time zone compiler To do this, you may need to compile the time zone compiler
'<code>zic</code>' supplied with this package instead of using the <code>zic</code> supplied with this package instead of using the
system '<code>zic</code>', since the format of <code>zic</code>'s system <code>zic</code>, since the format of <code>zic</code>'s
input is occasionally extended, and a platform may still be shipping input is occasionally extended, and a platform may still be shipping
an older <code>zic</code>. an older <code>zic</code>.
</p> </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> <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> <li>
<p> <p>
In POSIX.1-2017, time display in a process is controlled by the The proleptic <code>TZ</code> string,
environment variable <code>TZ</code>. which is all that POSIX.1-2017 requires,
Unfortunately, the POSIX.1-2017 has a format that is hard to describe and is error-prone in practice.
<code>TZ</code> string takes a form that is hard to describe and Also, proleptic <code>TZ</code> strings cannot deal with daylight
is error-prone in practice.
Also, POSIX.1-2017 <code>TZ</code> strings cannot deal with daylight
saving time rules not based on the Gregorian calendar (as in saving time rules not based on the Gregorian calendar (as in
Morocco), or with situations where more than two time zone Morocco), or with situations where more than two time zone
abbreviations or <abbr>UT</abbr> offsets are used in an area. abbreviations or <abbr>UT</abbr> offsets are used in an area.
</p> </p>
<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>
<p> <p>
@ -955,7 +996,7 @@ an older <code>zic</code>.
</dl> </dl>
<p> <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. Zealand after 2007.
It says that standard time (<abbr>NZST</abbr>) is 12 hours ahead It says that standard time (<abbr>NZST</abbr>) is 12 hours ahead
of <abbr>UT</abbr>, and that daylight saving time 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> <pre><code>TZ='NZST-12NZDT,M9.5.0,M4.1.0/3'</code></pre>
<p> <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. 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> </p>
<pre><code>TZ='Pacific/Auckland'</code></pre> <pre><code>TZ='Pacific/Auckland'</code></pre>
</li> </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> <li>
POSIX does not define the <abbr>DST</abbr> transitions POSIX.1-2024 requires support for geographical <code>TZ</code>.
for <code>TZ</code> values like Earlier POSIX editions require support only for proleptic <code>TZ</code>.
"<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> </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> <li>
The <code>TZ</code> environment variable is process-global, which The <code>TZ</code> environment variable is process-global, which
makes it hard to write efficient, thread-safe applications that 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 handling daylight saving time shifts &ndash; as might be required to
limit phone calls to off-peak hours. limit phone calls to off-peak hours.
</li> </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> <li>
POSIX requires that <code>time_t</code> clock counts exclude leap POSIX requires that <code>time_t</code> clock counts exclude leap
seconds. seconds.
</li> </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> <li>
The <code><abbr>tz</abbr></code> code attempts to support all the The <code><abbr>tz</abbr></code> code attempts to support all the
<code>time_t</code> implementations allowed by POSIX. <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. and 40-bit integers are also used occasionally.
Although earlier POSIX versions allowed <code>time_t</code> to be a Although earlier POSIX versions allowed <code>time_t</code> to be a
floating-point type, this was not supported by any practical system, 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. require <code>time_t</code> to be an integer type.
</li> </li>
</ul>
<h3 id="POSIX-extensions">Extensions to POSIX.1-2017 in the
<code><abbr>tz</abbr></code> code</h3>
<ul>
<li> <li>
<p> <p>
The <code>TZ</code> environment variable is used in generating If the <code>TZ</code> environment variable uses the geographical format,
the name of a file from which time-related information is read it is used in generating
(or is interpreted à la POSIX.1-2017); <code>TZ</code> is no longer the name of a file from which time-related information is read.
constrained to be a string containing abbreviations
and numeric data as described <a href="#POSIX">above</a>.
The file's format is <dfn><abbr>TZif</abbr></dfn>, The file's format is <dfn><abbr>TZif</abbr></dfn>,
a timezone information format that contains binary data; see a timezone information format that contains binary data; see
<a href="https://datatracker.ietf.org/doc/html/8536">Internet <a href="https://datatracker.ietf.org/doc/html/8536">Internet
@ -1053,10 +1125,11 @@ an older <code>zic</code>.
abbreviations are used. abbreviations are used.
</p> </p>
<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>' variable to take on values such as '<code>America/New_York</code>'
might cause "old" programs (that expect <code>TZ</code> to have a 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>) some other environment variable (for example, <code>TIMEZONE</code>)
to hold the string used to generate the <abbr>TZif</abbr> file's name. to hold the string used to generate the <abbr>TZif</abbr> file's name.
In the end, however, it was decided to continue using 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. assume pre-POSIX <code>TZ</code> values.
</p> </p>
</li> </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> <li>
Functions <code>tzalloc</code>, <code>tzfree</code>, Functions <code>tzalloc</code>, <code>tzfree</code>,
<code>localtime_rz</code>, and <code>mktime_z</code> for <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 and <code>localtime_rz</code> and <code>mktime_z</code> are
like <code>localtime_r</code> and <code>mktime</code> with an like <code>localtime_r</code> and <code>mktime</code> with an
extra <code>timezone_t</code> argument. 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>
<li> <li>
Negative <code>time_t</code> values are supported, on systems Negative <code>time_t</code> values are supported, on systems
@ -1116,6 +1180,7 @@ The vestigial <abbr>API</abbr>s are:
<li> <li>
The POSIX <code>tzname</code> variable does not suffice and is no The POSIX <code>tzname</code> variable does not suffice and is no
longer needed. longer needed.
It is planned to be removed in a future edition of POSIX.
To get a timestamp's time zone abbreviation, consult To get a timestamp's time zone abbreviation, consult
the <code>tm_zone</code> member if available; otherwise, the <code>tm_zone</code> member if available; otherwise,
use <code>strftime</code>'s <code>"%Z"</code> conversion use <code>strftime</code>'s <code>"%Z"</code> conversion
@ -1124,6 +1189,7 @@ The vestigial <abbr>API</abbr>s are:
<li> <li>
The POSIX <code>daylight</code> and <code>timezone</code> The POSIX <code>daylight</code> and <code>timezone</code>
variables do not suffice and are no longer needed. variables do not suffice and are no longer needed.
They are planned to be removed in a future edition of POSIX.
To get a timestamp's <abbr>UT</abbr> offset, consult To get a timestamp's <abbr>UT</abbr> offset, consult
the <code>tm_gmtoff</code> member if available; otherwise, the <code>tm_gmtoff</code> member if available; otherwise,
subtract values returned by <code>localtime</code> subtract values returned by <code>localtime</code>
@ -1278,13 +1344,13 @@ between now and the future time.
<p> <p>
Leap seconds were introduced in 1972 to accommodate the Leap seconds were introduced in 1972 to accommodate the
difference between atomic time and the less regular rotation of the earth. difference between atomic time and the less regular rotation of the earth.
Unfortunately they caused so many problems with civil Unfortunately they have caused so many problems with civil
timekeeping that they timekeeping that there are
are <a href="https://www.bipm.org/en/cgpm-2022/resolution-4">planned <a href="https://www.bipm.org/en/cgpm-2022/resolution-4">plans
to be discontinued by 2035</a>, with some as-yet-undetermined to discontinue them by 2035</a>.
mechanism replacing them, perhaps after the year 2135. Even if these plans come to fruition, a record of leap seconds will still be
Despite their impending obsolescence, a record of leap seconds is still needed to resolve timestamps from 1972 through 2035,
needed to resolve timestamps from 1972 through 2035. and there may also be a need to record whatever mechanism replaces them.
</p> </p>
<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 the establishment of a reference timescale for the Moon, which has
days roughly equivalent to 29.5 Earth days, and where relativistic days roughly equivalent to 29.5 Earth days, and where relativistic
effects cause clocks to tick slightly faster than on Earth. 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>
<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 magazine's 2002-11-11 issue; among other things, it proposed
year-round <abbr>DST</abbr> as a way of lessening wintertime despair. year-round <abbr>DST</abbr> as a way of lessening wintertime despair.
</li> </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> </ul>
<h2>Music</h2> <h2>Music</h2>
<ul> <ul>

View File

@ -81,10 +81,11 @@ C Library</a> (used in
title="Berkeley Software Distribution">BSD</abbr></a>, title="Berkeley Software Distribution">BSD</abbr></a>,
<a href="https://netbsd.org">Net<abbr>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.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://cygwin.com">Cygwin</a>,
<a href="https://mariadb.org">MariaDB</a>, <a href="https://mariadb.org">MariaDB</a>,
<a href="https://en.wikipedia.org/wiki/MINIX">MINIX</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://www.mysql.com">MySQL</a>,
<a href="https://en.wikipedia.org/wiki/WebOS"><abbr <a href="https://en.wikipedia.org/wiki/WebOS"><abbr
title="Web Operating System">webOS</abbr></a>, 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, and other entries represent smaller regions like Starke County,
Indiana, which switched from central to eastern time in 1991 Indiana, which switched from central to eastern time in 1991
and switched back in 2006. 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 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> implementation set the <code><abbr>TZ</abbr></code>
environment variable to the location's full name, environment variable to the location's full name,
e.g., <code><abbr>TZ</abbr>="America/New_York"</code>.</p> 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. <code>README</code> file for what to do next.
The code lets you compile the <code><abbr>tz</abbr></code> source files into 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 machine-readable binary files, one for each location. The binary files
are in a special timezone information format (<dfn><abbr>TZif</abbr></dfn>) are in a special format specified by
specified by <a href="https://datatracker.ietf.org/doc/html/8536">Internet <a href="https://datatracker.ietf.org/doc/html/8536">The
<abbr>RFC</abbr> 8536</a>. Time Zone Information Format (<abbr>TZif</abbr>)</a>
(Internet <abbr title="Request For Comments">RFC</abbr> 8536).
The code also lets The code also lets
you read a <abbr>TZif</abbr> file and interpret timestamps for that you read a <abbr>TZif</abbr> file and interpret timestamps for that
location.</p> location.</p>
@ -205,13 +207,11 @@ location.</p>
<p> <p>
The <code><abbr>tz</abbr></code> code and data The <code><abbr>tz</abbr></code> code and data
are by no means authoritative. If you find errors, please 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>, email changes to <a href="mailto:tz@iana.org"><code>tz@iana.org</code></a>,
the time zone mailing list. You can also <a the time zone mailing list. See
href="https://mm.icann.org/mailman/listinfo/tz">subscribe</a> to it <a href="https://lists.iana.org/postorius/lists/tz.iana.org/">the mailing
and browse the <a list's main page</a> to subscribe or to browse its archive of old messages.
href="https://mm.icann.org/pipermail/tz/">archive of old <a href="https://tzdata-meta.timtimeonline.com">Metadata for mailing list
messages</a>.
<a href="https://tzdata-meta.timtimeonline.com/">Metadata for mailing list
discussions</a> and corresponding data changes can be discussions</a> and corresponding data changes can be
generated <a href="https://github.com/timparenti/tzdata-meta">automatically</a>. generated <a href="https://github.com/timparenti/tzdata-meta">automatically</a>.
</p> </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 the <code><abbr>tz</abbr> README</code> file and installing the latest
data yourself. System-specific instructions for installing the data yourself. System-specific instructions for installing the
latest <code><abbr>tz</abbr></code> data have also been published 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 <a
href="https://source.android.com/devices/tech/config/timezone-rules">Android</a>, href="https://source.android.com/devices/tech/config/timezone-rules">Android</a>,
<a <a
@ -248,7 +248,7 @@ with lines terminated by <a href="https://en.wikipedia.org/wiki/Newline"><abbr
title="linefeed">LF</abbr></a>, title="linefeed">LF</abbr></a>,
which can be modified by common text editors such which can be modified by common text editors such
as <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>, 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>. <a href="https://www.vim.org">vim</a>.
Specialized source-file editing can be done via the Specialized source-file editing can be done via the
<a href="https://packagecontrol.io/packages/zoneinfo">Sublime <a href="https://packagecontrol.io/packages/zoneinfo">Sublime
@ -261,8 +261,8 @@ Studio Code</a>.
<p> <p>
For further information about updates, please see For further information about updates, please see
<a href="https://datatracker.ietf.org/doc/html/rfc6557">Procedures for <a href="https://datatracker.ietf.org/doc/html/rfc6557">Procedures for
Maintaining the Time Zone Database</a> (Internet <abbr Maintaining the Time Zone Database</a> (Internet <abbr>RFC</abbr> 6557).
title="Request For Comments">RFC</abbr> 6557). More detail can be More detail can be
found in <a href="theory.html">Theory and pragmatics of the found in <a href="theory.html">Theory and pragmatics of the
<code><abbr>tz</abbr></code> code and data</a>. <code><abbr>tz</abbr></code> code and data</a>.
<a href="https://a0.github.io/a0-tzmigration/">A0 TimeZone Migration</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 title="Extensible Markup Language">XML</abbr></a> format, and a variant
<a href="https://datatracker.ietf.org/doc/html/rfc7265">jCal</a> <a href="https://datatracker.ietf.org/doc/html/rfc7265">jCal</a>
(Internet <abbr>RFC</abbr> 7265) (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> title="JavaScript Object Notation">JSON</abbr></a> format.</li>
</ul> </ul>
</section> </section>
@ -413,7 +413,7 @@ distributions you can generally work around compatibility problems by
running the command <code>make rearguard_tarballs</code> and compiling running the command <code>make rearguard_tarballs</code> and compiling
from the resulting tarballs instead.</p> from the resulting tarballs instead.</p>
<ul> <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> href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a>
program that compiles program that compiles
<code><abbr>tz</abbr></code> source into iCalendar-compatible VTIMEZONE files. <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 <li>The <a href="https://howardhinnant.github.io/date/tz.html">Time Zone
Database Parser</a> is a Database Parser</a> is a
<a href="https://en.wikipedia.org/wiki/C++">C++</a> parser and <a href="https://en.wikipedia.org/wiki/C++">C++</a> parser and
runtime library with <a runtime library with a <a
href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0355r7.html">API</a> href="https://en.cppreference.com/w/cpp/chrono"><code>std::chrono</code> API</a>
adopted by that is a standard part of C++.
<a href="https://en.wikipedia.org/wiki/C++20">C++20</a>,
the current iteration of the C++ standard.
It is freely available under the It is freely available under the
<abbr title="Massachusetts Institute of Technology">MIT</abbr> license.</li> <abbr title="Massachusetts Institute of Technology">MIT</abbr> license.</li>
<li><a id="ICU" href="https://icu.unicode.org">International Components for <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 <li>The <a
href="https://www.oracle.com/java/technologies/javase/tzupdater-readme.html">TZUpdater 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 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://openjdk.org">OpenJDK</a> and
<a href="https://jdk.java.net/">Oracle JDK</a>. <a href="https://jdk.java.net">Oracle JDK</a>.
Although its source code is proprietary, its executable is available under the 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 <a href="https://www.oracle.com/a/tech/docs/tzupdater-lic.html">Java SE
Timezone Updater License Agreement</a>.</li> 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> ZIUpdater is licensed under the <abbr>GPL</abbr>.</li>
<li><a href="https://github.com/MenoData/Time4A">Time4A: Advanced date and <li><a href="https://github.com/MenoData/Time4A">Time4A: Advanced date and
time library for Android</a> 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 time and interval library for Java</a> compile
<code><abbr>tz</abbr></code> source into a binary format. <code><abbr>tz</abbr></code> source into a binary format.
Time4A is available under the Apache License and Time4J is 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> href="https://github.com/formatjs/date-time-format-timezone"><code>Intl.DateTimeFormat</code>
timezone polyfill</a> timezone polyfill</a>
is freely available under a <abbr>BSD</abbr>-style license.</li> 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 library manipulates timezone-aware timestamps in browsers and
in <a href="https://nodejs.org/en/">Node.js</a>. in <a href="https://nodejs.org/en/">Node.js</a>.
It is freely available under the <abbr>MIT</abbr> license.</li> 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 <code><abbr>tzdb</abbr></code> data, and are designed to replace <a
href="https://codeofmatt.com/javascript-date-type-is-horribly-broken/">JavaScript's href="https://codeofmatt.com/javascript-date-type-is-horribly-broken/">JavaScript's
problematic <code>Date</code> objects</a> when working with dates and times. 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 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> under the <abbr>MIT</abbr> license.</li>
<li><a href="https://github.com/pavkam/tzdb"><abbr>TZDB</abbr> &ndash; <li><a href="https://github.com/pavkam/tzdb"><abbr>TZDB</abbr> &ndash;
<abbr>IANA</abbr> Time Zone Database for Delphi/<abbr <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 and <a
href="https://en.wikipedia.org/wiki/Free_Pascal"><abbr>FPC</abbr></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> 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 Definitions for Python</a> compiles <code><abbr>tz</abbr></code> source into
<a href="https://www.python.org">Python</a>. <a href="https://www.python.org">Python</a>.
It is freely available under a <abbr>BSD</abbr>-style license. 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> <a href="https://github.com/nayarsystems/posix_tz_db"><code>posix_tz_db</code>
package</a> contains Python code package</a> contains Python code
to generate <abbr>CSV</abbr> and <abbr>JSON</abbr> tables that map 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> For example, it maps <code>"Africa/Cairo"</code>
to <code>"EET-2EEST,M4.5.5/0,M10.5.4/24"</code>, to <code>"EET-2EEST,M4.5.5/0,M10.5.4/24"</code>,
an approximation valid for Cairo timestamps from 2023 on. 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> The package is freely available under the MIT license.</li>
<li><a href="https://github.com/derickr/timelib">Timelib</a> is a C <li><a href="https://github.com/derickr/timelib">Timelib</a> is a C
library that reads <abbr>TZif</abbr> files and converts 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 Python is freely available under the
<a href="https://docs.python.org/3/license.html">Python Software Foundation <a href="https://docs.python.org/3/license.html">Python Software Foundation
License</a>. 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> <a href="https://pypi.org/project/tzdata/"><code>tzdata</code></a>
supplies TZif data if the underlying system data cannot be found; supplies TZif data if the underlying system data cannot be found;
it is freely available under the Apache License.</li> 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 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> of Legal Time in Germany</a>.</dd>
<dt>Israel</dt> <dt>Israel</dt>
<dd>The Interior Ministry periodically issues <a <dd><a
href="ftp://ftp.cs.huji.ac.il/pub/tz/announcements" href="https://tz.cs.huji.ac.il">Israel Timezone Files</a>
hreflang="he">announcements (in Hebrew)</a>.</dd> lists official time-change announcements and laws since 1940,
almost all in Hebrew.</dd>
<dt>Malaysia</dt> <dt>Malaysia</dt>
<dd>See Singapore <a href="#Singapore">below</a>.</dd> <dd>See Singapore <a href="#Singapore">below</a>.</dd>
<dt>Mexico</dt> <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 1972 even though the historical situation is messy, partly because
neither <abbr>UTC</abbr> nor <abbr>TAI</abbr> neither <abbr>UTC</abbr> nor <abbr>TAI</abbr>
is well-defined for sufficiently old timestamps.</li> is well-defined for sufficiently old timestamps.</li>
<li><a href="https://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> <li><a href="https://developers.google.com/time/smear">Leap Smear</a>
discusses how to gradually adjust <abbr>POSIX</abbr> clocks near 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 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> sixty seconds. This approach works with the default <code><abbr>tz</abbr></code>
"<code>posix</code>" configuration, is <a "<code>posix</code>" configuration, is <a
href="http://bk1.ntp.org/ntp-stable/README.leapsmear">supported</a> by 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 href="https://github.com/google/unsmear">supports</a> conversion between
<abbr>UTC</abbr> and smeared <abbr>POSIX</abbr> timestamps, and is used by major <abbr>UTC</abbr> and smeared <abbr>POSIX</abbr> timestamps, and is used by major
cloud service providers. However, according to cloud service providers. However, according to
@ -1111,11 +1124,18 @@ without Leap Seconds</a> gives pointers on this
contentious issue. contentious issue.
The General Conference on Weights and Measures The General Conference on Weights and Measures
<a href="https://www.bipm.org/en/cgpm-2022/resolution-4">decided in 2022</a> <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 to discontinue the use of leap seconds by 2035, and requested that no
as-yet-undetermined scheme some time after the year 2135. discontinuous adjustments be made to UTC for at least a century.
The World Radiocommunication Conference <a 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 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. 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> </li>
</ul> </ul>
</section> </section>
@ -1153,9 +1173,12 @@ headers.</li>
<li> <li>
<a href="https://datatracker.ietf.org/doc/html/rfc3339">Date and Time <a href="https://datatracker.ietf.org/doc/html/rfc3339">Date and Time
on the Internet: Timestamps</a> (Internet <abbr>RFC</abbr> 3339) on the Internet: Timestamps</a> (Internet <abbr>RFC</abbr> 3339)
specifies an <abbr>ISO</abbr> 8601 specifies an <abbr>ISO</abbr> 8601 profile for use in new Internet protocols.
profile for use in new Internet An extension, <a href="https://datatracker.ietf.org/doc/html/rfc9557">Date
protocols.</li> 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> <li>
<a href="https://web.archive.org/web/20190130042457/https://www.hackcraft.net/web/datetime/">Date &amp; Time <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 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> inventions, and these have been removed when possible.</li>
<li>Numeric time zone abbreviations typically count hours east of <li>Numeric time zone abbreviations typically count hours east of
<abbr>UT</abbr>, e.g., +09 for Japan and <abbr>UT</abbr>, e.g., +09 for Japan and
&minus;10 for Hawaii. However, the <abbr>POSIX</abbr> &minus;10 for Hawaii. However, <abbr>POSIX</abbr> proleptic
<code><abbr>TZ</abbr></code> environment variable uses the opposite convention. <code><abbr>TZ</abbr></code> settings use the opposite convention.
For example, one might use <code><abbr>TZ</abbr>="<abbr For example, one might use <code><abbr>TZ</abbr>="<abbr
title="Japan Standard Time">JST</abbr>-9"</code> and title="Japan Standard Time">JST</abbr>-9"</code> and
<code><abbr>TZ</abbr>="<abbr title="Hawaii Standard Time">HST</abbr>10"</code> <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. Fifteen bytes containing zeros reserved for future use.
.IP \(bu .IP \(bu
Six four-byte integer values, in the following order: Six four-byte integer values, in the following order:
.RS "\w' \(bu 'u" .RS "\w'\(bu 'u"
.TP "\w' 'u" .TP "\w' 'u"
.B tzh_ttisutcnt .B tzh_ttisutcnt
The number of UT/local indicators stored in the file. 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 The number of bytes of time zone abbreviation strings
stored in the file. stored in the file.
.RE .RE
.RE
.PP .PP
The above header is followed by the following fields, whose lengths The above header is followed by the following fields, whose lengths
depend on the contents of the header: 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 starting with the same-indexed transition time
and continuing up to but not including the next 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 (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. These values serve as indices into the next field.
.IP \(bu .IP \(bu
.B tzh_typecnt .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 is in the range [\-89999, 93599] (i.e., more than \-25 hours and less
than 26 hours); this allows easy support by implementations that than 26 hours); this allows easy support by implementations that
already support the POSIX-required range [\-24:59:59, 25:59:59]. already support the POSIX-required range [\-24:59:59, 25:59:59].
.RS "\w' 'u" .IP \(bu
.IP \(bu "\w'\(bu 'u"
.B tzh_charcnt .B tzh_charcnt
bytes that represent time zone designations, bytes that represent time zone designations,
which are null-terminated byte strings, each indexed by the 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 The standard/wall and UT/local indicators were designed for
transforming a TZif file's transition times into transitions appropriate transforming a TZif file's transition times into transitions appropriate
for another time zone specified via 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", 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 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 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. 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 the default rules are installation-dependent, and no implementation
is known to support this feature for timestamps past 2037, is known to support this feature for timestamps past 2037,
so users desiring (say) Greek time should instead specify 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. eight bytes are used for each transition time or leap second time.
(Leap second counts remain four bytes.) (Leap second counts remain four bytes.)
After the second header and data comes a newline-enclosed string 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 for use in handling instants
after the last transition time stored in the file after the last transition time stored in the file
or for all instants if the file has no transitions. or for all instants if the file has no transitions.
The TZ string is empty (i.e., nothing between the newlines) 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 If nonempty, the TZ string must agree with the local time
type after the last transition time if present in the eight-byte data; type after the last transition time if present in the eight-byte data;
for example, given the string 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 with the time period from the indefinite past up to but not including
the earliest transition time. the earliest transition time.
.SS Version 3 format .SS Version 3 format
For version-3-format timezone files, the TZ string may For version-3-format timezone files, a TZ string (see
use two minor extensions to the POSIX.1-2017 TZ format, as described in .BR newtzset (3))
.BR newtzset (3). may use the following POSIX.1-2024 extensions to POSIX.1-2017:
First, the hours part of its transition times may be signed and range from First, as in TZ="<\*-02>2<\*-01>,M3.5.0/\*-1,M10.5.0/0",
\-167 through 167 instead of the POSIX-required unsigned values 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. 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 January 1 at 00:00 and ends December 31 at 24:00 plus the difference
between daylight saving and standard time. between daylight saving and standard time.
.SS Version 4 format .SS Version 4 format
@ -354,7 +355,8 @@ version 2+ data even if the reader's native timestamps have only
.IP \(bu .IP \(bu
Some readers designed for version 2 might mishandle Some readers designed for version 2 might mishandle
timestamps after a version 3 or higher file's last transition, because 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 As a partial workaround, a writer can output more transitions
than necessary, so that only far-future timestamps are than necessary, so that only far-future timestamps are
mishandled by version 2 readers. 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 As a partial workaround, a writer can output more transitions
than necessary. than necessary.
.IP \(bu .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 Some readers do not use time type 0 for timestamps before
the first transition, in that they infer a time type using a the first transition, in that they infer a time type using a
heuristic that does not always select time type 0. 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: o Six four-byte integer values, in the following order:
tzh_ttisutcnt tzh_ttisutcnt
The number of UT/local indicators stored in the file. (UT The number of UT/local indicators stored in the file. (UT is
is Universal Time.) Universal Time.)
tzh_ttisstdcnt tzh_ttisstdcnt
The number of standard/wall indicators stored in the file. The number of standard/wall indicators stored in the file.
tzh_leapcnt tzh_leapcnt
The number of leap seconds for which data entries are stored The number of leap seconds for which data entries are stored
in the file. in the file.
tzh_timecnt tzh_timecnt
The number of transition times for which data entries are The number of transition times for which data entries are
stored in the file. stored in the file.
tzh_typecnt tzh_typecnt
The number of local time types for which data entries are The number of local time types for which data entries are
stored in the file (must not be zero). stored in the file (must not be zero).
tzh_charcnt tzh_charcnt
The number of bytes of time zone abbreviation strings stored The number of bytes of time zone abbreviation strings stored
in the file. in the file.
The above header is followed by the following fields, whose lengths The above header is followed by the following fields, whose lengths
depend on the contents of the header: depend on the contents of the header:
o tzh_timecnt four-byte signed integer values sorted in ascending o tzh_timecnt four-byte signed integer values sorted in ascending
order. These values are written in network byte order. Each is order. These values are written in network byte order. Each is
used as a transition time (as returned by time(2)) at which the used as a transition time (as returned by time(2)) at which the
rules for computing local time change. rules for computing local time change.
o tzh_timecnt one-byte unsigned integer values; each one but the o tzh_timecnt one-byte unsigned integer values; each one but the
last tells which of the different types of local time types last tells which of the different types of local time types
described in the file is associated with the time period described in the file is associated with the time period starting
starting with the same-indexed transition time and continuing up with the same-indexed transition time and continuing up to but not
to but not including the next transition time. (The last time including the next transition time. (The last time type is
type is present only for consistency checking with the present only for consistency checking with the proleptic TZ string
POSIX.1-2017-style TZ string described below.) These values described below.) These values serve as indices into the next
serve as indices into the next field. field.
o tzh_typecnt ttinfo entries, each defined as follows: o tzh_typecnt ttinfo entries, each defined as follows:
struct ttinfo { struct ttinfo {
int32_t tt_utoff; int32_t tt_utoff;
unsigned char tt_isdst; unsigned char tt_isdst;
unsigned char tt_desigidx; unsigned char tt_desigidx;
}; };
Each structure is written as a four-byte signed integer value Each structure is written as a four-byte signed integer value for
for tt_utoff, in network byte order, followed by a one-byte tt_utoff, in network byte order, followed by a one-byte boolean
boolean for tt_isdst and a one-byte value for tt_desigidx. In for tt_isdst and a one-byte value for tt_desigidx. In each
each structure, tt_utoff gives the number of seconds to be added structure, tt_utoff gives the number of seconds to be added to UT,
to UT, tt_isdst tells whether tm_isdst should be set by tt_isdst tells whether tm_isdst should be set by localtime(3) and
localtime(3) and tt_desigidx serves as an index into the array tt_desigidx serves as an index into the array of time zone
of time zone abbreviation bytes that follow the ttinfo entries abbreviation bytes that follow the ttinfo entries in the file; if
in the file; if the designated string is "-00", the ttinfo entry the designated string is "-00", the ttinfo entry is a placeholder
is a placeholder indicating that local time is unspecified. The indicating that local time is unspecified. The tt_utoff value is
tt_utoff value is never equal to -2**31, to let 32-bit clients never equal to -2**31, to let 32-bit clients negate it without
negate it without overflow. Also, in realistic applications overflow. Also, in realistic applications tt_utoff is in the
tt_utoff is in the range [-89999, 93599] (i.e., more than -25 range [-89999, 93599] (i.e., more than -25 hours and less than 26
hours and less than 26 hours); this allows easy support by hours); this allows easy support by implementations that already
implementations that already support the POSIX-required range support the POSIX-required range [-24:59:59, 25:59:59].
[-24:59:59, 25:59:59].
o tzh_charcnt bytes that represent time zone designations, which o tzh_charcnt bytes that represent time zone designations, which are
are null-terminated byte strings, each indexed by the null-terminated byte strings, each indexed by the tt_desigidx
tt_desigidx values mentioned above. The byte strings can values mentioned above. The byte strings can overlap if one is a
overlap if one is a suffix of the other. The encoding of suffix of the other. The encoding of these strings is not
these strings is not specified. specified.
o tzh_leapcnt pairs of four-byte values, written in network byte o tzh_leapcnt pairs of four-byte values, written in network byte
order; the first value of each pair gives the nonnegative time order; the first value of each pair gives the nonnegative time (as
(as returned by time(2)) at which a leap second occurs or at returned by time(2)) at which a leap second occurs or at which the
which the leap second table expires; the second is a signed leap second table expires; the second is a signed integer
integer specifying the correction, which is the total number specifying the correction, which is the total number of leap
of leap seconds to be applied during the time period starting seconds to be applied during the time period starting at the given
at the given time. The pairs of values are sorted in strictly time. The pairs of values are sorted in strictly ascending order
ascending order by time. Each pair denotes one leap second, by time. Each pair denotes one leap second, either positive or
either positive or negative, except that if the last pair has negative, except that if the last pair has the same correction as
the same correction as the previous one, the last pair denotes the previous one, the last pair denotes the leap second table's
the leap second table's expiration time. Each leap second is expiration time. Each leap second is at the end of a UTC calendar
at the end of a UTC calendar month. The first leap second has month. The first leap second has a nonnegative occurrence time,
a nonnegative occurrence time, and is a positive leap second and is a positive leap second if and only if its correction is
if and only if its correction is positive; the correction for positive; the correction for each leap second after the first
each leap second after the first differs from the previous differs from the previous leap second by either 1 for a positive
leap second by either 1 for a positive leap second, or -1 for leap second, or -1 for a negative leap second. If the leap second
a negative leap second. If the leap second table is empty, table is empty, the leap-second correction is zero for all
the leap-second correction is zero for all timestamps; timestamps; otherwise, for timestamps before the first occurrence
otherwise, for timestamps before the first occurrence time, time, the leap-second correction is zero if the first pair's
the leap-second correction is zero if the first pair's correction is 1 or -1, and is unspecified otherwise (which can
correction is 1 or -1, and is unspecified otherwise (which can happen only in files truncated at the start).
happen only in files truncated at the start).
o tzh_ttisstdcnt standard/wall indicators, each stored as a one- o tzh_ttisstdcnt standard/wall indicators, each stored as a one-byte
byte boolean; they tell whether the transition times boolean; they tell whether the transition times associated with
associated with local time types were specified as standard local time types were specified as standard time or local (wall
time or local (wall clock) time. clock) time.
o tzh_ttisutcnt UT/local indicators, each stored as a one-byte o tzh_ttisutcnt UT/local indicators, each stored as a one-byte
boolean; they tell whether the transition times associated boolean; they tell whether the transition times associated with
with local time types were specified as UT or local time. If local time types were specified as UT or local time. If a
a UT/local indicator is set, the corresponding standard/wall UT/local indicator is set, the corresponding standard/wall
indicator must also be set. indicator must also be set.
The standard/wall and UT/local indicators were designed for The standard/wall and UT/local indicators were designed for
transforming a TZif file's transition times into transitions transforming a TZif file's transition times into transitions
appropriate for another time zone specified via a appropriate for another time zone specified via a proleptic TZ string
POSIX.1-2017-style TZ string that lacks rules. For example, when that lacks rules. For example, when TZ="EET-2EEST" and there is no
TZ="EET-2EEST" and there is no TZif file "EET-2EEST", the idea was TZif file "EET-2EEST", the idea was to adapt the transition times from
to adapt the transition times from a TZif file with the well-known a TZif file with the well-known name "posixrules" that is present only
name "posixrules" that is present only for this purpose and is a for this purpose and is a copy of the file "Europe/Brussels", a file
copy of the file "Europe/Brussels", a file with a different UT with a different UT offset. POSIX does not specify the details of this
offset. POSIX does not specify this obsolete transformational obsolete transformational behavior, the default rules are installation-
behavior, the default rules are installation-dependent, and no dependent, and no implementation is known to support this feature for
implementation is known to support this feature for timestamps past timestamps past 2037, so users desiring (say) Greek time should instead
2037, so users desiring (say) Greek time should instead specify specify TZ="Europe/Athens" for better historical coverage, falling back
TZ="Europe/Athens" for better historical coverage, falling back on on TZ="EET-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required
TZ="EET-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required and older timestamps need not be handled accurately.
and older timestamps need not be handled accurately.
The localtime(3) function normally uses the first ttinfo structure The localtime(3) function normally uses the first ttinfo structure in
in the file if either tzh_timecnt is zero or the time argument is the file if either tzh_timecnt is zero or the time argument is less
less than the first transition time recorded in the file. than the first transition time recorded in the file.
Version 2 format Version 2 format
For version-2-format timezone files, the above header and data are For version-2-format timezone files, the above header and data are
followed by a second header and data, identical in format except that followed by a second header and data, identical in format except that
eight bytes are used for each transition time or leap second time. eight bytes are used for each transition time or leap second time.
(Leap second counts remain four bytes.) After the second header and (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 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 proleptic TZ, for use in handling instants after the last transition
after the last transition time stored in the file or for all instants time stored in the file or for all instants if the file has no
if the file has no transitions. The TZ string is empty (i.e., nothing transitions. The TZ string is empty (i.e., nothing between the
between the newlines) if there is no POSIX.1-2017-style representation newlines) if there is no proleptic representation for such instants.
for such instants. If nonempty, the TZ string must agree with the If nonempty, the TZ string must agree with the local time type after
local time type after the last transition time if present in the eight- the last transition time if present in the eight-byte data; for
byte data; for example, given the string "WET0WEST,M3.5.0/1,M10.5.0" example, given the string "WET0WEST,M3.5.0/1,M10.5.0" then if a last
then if a last transition time is in July, the transition's local time transition time is in July, the transition's local time type must
type must specify a daylight-saving time abbreviated "WEST" that is one specify a daylight-saving time abbreviated "WEST" that is one hour east
hour east of UT. Also, if there is at least one transition, time type of UT. Also, if there is at least one transition, time type 0 is
0 is associated with the time period from the indefinite past up to but associated with the time period from the indefinite past up to but not
not including the earliest transition time. including the earliest transition time.
Version 3 format Version 3 format
For version-3-format timezone files, the TZ string may use two minor For version-3-format timezone files, a TZ string (see newtzset(3)) may
extensions to the POSIX.1-2017 TZ format, as described in newtzset(3). use the following POSIX.1-2024 extensions to POSIX.1-2017: First, as in
First, the hours part of its transition times may be signed and range TZ="<-02>2<-01>,M3.5.0/-1,M10.5.0/0", the hours part of its transition
from -167 through 167 instead of the POSIX-required unsigned values times may be signed and range from -167 through 167 instead of being
from 0 through 24. Second, DST is in effect all year if it starts limited to unsigned values from 0 through 24. Second, as in
January 1 at 00:00 and ends December 31 at 24:00 plus the difference 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. between daylight saving and standard time.
Version 4 format Version 4 format
For version-4-format TZif files, the first leap second record can have 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 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 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, are present and the last entry's correction equals the previous one,
the last entry denotes the expiration of the leap second table instead the last entry denotes the expiration of the leap second table instead
of a leap second; timestamps after this expiration are unreliable in of a leap second; timestamps after this expiration are unreliable in
that future releases will likely add leap second entries after the that future releases will likely add leap second entries after the
expiration, and the added leap seconds will change how post-expiration expiration, and the added leap seconds will change how post-expiration
timestamps are treated. timestamps are treated.
Interoperability considerations Interoperability considerations
Future changes to the format may append more data. 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. 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. extends beyond the calculated end of the version 1 data block.
Other than version 1, writers should generate the lowest version number Other than version 1, writers should generate the lowest version number
needed by a file's data. For example, a writer should generate a 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 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 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 file should generate a version 3 file only if TZ string extensions are
necessary to accurately model transition times. necessary to accurately model transition times.
The sequence of time changes defined by the version 1 header and data 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 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 by the version 2+ header and data block, and by the footer. This
guideline helps obsolescent version 1 readers agree with current guideline helps obsolescent version 1 readers agree with current
readers about timestamps within the contiguous sub-sequence. It also readers about timestamps within the contiguous sub-sequence. It also
lets writers not supporting obsolescent readers use a tzh_timecnt of lets writers not supporting obsolescent readers use a tzh_timecnt of
zero in the version 1 data block to save space. zero in the version 1 data block to save space.
When a TZif file contains a leap second table expiration time, TZif When a TZif file contains a leap second table expiration time, TZif
readers should either refuse to process post-expiration timestamps, or readers should either refuse to process post-expiration timestamps, or
process them as if the expiration time did not exist (possibly with an process them as if the expiration time did not exist (possibly with an
error indication). error indication).
Time zone designations should consist of at least three (3) and no more Time zone designations should consist of at least three (3) and no more
than six (6) ASCII characters from the set of alphanumerics, "-", and than six (6) ASCII characters from the set of alphanumerics, "-", and
"+". This is for compatibility with POSIX requirements for time zone "+". This is for compatibility with POSIX requirements for time zone
abbreviations. 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 version 1 header and data block except for the purpose of skipping over
them. 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 blocks and check that they all fit within the actual file size, as part
of a validity check for the file. of a validity check for the file.
When a positive leap second occurs, readers should append an extra When a positive leap second occurs, readers should append an extra
second to the local minute containing the second just before the leap 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 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 seconds, the leap second occurs earlier than the last second of the
local minute and the minute's remaining local seconds are numbered local minute and the minute's remaining local seconds are numbered
through 60 instead of the usual 59; the UTC offset is unaffected. through 60 instead of the usual 59; the UTC offset is unaffected.
Common interoperability issues Common interoperability issues
This section documents common problems in reading or writing TZif This section documents common problems in reading or writing TZif
files. Most of these are problems in generating TZif files for use by files. Most of these are problems in generating TZif files for use by
older readers. The goals of this section are: 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, 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 generated by future TZif writers, and
o to help any future specification authors see what sort of problems o to help any future specification authors see what sort of problems
arise when the TZif format is changed. arise when the TZif format is changed.
When new versions of the TZif format have been defined, a design goal 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 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. 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 When complete compatibility was not achieved, an attempt was made to
limit glitches to rarely used timestamps and allow simple partial limit glitches to rarely used timestamps and allow simple partial
workarounds in writers designed to generate new-version data useful workarounds in writers designed to generate new-version data useful
even for older-version readers. This section attempts to document even for older-version readers. This section attempts to document
these compatibility issues and workarounds, as well as to document these compatibility issues and workarounds, as well as to document
other common bugs in readers. other common bugs in readers.
Interoperability problems with TZif include the following: Interoperability problems with TZif include the following:
o Some readers examine only version 1 data. As a partial o Some readers examine only version 1 data. As a partial
workaround, a writer can output as much version 1 data as workaround, a writer can output as much version 1 data as
possible. However, a reader should ignore version 1 data, and possible. However, a reader should ignore version 1 data, and
should use version 2+ data even if the reader's native timestamps should use version 2+ data even if the reader's native timestamps
have only 32 bits. have only 32 bits.
o Some readers designed for version 2 might mishandle timestamps o Some readers designed for version 2 might mishandle timestamps
after a version 3 or higher file's last transition, because they 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 cannot parse the POSIX.1-2024 extensions to POSIX.1-2017 in the
a partial workaround, a writer can output more transitions than proleptic TZ string. As a partial workaround, a writer can output
necessary, so that only far-future timestamps are mishandled by more transitions than necessary, so that only far-future
version 2 readers. timestamps are mishandled by version 2 readers.
o Some readers designed for version 2 do not support permanent o Some readers designed for version 2 do not support permanent
daylight saving time with transitions after 24:00 - e.g., a TZ daylight saving time with transitions after 24:00 - e.g., a TZ
string "EST5EDT,0/0,J365/25" denoting permanent Eastern Daylight string "EST5EDT,0/0,J365/25" denoting permanent Eastern Daylight
Time (-04). As a workaround, a writer can substitute standard 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 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 time zone with a never-used standard time (XXX, -03) and negative
daylight saving time (EDT, -04) all year. Alternatively, as a daylight saving time (EDT, -04) all year. Alternatively, as a
partial workaround a writer can substitute standard time for the partial workaround a writer can substitute standard time for the
next time zone east - e.g., "AST4" for permanent Atlantic Standard next time zone east - e.g., "AST4" for permanent Atlantic Standard
Time (-04). Time (-04).
o Some readers designed for version 2 or 3, and that require strict o Some readers designed for version 2 or 3, and that require strict
conformance to RFC 8536, reject version 4 files whose leap second conformance to RFC 8536, reject version 4 files whose leap second
tables are truncated at the start or that end in expiration times. tables are truncated at the start or that end in expiration times.
o Some readers ignore the footer, and instead predict future o Some readers ignore the footer, and instead predict future
timestamps from the time type of the last transition. As a timestamps from the time type of the last transition. As a
partial workaround, a writer can output more transitions than partial workaround, a writer can output more transitions than
necessary. 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 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 first transition, in that they infer a time type using a heuristic
that does not always select time type 0. As a partial workaround, 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 ** 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 ** of tzhead and a second instance of the data in which each coded transition
** time uses 8 rather than 4 chars, ** 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 ** instants after the last transition time stored in the file
** (with nothing between the newlines if there is no POSIX.1-2017 ** (with nothing between the newlines if there is no POSIX.1-2017
** representation for such instants). ** 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 ** 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 ** 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 ** time December 31 at 24:00 plus the difference between DST and
** standard time, indicating DST all year. ** standard time, indicating DST all year.

View File

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

View File

@ -152,7 +152,8 @@ tabbed columns line up.)
.nf .nf
.sp .sp
.if \n(.g .ft CR .if \n(.g .ft CR
.in +2 .if t .in +.5i
.if n .in +2
.nr w \w'1896-01-13 'u+\n(.i .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 .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" TZ="Pacific/Honolulu"

10
zdump.c
View File

@ -89,7 +89,7 @@ static bool warned;
static bool errout; static bool errout;
static char const *abbr(struct tm const *); 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 void dumptime(struct tm const *);
static time_t hunt(timezone_t, time_t, time_t, bool); static time_t hunt(timezone_t, time_t, time_t, bool);
static void show(timezone_t, char *, 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 *, static void showtrans(char const *, struct tm const *, time_t, char const *,
char const *); char const *);
static const char *tformat(void); 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? */ /* Is C an ASCII digit? */
static bool static bool
@ -134,7 +134,7 @@ size_overflow(void)
/* Return A + B, exiting if the result would overflow either ptrdiff_t /* Return A + B, exiting if the result would overflow either ptrdiff_t
or size_t. A and B are both nonnegative. */ 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) sumsize(ptrdiff_t a, ptrdiff_t b)
{ {
#ifdef ckd_add #ifdef ckd_add
@ -162,7 +162,7 @@ xstrsize(char const *str)
/* Return a pointer to a newly allocated buffer of size SIZE, exiting /* Return a pointer to a newly allocated buffer of size SIZE, exiting
on failure. SIZE should be positive. */ on failure. SIZE should be positive. */
ATTRIBUTE_MALLOC static void * static void *
xmalloc(ptrdiff_t size) xmalloc(ptrdiff_t size)
{ {
void *p = malloc(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> # include <stdarg.h>
/* A substitute for snprintf that is good enough for zdump. */ /* 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, ...) my_snprintf(char *s, size_t size, char const *format, ...)
{ {
int n; int n;

42
zic.8
View File

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

143
zic.8.txt
View File

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

31
zic.c
View File

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