From e66ca70de4daf76472887efffa74a91e32b98382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Fri, 6 Sep 2024 14:22:49 +0200 Subject: [PATCH] Import tzcode 2024b --- CONTRIBUTING | 18 +- Makefile | 412 ++++++++++++++++++++++++---------------------- NEWS | 124 +++++++++++++- asctime.c | 19 ++- localtime.c | 91 ++-------- newctime.3 | 102 +++++++----- newctime.3.txt | 47 +++--- newstrftime.3 | 30 ++-- newstrftime.3.txt | 16 +- newtzset.3 | 66 ++++++-- newtzset.3.txt | 50 ++++-- private.h | 114 ++++++++----- theory.html | 214 ++++++++++++++++-------- tz-art.html | 5 + tz-link.html | 113 ++++++++----- tzfile.5 | 44 +++-- tzfile.5.txt | 398 ++++++++++++++++++++++---------------------- tzfile.h | 8 +- tzselect.ksh | 125 +++++++------- version | 2 +- workman.sh | 3 +- zdump.8 | 3 +- zdump.c | 10 +- zic.8 | 42 +++-- zic.8.txt | 143 ++++++++-------- zic.c | 31 ++-- 26 files changed, 1276 insertions(+), 954 deletions(-) diff --git a/CONTRIBUTING b/CONTRIBUTING index 6d800e4c03a3..f6edbd3be7d3 100644 --- a/CONTRIBUTING +++ b/CONTRIBUTING @@ -23,10 +23,10 @@ such as renaming, adding or removing zones, please read "Theory and pragmatics of the tz code and data" . It is also good to browse the mailing list archives - for examples of patches that tend -to work well. Additions to data should contain commentary citing -reliable sources as justification. Citations should use "https:" URLs -if available. + +for examples of patches that tend to work well. +Changes should contain commentary citing reliable sources. +Citations should use "https:" URLs if available. For changes that fix sensitive security-related bugs, please see the distribution's 'SECURITY' file. @@ -63,12 +63,16 @@ If you use Git the following workflow may be helpful: * Edit source files. Include commentary that justifies the changes by citing reliable sources. - * Debug the changes, e.g.: + * Debug the changes locally, e.g.: - make check - make install + make TOPDIR=$PWD/tz clean check install ./zdump -v America/Los_Angeles + Although builds assume only basic POSIX, they use extra features + if available. 'make check' accesses validator.w3.org unless you + lack 'curl' or use 'make CURL=:'. If you have the latest GCC, + "make CFLAGS='$(GCC_DEBUG_FLAGS)'" does extra checking. + * For each separable change, commit it in the new branch, e.g.: git add northamerica diff --git a/Makefile b/Makefile index d48354c72df4..0087b4596515 100644 --- a/Makefile +++ b/Makefile @@ -3,17 +3,17 @@ # 2009-05-17 by Arthur David Olson. # Request POSIX conformance; this must be the first non-comment line. .POSIX: -# On older platforms you may need to scrounge for a POSIX-conforming 'make'. -# For example, on Solaris 10 (2005), use /usr/sfw/bin/gmake or -# /usr/xpg4/bin/make, not /usr/ccs/bin/make. +# On older platforms you may need to scrounge for POSIX conformance. +# For example, on Solaris 10 (2005) with Sun Studio 12 aka Sun C 5.9 (2007), +# use 'PATH=/usr/xpg4/bin:$PATH make CC=c99'. # To affect how this Makefile works, you can run a shell script like this: # # #!/bin/sh -# make CC='gcc -std=gnu11' "$@" +# make CC='gcc -std=gnu23' "$@" # -# This example script is appropriate for a pre-2017 GNU/Linux system -# where a non-default setting is needed to support this package's use of C99. +# This example script is appropriate for a circa 2024 GNU/Linux system +# where a non-default setting enables this package's optional use of C23. # # Alternatively, you can simply edit this Makefile to tailor the following # macro definitions. @@ -53,7 +53,7 @@ DATAFORM= main LOCALTIME= Factory -# The POSIXRULES macro controls interpretation of POSIX-2017.1-like TZ +# The POSIXRULES macro controls interpretation of POSIX-like TZ # settings like TZ='EET-2EEST' that lack DST transition rules. # If POSIXRULES is '-', no template is installed; this is the default. # Any other value for POSIXRULES is obsolete and should not be relied on, as: @@ -132,8 +132,9 @@ LIBDIR = $(TOPDIR)/$(USRDIR)/lib # Types to try, as an alternative to time_t. TIME_T_ALTERNATIVES = $(TIME_T_ALTERNATIVES_HEAD) $(TIME_T_ALTERNATIVES_TAIL) -TIME_T_ALTERNATIVES_HEAD = int_least64_t -TIME_T_ALTERNATIVES_TAIL = int_least32_t uint_least32_t uint_least64_t +TIME_T_ALTERNATIVES_HEAD = int_least64_t.ck +TIME_T_ALTERNATIVES_TAIL = int_least32_t.ck uint_least32_t.ck \ + uint_least64_t.ck # What kind of TZif data files to generate. (TZif is the binary time # zone data format that zic generates; see Internet RFC 8536.) @@ -219,6 +220,7 @@ LDLIBS= # than what POSIX specifies, assuming local time is UT. # For example, N is 252460800 on AmigaOS. # -DHAVE_DECL_ASCTIME_R=0 if does not declare asctime_r +# on POSIX platforms predating POSIX.1-2024 # -DHAVE_DECL_ENVIRON if declares 'environ' # -DHAVE_DECL_TIMEGM=0 if does not declare timegm # -DHAVE_DIRECT_H if mkdir needs (MS-Windows) @@ -229,7 +231,7 @@ LDLIBS= # where LDLIBS also needs to contain -lintl on some hosts; # -DHAVE_GETTEXT=0 to avoid using gettext # -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares -# ctime_r and asctime_r incompatibly with the POSIX standard +# ctime_r and asctime_r incompatibly with POSIX.1-2017 and earlier # (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined). # -DHAVE_INTTYPES_H=0 if does not work*+ # -DHAVE_LINK=0 if your system lacks a link function @@ -261,8 +263,11 @@ LDLIBS= # -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers # with external linkage, e.g., applications cannot define 'localtime'. # -Dssize_t=long on hosts like MS-Windows that lack ssize_t -# -DSUPPORT_C89 if the tzcode library should support C89 callers+ -# However, this might trigger latent bugs in C99-or-later callers. +# -DSUPPORT_C89=0 if the tzcode library should not support C89 callers +# Although -DSUPPORT_C89=0 might work around latent bugs in callers, +# it does not conform to POSIX. +# -DSUPPORT_POSIX2008 if the library should support older POSIX callers+ +# However, this might cause problems in POSIX.1-2024-or-later callers. # -DSUPPRESS_TZDIR to not prepend TZDIR to file names; this has # security implications and is not recommended for general use # -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires; @@ -274,7 +279,7 @@ LDLIBS= # -DTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory; # the default is system-supplied, typically "/usr/lib/locale" # -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified -# DST transitions for POSIX.1-2017-style TZ strings lacking them, +# DST transitions for proleptic format TZ strings lacking them, # in the usual case where POSIXRULES is '-'. If not specified, # TZDEFRULESTRING defaults to US rules for future DST transitions. # This mishandles some past timestamps, as US DST rules have changed. @@ -302,23 +307,25 @@ LDLIBS= # # * Options marked "*" can be omitted if your compiler is C23 compatible. # * Options marked "+" are obsolescent and are planned to be removed -# once the code assumes C99 or later, say in the year 2029. +# once the code assumes C99 or later (say in the year 2029) +# and POSIX.1-2024 or later (say in the year 2034). # # Select instrumentation via "make GCC_INSTRUMENT='whatever'". GCC_INSTRUMENT = \ -fsanitize=undefined -fsanitize-address-use-after-scope \ -fsanitize-undefined-trap-on-error -fstack-protector # Omit -fanalyzer from GCC_DEBUG_FLAGS, as it makes GCC too slow. -GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ +GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \ $(GCC_INSTRUMENT) \ -Wall -Wextra \ -Walloc-size-larger-than=100000 -Warray-bounds=2 \ -Wbad-function-cast -Wbidi-chars=any,ucn -Wcast-align=strict -Wdate-time \ -Wdeclaration-after-statement -Wdouble-promotion \ - -Wduplicated-branches -Wduplicated-cond \ + -Wduplicated-branches -Wduplicated-cond -Wflex-array-member-not-at-end \ -Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \ -Wimplicit-fallthrough=5 -Winit-self -Wlogical-op \ - -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ + -Wmissing-declarations -Wmissing-prototypes \ + -Wmissing-variable-declarations -Wnested-externs \ -Wnull-dereference \ -Wold-style-definition -Woverlength-strings -Wpointer-arith \ -Wshadow -Wshift-overflow=2 -Wstrict-overflow \ @@ -327,10 +334,9 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ -Wsuggest-attribute=const -Wsuggest-attribute=format \ -Wsuggest-attribute=malloc \ -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \ - -Wtrampolines -Wundef -Wuninitialized -Wunused-macros -Wuse-after-free=3 \ + -Wtrampolines -Wundef -Wunused-macros -Wuse-after-free=3 \ -Wvariadic-macros -Wvla -Wwrite-strings \ - -Wno-address -Wno-format-nonliteral -Wno-sign-compare \ - -Wno-type-limits + -Wno-format-nonliteral -Wno-sign-compare # # If your system has a "GMT offset" field in its "struct tm"s # (or if you decide to add such a field in your system's "time.h" file), @@ -341,9 +347,8 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ # Similarly, if your system has a "zone abbreviation" field, define # -DTM_ZONE=tm_zone # and define NO_TM_ZONE to suppress any guessing. -# Although these two fields are not required by POSIX.1-2017, -# POSIX 202x/D4 requires them and they are widely available -# on GNU/Linux and BSD systems. +# Although POSIX.1-2024 requires these fields and they are widely available +# on GNU/Linux and BSD systems, some older systems lack them. # # The next batch of options control support for external variables # exported by tzcode. In practice these variables are less useful @@ -353,7 +358,9 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ # # -DHAVE_TZNAME=0 # do not support "tzname" # # -DHAVE_TZNAME=1 # support "tzname", which is defined by system library # # -DHAVE_TZNAME=2 # support and define "tzname" -# # to the "CFLAGS=" line. "tzname" is required by POSIX.1-1988 and later. +# # to the "CFLAGS=" line. Although "tzname" is required by POSIX.1-1988 +# # and later, its contents are unspecified if you use a geographical TZ +# # and the variable is planned to be removed in a future POSIX edition. # # If not defined, the code attempts to guess HAVE_TZNAME from other macros. # # Warning: unless time_tz is also defined, HAVE_TZNAME=1 can cause # # crashes when combined with some platforms' standard libraries, @@ -364,7 +371,9 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ # # -DUSG_COMPAT=1 # support, and variables are defined by system library # # -DUSG_COMPAT=2 # support and define variables # # to the "CFLAGS=" line; "timezone" and "daylight" are inspired by Unix -# # Systems Group code and are required by POSIX.1-2008 and later (with XSI). +# # Systems Group code and are required by POSIX.1-2008 and later (with XSI), +# # although their contents are unspecified if you use a geographical TZ +# # and the variables are planned to be removed in a future edition of POSIX. # # If not defined, the code attempts to guess USG_COMPAT from other macros. # # # # To support the external variable "altzone", add @@ -428,18 +437,13 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ # The name of a POSIX-like library archiver, its flags, C compiler, # linker flags, and 'make' utility. Ordinarily the defaults suffice. -# The commented-out values are the defaults specified by POSIX.1-202x/D4. +# The commented-out values are the defaults specified by POSIX.1-2024. #AR = ar #ARFLAGS = -rv #CC = c17 #LDFLAGS = #MAKE = make -# For leap seconds, this Makefile uses LEAPSECONDS='-L leapseconds' in -# submake command lines. The default is no leap seconds. - -LEAPSECONDS= - # Where to fetch leap-seconds.list from. leaplist_URI = \ https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list @@ -461,7 +465,7 @@ ZFLAGS= # How to use zic to install TZif files. -ZIC_INSTALL= $(ZIC) -d '$(DESTDIR)$(TZDIR)' $(LEAPSECONDS) +ZIC_INSTALL= $(ZIC) -d '$(DESTDIR)$(TZDIR)' # The name of a POSIX-compliant 'awk' on your system. # mawk 1.3.3 and Solaris 10 /usr/bin/awk do not work. @@ -480,6 +484,7 @@ KSHELL= /bin/bash # Name of curl , used for HTML validation # and to fetch leap-seconds.list from upstream. +# Set CURL=: to disable use of the Internet. CURL= curl # Name of GNU Privacy Guard , used to sign distributions. @@ -533,21 +538,28 @@ OK_LINE= '^'$(OK_CHAR)'*$$' # Flags to give 'tar' when making a distribution. # Try to use flags appropriate for GNU tar. -GNUTARFLAGS= --format=pax --pax-option='delete=atime,delete=ctime' \ +GNUTARFLAGS= --format=pax --pax-option=delete=atime,delete=ctime \ --numeric-owner --owner=0 --group=0 \ --mode=go+u,go-w --sort=name -TARFLAGS= `if tar $(GNUTARFLAGS) --version >/dev/null 2>&1; \ - then echo $(GNUTARFLAGS); \ - else :; \ - fi` +SETUP_TAR= \ + export LC_ALL=C && \ + if tar $(GNUTARFLAGS) --version >/dev/null 2>&1; then \ + TAR='tar $(GNUTARFLAGS)'; \ + else \ + TAR=tar; \ + fi # Flags to give 'gzip' when making a distribution. GZIPFLAGS= -9n # When comparing .tzs files, use GNU diff's -F'^TZ=' option if supported. # This makes it easier to see which Zone has been affected. -DIFF_TZS= diff -u$$(! diff -u -F'^TZ=' - - <>/dev/null >&0 2>&1 \ - || echo ' -F^TZ=') +SETUP_DIFF_TZS = \ + if diff -u -F'^TZ=' - - <>/dev/null >&0 2>&1; then \ + DIFF_TZS='diff -u -F^TZ='; \ + else \ + DIFF_TZS='diff -u'; \ + fi # ':' on typical hosts; 'ranlib' on the ancient hosts that still need ranlib. RANLIB= : @@ -561,8 +573,8 @@ RANLIB= : TZCOBJS= zic.o -TZDOBJS= zdump.o localtime.o asctime.o strftime.o -DATEOBJS= date.o localtime.o strftime.o asctime.o +TZDOBJS= zdump.o localtime.o strftime.o +DATEOBJS= date.o localtime.o strftime.o LIBSRCS= localtime.c asctime.c difftime.c strftime.c LIBOBJS= localtime.o asctime.o difftime.o strftime.o HEADERS= tzfile.h private.h @@ -579,8 +591,7 @@ MANTXTS= newctime.3.txt newstrftime.3.txt newtzset.3.txt \ COMMON= calendars CONTRIBUTING LICENSE Makefile \ NEWS README SECURITY theory.html version WEB_PAGES= tz-art.html tz-how-to.html tz-link.html -CHECK_WEB_PAGES=check_theory.html check_tz-art.html \ - check_tz-how-to.html check_tz-link.html +CHECK_WEB_PAGES=theory.ck tz-art.ck tz-how-to.ck tz-link.ck DOCS= $(MANS) date.1 $(MANTXTS) $(WEB_PAGES) PRIMARY_YDATA= africa antarctica asia australasia \ europe northamerica southamerica @@ -641,8 +652,7 @@ install: all $(DATA) $(REDO) $(MANS) '$(DESTDIR)$(MANDIR)/man3' '$(DESTDIR)$(MANDIR)/man5' \ '$(DESTDIR)$(MANDIR)/man8' $(ZIC_INSTALL) -l $(LOCALTIME) \ - `case '$(POSIXRULES)' in ?*) echo '-p';; esac \ - ` $(POSIXRULES) \ + -p $(POSIXRULES) \ -t '$(DESTDIR)$(TZDEFAULT)' cp -f $(TABDATA) '$(DESTDIR)$(TZDIR)/.' cp tzselect '$(DESTDIR)$(BINDIR)/.' @@ -665,10 +675,10 @@ INSTALL: ALL install date.1 # and append "-dirty" if the contents do not already end in "-dirty". version: $(VERSION_DEPS) { (type git) >/dev/null 2>&1 && \ - V=`git describe --match '[0-9][0-9][0-9][0-9][a-z]*' \ - --abbrev=7 --dirty` || \ - if test '$(VERSION)' = unknown && V=`cat $@`; then \ - case $$V in *-dirty);; *) V=$$V-dirty;; esac; \ + V=$$(git describe --match '[0-9][0-9][0-9][0-9][a-z]*' \ + --abbrev=7 --dirty) || \ + if test '$(VERSION)' = unknown && read -r V <$@; then \ + V=$${V%-dirty}-dirty; \ else \ V='$(VERSION)'; \ fi; } && \ @@ -678,7 +688,7 @@ version: $(VERSION_DEPS) # These files can be tailored by setting BACKWARD, PACKRATDATA, PACKRATLIST. vanguard.zi main.zi rearguard.zi: $(DSTDATA_ZI_DEPS) $(AWK) \ - -v DATAFORM=`expr $@ : '\(.*\).zi'` \ + -v DATAFORM=$(@:.zi=) \ -v PACKRATDATA='$(PACKRATDATA)' \ -v PACKRATLIST='$(PACKRATLIST)' \ -f ziguard.awk \ @@ -687,7 +697,7 @@ vanguard.zi main.zi rearguard.zi: $(DSTDATA_ZI_DEPS) # This file has a version comment that attempts to capture any tailoring # via BACKWARD, DATAFORM, PACKRATDATA, PACKRATLIST, and REDO. tzdata.zi: $(DATAFORM).zi version zishrink.awk - version=`sed 1q version` && \ + read -r version $@ + ./zdump -i $(TZS_CUTOFF_FLAG) "$$PWD/$(@:.zd=)" >$@ TZS_NEW_DEPS = tzdata.zi zdump zic $(TZS_NEW): $(TZS_NEW_DEPS) @@ -812,20 +815,19 @@ $(TZS_NEW): $(TZS_NEW_DEPS) $(zic) -d tzs$(TZS_YEAR).dir tzdata.zi $(AWK) '/^L/{print "Link\t" $$2 "\t" $$3}' \ tzdata.zi | LC_ALL=C sort >$@.out - wd=`pwd` && \ - x=`$(AWK) '/^Z/{print "tzs$(TZS_YEAR).dir/" $$2 ".zd"}' \ + x=$$($(AWK) '/^Z/{print "tzs$(TZS_YEAR).dir/" $$2 ".zd"}' \ tzdata.zi \ - | LC_ALL=C sort -t . -k 2,2` && \ + | LC_ALL=C sort -t . -k 2,2) && \ set x $$x && \ shift && \ ZDS=$$* && \ - $(MAKE) wd="$$wd" TZS_CUTOFF_FLAG="$(TZS_CUTOFF_FLAG)" \ + $(MAKE) TZS_CUTOFF_FLAG="$(TZS_CUTOFF_FLAG)" \ ZDS="$$ZDS" $$ZDS && \ sed 's,^TZ=".*\.dir/,TZ=",' $$ZDS >>$@.out rm -fr tzs$(TZS_YEAR).dir mv $@.out $@ -# If $(TZS) exists but 'make check_tzs' fails, a maintainer should inspect the +# If $(TZS) exists but 'make tzs.ck' fails, a maintainer should inspect the # failed output and fix the inconsistency, perhaps by running 'make force_tzs'. $(TZS): touch $@ @@ -842,7 +844,7 @@ date: $(DATEOBJS) $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DATEOBJS) $(LDLIBS) tzselect: tzselect.ksh version - VERSION=`cat version` && sed \ + read -r VERSION /dev/null 2>&1 \ - || { LC_ALL='$(UTF8_LOCALE)'; export LC_ALL; false; }; } + || { export LC_ALL='$(UTF8_LOCALE)'; false; }; } -check_character_set: $(ENCHILADA) +character-set.ck: $(ENCHILADA) $(UTF8_LOCALE_MISSING) || { \ sharp='#' && \ ! grep -Env $(SAFE_LINE) $(MANS) date.1 $(MANTXTS) \ @@ -882,48 +884,55 @@ check_character_set: $(ENCHILADA) } touch $@ -check_white_space: $(ENCHILADA) +white-space.ck: $(ENCHILADA) $(UTF8_LOCALE_MISSING) || { \ - patfmt=' \t|[\f\r\v]' && pat=`printf "$$patfmt\\n"` && \ + enchilada='$(ENCHILADA)' && \ + patfmt=' \t|[\f\r\v]' && pat=$$(printf "$$patfmt\\n") && \ ! grep -En "$$pat|[$s]\$$" \ - $$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list); \ + $${enchilada%leap-seconds.list*} \ + $${enchilada#*leap-seconds.list}; \ } touch $@ PRECEDES_FILE_NAME = ^(Zone|Link[$s]+[^$s]+)[$s]+ FILE_NAME_COMPONENT_TOO_LONG = $(PRECEDES_FILE_NAME)[^$s]*[^/$s]{15} -check_name_lengths: $(TDATA_TO_CHECK) backzone - ! grep -En '$(FILE_NAME_COMPONENT_TOO_LONG)' \ +name-lengths.ck: $(TDATA_TO_CHECK) backzone + :;! grep -En '$(FILE_NAME_COMPONENT_TOO_LONG)' \ $(TDATA_TO_CHECK) backzone touch $@ +mainguard.ck: main.zi + test '$(PACKRATLIST)' || \ + cat $(TDATA) $(PACKRATDATA) | diff -u - main.zi + touch $@ + PRECEDES_STDOFF = ^(Zone[$s]+[^$s]+)?[$s]+ STDOFF = [-+]?[0-9:.]+ RULELESS_SAVE = (-|$(STDOFF)[sd]?) RULELESS_SLASHED_ABBRS = \ $(PRECEDES_STDOFF)$(STDOFF)[$s]+$(RULELESS_SAVE)[$s]+[^$s]*/ -check_slashed_abbrs: $(TDATA_TO_CHECK) - ! grep -En '$(RULELESS_SLASHED_ABBRS)' $(TDATA_TO_CHECK) +slashed-abbrs.ck: $(TDATA_TO_CHECK) + :;! grep -En '$(RULELESS_SLASHED_ABBRS)' $(TDATA_TO_CHECK) touch $@ CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; } -check_sorted: backward backzone +sorted.ck: backward backzone $(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} !/./ {g++}' \ backward | LC_ALL=C sort -cu - $(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu + $(AWK) '/^Zone.*\// {print $$2}' backzone | LC_ALL=C sort -cu touch $@ -check_back: checklinks.awk $(TDATA_TO_CHECK) +back.ck: checklinks.awk $(TDATA_TO_CHECK) $(AWK) \ -v DATAFORM=$(DATAFORM) \ -v backcheck=backward \ -f checklinks.awk $(TDATA_TO_CHECK) touch $@ -check_links: checklinks.awk tzdata.zi +links.ck: checklinks.awk tzdata.zi $(AWK) \ -v DATAFORM=$(DATAFORM) \ -f checklinks.awk tzdata.zi @@ -932,26 +941,36 @@ check_links: checklinks.awk tzdata.zi # Check timestamps from now through 28 years from now, to make sure # that zonenow.tab contains all sequences of planned timestamps, # without any duplicate sequences. In theory this might require -# 2800 years but that would take a long time to check. -CHECK_NOW_TIMESTAMP = `./date +%s` +# 2800+ years but that would take a long time to check. +CHECK_NOW_TIMESTAMP = $$(./date +%s) CHECK_NOW_FUTURE_YEARS = 28 -CHECK_NOW_FUTURE_SECS = $(CHECK_NOW_FUTURE_YEARS) '*' 366 '*' 24 '*' 60 '*' 60 -check_now: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab - rm -fr $@.dir - mkdir $@.dir - ./zic -d $@.dir tzdata.zi +CHECK_NOW_FUTURE_SECS = $(CHECK_NOW_FUTURE_YEARS) * 366 * 24 * 60 * 60 +now.ck: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab + rm -fr $@d + mkdir $@d + ./zic -d $@d tzdata.zi now=$(CHECK_NOW_TIMESTAMP) && \ - future=`expr $(CHECK_NOW_FUTURE_SECS) + $$now` && \ + future=$$(($(CHECK_NOW_FUTURE_SECS) + $$now)) && \ ./zdump -i -t $$now,$$future \ - $$(find $$PWD/$@.dir/????*/ -type f) \ - >$@.dir/zdump.tab + $$(find "$$PWD/$@d"/????*/ -type f) \ + >$@d/zdump-now.tab && \ + ./zdump -i -t 0,$$future \ + $$(find "$$PWD/$@d" -name Etc -prune \ + -o -type f ! -name '*.tab' -print) \ + >$@d/zdump-1970.tab $(AWK) \ - -v zdump_table=$@.dir/zdump.tab \ + -v zdump_table=$@d/zdump-now.tab \ -f checknow.awk zonenow.tab - rm -fr $@.dir + $(AWK) \ + 'BEGIN {print "-\t-\tUTC"} /^Zone/ {print "-\t-\t" $$2}' \ + $(PRIMARY_YDATA) backward factory | \ + $(AWK) \ + -v zdump_table=$@d/zdump-1970.tab \ + -f checknow.awk + rm -fr $@d touch $@ -check_tables: checktab.awk $(YDATA) backward zone.tab zone1970.tab +tables.ck: checktab.awk $(YDATA) backward zone.tab zone1970.tab for tab in $(ZONETABLES); do \ test "$$tab" = zone.tab && links='$(BACKWARD)' || links=''; \ $(AWK) -f checktab.awk -v zone_table=$$tab $(YDATA) $$links \ @@ -959,26 +978,24 @@ check_tables: checktab.awk $(YDATA) backward zone.tab zone1970.tab done touch $@ -check_tzs: $(TZS) $(TZS_NEW) +tzs.ck: $(TZS) $(TZS_NEW) if test -s $(TZS); then \ - $(DIFF_TZS) $(TZS) $(TZS_NEW); \ + $(SETUP_DIFF_TZS) && $$DIFF_TZS $(TZS) $(TZS_NEW); \ else \ cp $(TZS_NEW) $(TZS); \ fi touch $@ check_web: $(CHECK_WEB_PAGES) -check_theory.html: theory.html -check_tz-art.html: tz-art.html -check_tz-how-to.html: tz-how-to.html -check_tz-link.html: tz-link.html -check_theory.html check_tz-art.html check_tz-how-to.html check_tz-link.html: - $(CURL) -sS --url https://validator.w3.org/nu/ -F out=gnu \ - -F file=@$$(expr $@ : 'check_\(.*\)') -o $@.out && \ +.SUFFIXES: .ck .html +.html.ck: + { ! ($(CURL) --version) >/dev/null 2>&1 || \ + $(CURL) -sS --url https://validator.w3.org/nu/ -F out=gnu \ + -F file=@$<; } >$@.out && \ test ! -s $@.out || { cat $@.out; exit 1; } mv $@.out $@ -check_ziguard: rearguard.zi vanguard.zi ziguard.awk +ziguard.ck: rearguard.zi vanguard.zi ziguard.awk $(AWK) -v DATAFORM=rearguard -f ziguard.awk vanguard.zi | \ diff -u rearguard.zi - $(AWK) -v DATAFORM=vanguard -f ziguard.awk rearguard.zi | \ @@ -987,36 +1004,35 @@ check_ziguard: rearguard.zi vanguard.zi ziguard.awk # Check that zishrink.awk does not alter the data, and that ziguard.awk # preserves main-format data. -check_zishrink: check_zishrink_posix check_zishrink_right -check_zishrink_posix check_zishrink_right: \ +check_zishrink: zishrink-posix.ck zishrink-right.ck +zishrink-posix.ck zishrink-right.ck: \ zic leapseconds $(PACKRATDATA) $(PACKRATLIST) \ $(TDATA) $(DATAFORM).zi tzdata.zi - rm -fr $@.dir $@-t.dir $@-shrunk.dir - mkdir $@.dir $@-t.dir $@-shrunk.dir + rm -fr $@d t-$@d shrunk-$@d + mkdir $@d t-$@d shrunk-$@d case $@ in \ - *_right) leap='-L leapseconds';; \ + *right*) leap='-L leapseconds';; \ *) leap=;; \ esac && \ - $(ZIC) $$leap -d $@.dir $(DATAFORM).zi && \ - $(ZIC) $$leap -d $@-shrunk.dir tzdata.zi && \ + $(ZIC) $$leap -d $@d $(DATAFORM).zi && \ + $(ZIC) $$leap -d shrunk-$@d tzdata.zi && \ case $(DATAFORM),$(PACKRATLIST) in \ main,) \ - $(ZIC) $$leap -d $@-t.dir $(TDATA) && \ + $(ZIC) $$leap -d t-$@d $(TDATA) && \ $(AWK) '/^Rule/' $(TDATA) | \ - $(ZIC) $$leap -d $@-t.dir - $(PACKRATDATA) && \ - diff -r $@.dir $@-t.dir;; \ + $(ZIC) $$leap -d t-$@d - $(PACKRATDATA) && \ + diff -r $@d t-$@d;; \ esac - diff -r $@.dir $@-shrunk.dir - rm -fr $@.dir $@-t.dir $@-shrunk.dir + diff -r $@d shrunk-$@d + rm -fr $@d t-$@d shrunk-$@d touch $@ clean_misc: - rm -fr check_*.dir typecheck_*.dir - rm -f *.o *.out $(TIME_T_ALTERNATIVES) \ - check_* core typecheck_* \ + rm -fr *.ckd *.dir + rm -f *.ck *.core *.o *.out core core.* \ date tzdir.h tzselect version.h zdump zic libtz.a clean: clean_misc - rm -fr *.dir tzdb-*/ + rm -fr tzdb-*/ rm -f *.zi $(TZS_NEW) maintainer-clean: clean @@ -1027,7 +1043,7 @@ maintainer-clean: clean names: @echo $(ENCHILADA) -public: check check_public $(CHECK_TIME_T_ALTERNATIVES) \ +public: check public.ck $(CHECK_TIME_T_ALTERNATIVES) \ tarballs signatures date.1.txt: date.1 @@ -1041,7 +1057,7 @@ zdump.8.txt: zdump.8 zic.8.txt: zic.8 $(MANTXTS): workman.sh - LC_ALL=C sh workman.sh `expr $@ : '\(.*\)\.txt$$'` >$@.out + LC_ALL=C sh workman.sh $(@:.txt=) >$@.out mv $@.out $@ # Set file timestamps deterministically if possible, @@ -1054,13 +1070,13 @@ SET_TIMESTAMP_N = sh -c '\ n=$$0 dest=$$1; shift; \ <"$$dest" && \ if test $$n != 0 && \ - lsout=`ls -nt --time-style="+%s" "$$@" 2>/dev/null`; then \ + lsout=$$(ls -nt --time-style="+%s" "$$@" 2>/dev/null); then \ set x $$lsout && \ - timestamp=`expr $$7 + $$n` && \ + timestamp=$$(($$7 + $$n)) && \ echo "+ touch -md @$$timestamp $$dest" && \ touch -md @$$timestamp "$$dest"; \ else \ - newest=`ls -t "$$@" | sed 1q` && \ + newest=$$(ls -t "$$@" | sed 1q) && \ echo "+ touch -mr $$newest $$dest" && \ touch -mr "$$newest" "$$dest"; \ fi' @@ -1083,15 +1099,15 @@ SET_TIMESTAMP_DEP = $(SET_TIMESTAMP_N) 1 set-timestamps.out: $(EIGHT_YARDS) rm -f $@ if (type git) >/dev/null 2>&1 && \ - files=`git ls-files $(EIGHT_YARDS)` && \ + files=$$(git ls-files $(EIGHT_YARDS)) && \ touch -md @1 test.out; then \ rm -f test.out && \ for file in $$files; do \ if git diff --quiet $$file; then \ - time=`TZ=UTC0 git log -1 \ + time=$$(TZ=UTC0 git log -1 \ --format='tformat:%cd' \ --date='format:%Y-%m-%dT%H:%M:%SZ' \ - $$file` && \ + $$file) && \ echo "+ touch -md $$time $$file" && \ touch -md $$time $$file; \ else \ @@ -1100,8 +1116,8 @@ set-timestamps.out: $(EIGHT_YARDS) done; \ fi $(SET_TIMESTAMP_DEP) leapseconds $(LEAP_DEPS) - for file in `ls $(MANTXTS) | sed 's/\.txt$$//'`; do \ - $(SET_TIMESTAMP_DEP) $$file.txt $$file workman.sh || \ + for file in $(MANTXTS); do \ + $(SET_TIMESTAMP_DEP) $$file $${file%.txt} workman.sh || \ exit; \ done $(SET_TIMESTAMP_DEP) version $(VERSION_DEPS) @@ -1114,30 +1130,29 @@ set-tzs-timestamp.out: $(TZS) # The zics below ensure that each data file can stand on its own. # We also do an all-files run to catch links to links. -check_public: $(VERSION_DEPS) - rm -fr public.dir - mkdir public.dir - ln $(VERSION_DEPS) public.dir - cd public.dir \ +public.ck: $(VERSION_DEPS) + rm -fr $@d + mkdir $@d + ln $(VERSION_DEPS) $@d + cd $@d \ && $(MAKE) CFLAGS='$(GCC_DEBUG_FLAGS)' TZDIR='$(TZDIR)' ALL - for i in $(TDATA_TO_CHECK) public.dir/tzdata.zi \ - public.dir/vanguard.zi public.dir/main.zi \ - public.dir/rearguard.zi; \ + for i in $(TDATA_TO_CHECK) \ + tzdata.zi vanguard.zi main.zi rearguard.zi; \ do \ - public.dir/zic -v -d public.dir/zoneinfo $$i 2>&1 || exit; \ + $@d/zic -v -d $@d/zoneinfo $@d/$$i || exit; \ done - public.dir/zic -v -d public.dir/zoneinfo-all $(TDATA_TO_CHECK) + $@d/zic -v -d $@d/zoneinfo-all $(TDATA_TO_CHECK) : : Also check 'backzone' syntax. - rm public.dir/main.zi - cd public.dir && $(MAKE) PACKRATDATA=backzone main.zi - public.dir/zic -d public.dir/zoneinfo main.zi - rm public.dir/main.zi - cd public.dir && \ + rm $@d/main.zi + cd $@d && $(MAKE) PACKRATDATA=backzone main.zi + $@d/zic -d $@d/zoneinfo main.zi + rm $@d/main.zi + cd $@d && \ $(MAKE) PACKRATDATA=backzone PACKRATLIST=zone.tab main.zi - public.dir/zic -d public.dir/zoneinfo main.zi + $@d/zic -d $@d/zoneinfo main.zi : - rm -fr public.dir + rm -fr $@d touch $@ # Check that the code works under various alternative @@ -1145,46 +1160,47 @@ check_public: $(VERSION_DEPS) check_time_t_alternatives: $(TIME_T_ALTERNATIVES) $(TIME_T_ALTERNATIVES_TAIL): $(TIME_T_ALTERNATIVES_HEAD) $(TIME_T_ALTERNATIVES): $(VERSION_DEPS) - rm -fr $@.dir - mkdir $@.dir - ln $(VERSION_DEPS) $@.dir + rm -fr $@d + mkdir $@d + ln $(VERSION_DEPS) $@d case $@ in \ - int*32_t) range=-2147483648,2147483648;; \ + *32_t*) range=-2147483648,2147483648;; \ u*) range=0,4294967296;; \ *) range=-4294967296,4294967296;; \ esac && \ - wd=`pwd` && \ - zones=`$(AWK) '/^[^#]/ { print $$3 }' /dev/null; then \ quiet_option='-q'; \ else \ quiet_option=''; \ fi && \ - diff $$quiet_option -r $(TIME_T_ALTERNATIVES_HEAD).dir/etc \ - $@.dir/etc && \ + diff $$quiet_option -r $(TIME_T_ALTERNATIVES_HEAD)d/etc \ + $@d/etc && \ diff $$quiet_option -r \ - $(TIME_T_ALTERNATIVES_HEAD).dir/usr/share \ - $@.dir/usr/share; \ + $(TIME_T_ALTERNATIVES_HEAD)d/usr/share \ + $@d/usr/share; \ } touch $@ @@ -1199,7 +1215,7 @@ ALL_ASC = $(TRADITIONAL_ASC) $(REARGUARD_ASC) \ tarballs rearguard_tarballs tailored_tarballs traditional_tarballs \ signatures rearguard_signatures traditional_signatures: \ version set-timestamps.out rearguard.zi vanguard.zi - VERSION=`cat version` && \ + read -r VERSION $@.out mv $@.out $@ tzdata$(VERSION).tar.gz: set-timestamps.out - LC_ALL=C && export LC_ALL && \ - tar $(TARFLAGS) -cf - $(TZDATA_DIST) | \ + $(SETUP_TAR) && \ + $$TAR -cf - $(TZDATA_DIST) | \ gzip $(GZIPFLAGS) >$@.out mv $@.out $@ @@ -1251,9 +1267,9 @@ tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out : The dummy pacificnew pacifies TZUpdater 2.3.1 and earlier. $(CREATE_EMPTY) $@.dir/pacificnew touch -mr version $@.dir/version - LC_ALL=C && export LC_ALL && \ + $(SETUP_TAR) && \ (cd $@.dir && \ - tar $(TARFLAGS) -cf - \ + $$TAR -cf - \ $(TZDATA_DIST) pacificnew | \ gzip $(GZIPFLAGS)) >$@.out mv $@.out $@ @@ -1269,9 +1285,14 @@ tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out rm -fr $@.dir mkdir $@.dir : The dummy pacificnew pacifies TZUpdater 2.3.1 and earlier. + if test $(DATAFORM) = vanguard; then \ + pacificnew=; \ + else \ + pacificnew=pacificnew; \ + fi && \ cd $@.dir && \ $(CREATE_EMPTY) $(PRIMARY_YDATA) $(NDATA) backward \ - `test $(DATAFORM) = vanguard || echo pacificnew` + $$pacificnew (grep '^#' tzdata.zi && echo && cat $(DATAFORM).zi) \ >$@.dir/etcetera touch -mr tzdata.zi $@.dir/etcetera @@ -1291,9 +1312,9 @@ tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out test -f $@.dir/$$file || links="$$links $$file"; \ done && \ ln $$links $@.dir - LC_ALL=C && export LC_ALL && \ + $(SETUP_TAR) && \ (cd $@.dir && \ - tar $(TARFLAGS) -cf - * | gzip $(GZIPFLAGS)) >$@.out + $$TAR -cf - * | gzip $(GZIPFLAGS)) >$@.out mv $@.out $@ tzdb-$(VERSION).tar.lz: set-timestamps.out set-tzs-timestamp.out @@ -1301,8 +1322,8 @@ tzdb-$(VERSION).tar.lz: set-timestamps.out set-tzs-timestamp.out mkdir tzdb-$(VERSION) ln $(ENCHILADA) tzdb-$(VERSION) $(SET_TIMESTAMP) tzdb-$(VERSION) tzdb-$(VERSION)/* - LC_ALL=C && export LC_ALL && \ - tar $(TARFLAGS) -cf - tzdb-$(VERSION) | lzip -9 >$@.out + $(SETUP_TAR) && \ + $$TAR -cf - tzdb-$(VERSION) | lzip -9 >$@.out mv $@.out $@ tzcode$(VERSION).tar.gz.asc: tzcode$(VERSION).tar.gz @@ -1313,22 +1334,21 @@ $(ALL_ASC): $(GPG) --armor --detach-sign $? TYPECHECK_CFLAGS = $(CFLAGS) -DTYPECHECK -D__time_t_defined -D_TIME_T -typecheck: typecheck_long_long typecheck_unsigned -typecheck_long_long typecheck_unsigned: $(VERSION_DEPS) - rm -fr $@.dir - mkdir $@.dir - ln $(VERSION_DEPS) $@.dir - cd $@.dir && \ +typecheck: long-long.ck unsigned.ck +long-long.ck unsigned.ck: $(VERSION_DEPS) + rm -fr $@d + mkdir $@d + ln $(VERSION_DEPS) $@d + cd $@d && \ case $@ in \ - *_long_long) i="long long";; \ - *_unsigned ) i="unsigned" ;; \ + long-long.*) i="long long";; \ + unsigned.* ) i="unsigned" ;; \ esac && \ - typecheck_cflags='' && \ $(MAKE) \ CFLAGS="$(TYPECHECK_CFLAGS) \"-Dtime_t=$$i\"" \ - TOPDIR="`pwd`" \ + TOPDIR="$$PWD" \ install - $@.dir/zdump -i -c 1970,1971 Europe/Rome + $@d/zdump -i -c 1970,1971 Europe/Rome touch $@ zonenames: tzdata.zi @@ -1347,7 +1367,7 @@ zic.o: private.h tzfile.h tzdir.h version.h .PHONY: check_web check_zishrink .PHONY: clean clean_misc commit-leap-seconds.list dummy.zd .PHONY: fetch-leap-seconds.list force_tzs -.PHONY: install install_data maintainer-clean names +.PHONY: install maintainer-clean names .PHONY: posix_only posix_right public .PHONY: rearguard_signatures rearguard_signatures_version .PHONY: rearguard_tarballs rearguard_tarballs_version diff --git a/NEWS b/NEWS index d407342a50e6..83b8b8c8d39c 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,125 @@ News for the tz database +Release 2024b - 2024-09-04 12:27:47 -0700 + + Briefly: + Improve historical data for Mexico, Mongolia, and Portugal. + System V names are now obsolescent. + The main data form now uses %z. + The code now conforms to RFC 8536 for early timestamps. + Support POSIX.1-2024, which removes asctime_r and ctime_r. + Assume POSIX.2-1992 or later for shell scripts. + SUPPORT_C89 now defaults to 1. + + Changes to past timestamps + + Asia/Choibalsan is now an alias for Asia/Ulaanbaatar rather than + being a separate Zone with differing behavior before April 2008. + This seems better given our wildly conflicting information about + Mongolia's time zone history. (Thanks to Heitor David Pinto.) + + Historical transitions for Mexico have been updated based on + official Mexican decrees. The affected timestamps occur during + the years 1921-1927, 1931, 1945, 1949-1970, and 1981-1997. + The affected zones are America/Bahia_Banderas, America/Cancun, + America/Chihuahua, America/Ciudad_Juarez, America/Hermosillo, + America/Mazatlan, America/Merida, America/Mexico_City, + America/Monterrey, America/Ojinaga, and America/Tijuana. + (Thanks to Heitor David Pinto.) + + Historical transitions for Portugal, represented by Europe/Lisbon, + Atlantic/Azores, and Atlantic/Madeira, have been updated based on a + close reading of old Portuguese legislation, replacing previous data + mainly originating from Whitman and Shanks & Pottenger. These + changes affect a few transitions in 1917-1921, 1924, and 1940 + throughout these regions by a few hours or days, and various + timestamps between 1977 and 1993 depending on the region. In + particular, the Azores and Madeira did not observe DST from 1977 to + 1981. Additionally, the adoption of standard zonal time in former + Portuguese colonies have been adjusted: Africa/Maputo in 1909, and + Asia/Dili by 22 minutes at the start of 1912. + (Thanks to Tim Parenti.) + + Changes to past tm_isdst flags + + The period from 1966-04-03 through 1966-10-02 in Portugal is now + modeled as DST, to more closely reflect how contemporaneous changes + in law entered into force. + + Changes to data + + Names present only for compatibility with UNIX System V + (last released in the 1990s) have been moved to 'backward'. + These names, which for post-1970 timestamps mostly just duplicate + data of geographical names, were confusing downstream uses. + Names moved to 'backward' are now links to geographical names. + This affects behavior for TZ='EET' for some pre-1981 timestamps, + for TZ='CET' for some pre-1947 timestamps, and for TZ='WET' for + some pre-1996 timestamps. Also, TZ='MET' now behaves like + TZ='CET' and so uses the abbreviation "CET" rather than "MET". + Those needing the previous TZDB behavior, which does not match any + real-world clocks, can find the old entries in 'backzone'. + (Problem reported by Justin Grant.) + + The main source files' time zone abbreviations now use %z, + supported by zic since release 2015f and used in vanguard form + since release 2022b. For example, America/Sao_Paulo now contains + the zone continuation line "-3:00 Brazil %z", which is less error + prone than the old "-3:00 Brazil -03/-02". This does not change + the represented data: the generated TZif files are unchanged. + Rearguard form still avoids %z, to support obsolescent parsers. + + Asia/Almaty has been removed from zonenow.tab as it now agrees + with Asia/Tashkent for future timestamps, due to Kazakhstan's + 2024-02-29 time zone change. Similarly, America/Scoresbysund + has been removed, as it now agrees with America/Nuuk due to + its 2024-03-31 time zone change. + + Changes to code + + localtime.c now always uses a TZif file's time type 0 to handle + timestamps before the file's first transition. Formerly, + localtime.c sometimes inferred a different time type, in order to + handle problematic data generated by zic 2018e or earlier. As it + is now safe to assume more recent versions of zic, there is no + longer a pressing need to fail to conform RFC 8536 section 3.2, + which requires using time type 0 in this situation. This change + does not affect behavior when reading TZif files generated by zic + 2018f and later. + + POSIX.1-2024 removes asctime_r and ctime_r and does not let + libraries define them, so remove them except when needed to + conform to earlier POSIX. These functions are dangerous as they + can overrun user buffers. If you still need them, add + -DSUPPORT_POSIX2008 to CFLAGS. + + The SUPPORT_C89 option now defaults to 1 instead of 0, fixing a + POSIX-conformance bug introduced in 2023a. + + tzselect now supports POSIX.1-2024 proleptic TZ strings. Also, it + assumes POSIX.2-1992 or later, as practical porting targets now + all support that, and it uses some features from POSIX.1-2024 if + available. + + Changes to build procedure + + 'make check' no longer requires curl and Internet access. + + The build procedure now assumes POSIX.2-1992 or later, to simplify + maintenance. To build on Solaris 10, the only extant system still + defaulting to pre-POSIX, prepend /usr/xpg4/bin to PATH. + + Changes to documentation + + The documentation now reflects POSIX.1-2024. + + Changes to commentary + + Commentary about historical transitions in Portugal and her former + colonies has been expanded with links to many relevant legislation. + (Thanks to Tim Parenti.) + + Release 2024a - 2024-02-01 09:28:56 -0800 Briefly: @@ -161,7 +281,7 @@ Release 2023d - 2023-12-21 20:02:24 -0800 * It uses the special .POSIX target. * It quotes special characters more carefully. * It no longer mishandles builds in an ISO 8859 locale. - Due to the CC changes, TZDIR is now #defined in a file tzfile.h + Due to the CC changes, TZDIR is now #defined in a file tzdir.h built by 'make', not in a $(CC) -D option. Also, TZDEFAULT is now treated like TZDIR as they have similar roles. @@ -283,7 +403,7 @@ Release 2023a - 2023-03-22 12:39:33 -0700 To improve tzselect diagnostics, zone1970.tab's comments column is now limited to countries that have multiple timezones. - Note that leap seconds are planned to be discontinued by 2035. + Note that there are plans to discontinue leap seconds by 2035. Release 2022g - 2022-11-29 08:58:31 -0800 diff --git a/asctime.c b/asctime.c index a40661f28976..f75ec8685da8 100644 --- a/asctime.c +++ b/asctime.c @@ -1,4 +1,4 @@ -/* asctime and asctime_r a la POSIX and ISO C, except pad years before 1000. */ +/* asctime a la ISO C. */ /* ** This file is in the public domain, so clarified as of @@ -25,8 +25,8 @@ ** leading zeroes to get the newline in the traditional place. ** The -4 ensures that we get four characters of output even if ** we call a strftime variant that produces fewer characters for some years. -** The ISO C and POSIX standards prohibit padding the year, -** but many implementations pad anyway; most likely the standards are buggy. +** This conforms to recent ISO C and POSIX standards, which say behavior +** is undefined when the year is less than 1000 or greater than 9999. */ static char const ASCTIME_FMT[] = "%s %s%3d %.2d:%.2d:%.2d %-4s\n"; /* @@ -60,6 +60,18 @@ static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1]; static char buf_ctime[sizeof buf_asctime]; #endif +/* Publish asctime_r and ctime_r only when supporting older POSIX. */ +#if SUPPORT_POSIX2008 +# define asctime_static +#else +# define asctime_static static +# undef asctime_r +# undef ctime_r +# define asctime_r static_asctime_r +# define ctime_r static_ctime_r +#endif + +asctime_static char * asctime_r(struct tm const *restrict timeptr, char *restrict buf) { @@ -116,6 +128,7 @@ asctime(register const struct tm *timeptr) return asctime_r(timeptr, buf_asctime); } +asctime_static char * ctime_r(const time_t *timep, char *buf) { diff --git a/localtime.c b/localtime.c index 940a04fd09ab..7ae9ce5e519d 100644 --- a/localtime.c +++ b/localtime.c @@ -106,7 +106,7 @@ static char const UNSPEC[] = "-00"; for ttunspecified to work without crashing. */ enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 }; -/* Limit to time zone abbreviation length in POSIX.1-2017-style TZ strings. +/* Limit to time zone abbreviation length in proleptic TZ strings. This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */ #ifndef TZNAME_MAXIMUM # define TZNAME_MAXIMUM 255 @@ -130,11 +130,6 @@ struct state { char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"), 2 * (TZNAME_MAXIMUM + 1))]; struct lsinfo lsis[TZ_MAX_LEAPS]; - - /* The time type to use for early times or if no transitions. - It is always zero for recent tzdb releases. - It might be nonzero for data from tzdb 2018e or earlier. */ - int defaulttype; }; enum r_type { @@ -187,8 +182,9 @@ static int lcl_is_set; ** objects: a broken-down time structure and an array of char. ** Thanks to Paul Eggert for noting this. ** -** This requirement was removed in C99, so support it only if requested, -** as support is more likely to lead to bugs in badly written programs. +** Although this requirement was removed in C99 it is still present in POSIX. +** Follow the requirement if SUPPORT_C89, even though this is more likely to +** trigger latent bugs in programs. */ #if SUPPORT_C89 @@ -710,58 +706,6 @@ tzloadbody(char const *name, struct state *sp, bool doextend, if (sp->typecnt == 0) return EINVAL; - /* Infer sp->defaulttype from the data. Although this default - type is always zero for data from recent tzdb releases, - things are trickier for data from tzdb 2018e or earlier. - - The first set of heuristics work around bugs in 32-bit data - generated by tzdb 2013c or earlier. The workaround is for - zones like Australia/Macquarie where timestamps before the - first transition have a time type that is not the earliest - standard-time type. See: - https://mm.icann.org/pipermail/tz/2013-May/019368.html */ - /* - ** If type 0 does not specify local time, or is unused in transitions, - ** it's the type to use for early times. - */ - for (i = 0; i < sp->timecnt; ++i) - if (sp->types[i] == 0) - break; - i = i < sp->timecnt && ! ttunspecified(sp, 0) ? -1 : 0; - /* - ** Absent the above, - ** if there are transition times - ** and the first transition is to a daylight time - ** find the standard type less than and closest to - ** the type of the first transition. - */ - if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) { - i = sp->types[0]; - while (--i >= 0) - if (!sp->ttis[i].tt_isdst) - break; - } - /* The next heuristics are for data generated by tzdb 2018e or - earlier, for zones like EST5EDT where the first transition - is to DST. */ - /* - ** If no result yet, find the first standard type. - ** If there is none, punt to type zero. - */ - if (i < 0) { - i = 0; - while (sp->ttis[i].tt_isdst) - if (++i >= sp->typecnt) { - i = 0; - break; - } - } - /* A simple 'sp->defaulttype = 0;' would suffice here if we - didn't have to worry about 2018e-or-earlier data. Even - simpler would be to remove the defaulttype member and just - use 0 in its place. */ - sp->defaulttype = i; - return 0; } @@ -807,7 +751,7 @@ is_digit(char c) ** Return a pointer to that character. */ -ATTRIBUTE_REPRODUCIBLE static const char * +ATTRIBUTE_PURE_114833 static const char * getzname(register const char *strp) { register char c; @@ -828,7 +772,7 @@ getzname(register const char *strp) ** We don't do any checking here; checking is done later in common-case code. */ -ATTRIBUTE_REPRODUCIBLE static const char * +ATTRIBUTE_PURE_114833 static const char * getqzname(register const char *strp, const int delim) { register int c; @@ -1080,7 +1024,7 @@ transtime(const int year, register const struct rule *const rulep, } /* -** Given a POSIX.1-2017-style TZ string, fill in the rule tables as +** Given a POSIX.1 proleptic TZ string, fill in the rule tables as ** appropriate. */ @@ -1183,11 +1127,13 @@ tzparse(const char *name, struct state *sp, struct state const *basep) do { int_fast32_t yearsecs = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY; + time_t janfirst1 = janfirst; yearbeg--; - if (increment_overflow_time(&janfirst, -yearsecs)) { + if (increment_overflow_time(&janfirst1, -yearsecs)) { janoffset = -yearsecs; break; } + janfirst = janfirst1; } while (atlo < janfirst && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg); @@ -1313,7 +1259,7 @@ tzparse(const char *name, struct state *sp, struct state const *basep) /* ** Transitions from DST to DDST ** will effectively disappear since - ** POSIX.1-2017 provides for only one + ** proleptic TZ strings have only one ** DST offset. */ if (isdst && !sp->ttis[j].tt_ttisstd) { @@ -1342,7 +1288,6 @@ tzparse(const char *name, struct state *sp, struct state const *basep) sp->timecnt = 0; init_ttinfo(&sp->ttis[0], -stdoffset, false, 0); } - sp->defaulttype = 0; sp->charcnt = charcnt; cp = sp->chars; memcpy(cp, stdname, stdlen); @@ -1378,7 +1323,6 @@ zoneinit(struct state *sp, char const *name) sp->goback = sp->goahead = false; init_ttinfo(&sp->ttis[0], 0, false, 0); strcpy(sp->chars, utc); - sp->defaulttype = 0; return 0; } else { int err = tzload(name, sp, true); @@ -1465,8 +1409,8 @@ tzfree(timezone_t sp) } /* -** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and -** ctime_r are obsolescent and have potential security problems that +** NetBSD 6.1.4 has ctime_rz, but omit it because C23 deprecates ctime and +** POSIX.1-2024 removes ctime_r. Both have potential security problems that ** ctime_rz would share. Callers can instead use localtime_rz + strftime. ** ** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work @@ -1484,8 +1428,7 @@ tzfree(timezone_t sp) ** ** If successful and SETNAME is nonzero, ** set the applicable parts of tzname, timezone and altzone; -** however, it's OK to omit this step -** if the timezone is compatible with POSIX.1-2017 +** however, it's OK to omit this step for proleptic TZ strings ** since in that case tzset should have already done this step correctly. ** SETNAME's type is int_fast32_t for compatibility with gmtsub, ** but it is actually a boolean and its value should be 0 or 1. @@ -1553,7 +1496,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, return result; } if (sp->timecnt == 0 || t < sp->ats[0]) { - i = sp->defaulttype; + i = 0; } else { register int lo = 1; register int hi = sp->timecnt; @@ -2285,7 +2228,7 @@ mktime(struct tm *tmp) } #if STD_INSPIRED -/* This function is obsolescent and may disapper in future releases. +/* This function is obsolescent and may disappear in future releases. Callers can instead use mktime. */ time_t timelocal(struct tm *tmp) @@ -2303,7 +2246,7 @@ timelocal(struct tm *tmp) # define EXTERN_TIMEOFF static #endif -/* This function is obsolescent and may disapper in future releases. +/* This function is obsolescent and may disappear in future releases. Callers can instead use mktime_z with a fixed-offset zone. */ EXTERN_TIMEOFF time_t timeoff(struct tm *tmp, long offset) diff --git a/newctime.3 b/newctime.3 index 3b54d4ad6ad2..d19fd25b7926 100644 --- a/newctime.3 +++ b/newctime.3 @@ -9,16 +9,16 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time .el .ds - \- .B #include .PP -.BR "extern char *tzname[];" " /\(** (optional) \(**/" -.PP .B [[deprecated]] char *ctime(time_t const *clock); .PP +/* Only in POSIX.1-2017 and earlier. */ .B char *ctime_r(time_t const *clock, char *buf); .PP .B double difftime(time_t time1, time_t time0); .PP .B [[deprecated]] char *asctime(struct tm const *tm); .PP +/* Only in POSIX.1-2017 and earlier. */ .B "char *asctime_r(struct tm const *restrict tm," .B " char *restrict result);" .PP @@ -112,17 +112,6 @@ The function corrects for the time zone and any time zone adjustments (such as Daylight Saving Time in the United States). -After filling in the -.q "tm" -structure, -.B localtime -sets the -.BR tm_isdst 'th -element of -.B tzname -to a pointer to a string that's the time zone abbreviation to be used with -.BR localtime 's -return value. .PP The .B gmtime @@ -191,9 +180,19 @@ are determined. The .B mktime function -returns the specified calendar time; +returns the specified calendar time. If the calendar time cannot be represented, -it returns \-1. +it returns \-1 without updating the structure. +To distinguish failure from a valid \-1 return, +you can set +.B tm_wday +or +.B tm_yday +to a negative value before calling +.BR mktime ; +if that value is still negative when +.B mktime +returns, the calendar time could not be represented. .PP The .B difftime @@ -213,6 +212,13 @@ and functions are like their unsuffixed counterparts, except that they accept an additional argument specifying where to store the result if successful. +The +.B ctime_r +and +.B asctime_r +functions are present only on systems supporting POSIX.1-2017 and earlier, +as they are removed in POSIX.1-2024 and user code can define these +functions with other meanings. .PP The .B localtime_rz @@ -275,21 +281,43 @@ from UT, with positive values indicating east of the Prime Meridian. The field's name is derived from Greenwich Mean Time, a precursor of UT. .PP -In +In platforms conforming to POSIX.1-2024 the .B "struct tm" the .B tm_zone and .B tm_gmtoff -fields exist, and are filled in, only if arrangements to do -so were made when the library containing these functions was -created. -Similarly, the -.B tzname -variable is optional; also, there is no guarantee that -.B tzname -will -continue to exist in this form in future releases of this code. +fields exist, and are filled in. +For +.B localtime_rz +and +.B mktime_rz +the storage lifetime of the strings addressed by +.B tm_zone +extends until the corresponding +.B timezone_t +object is freed via +.BR tzfree . +For the other functions the lifetime extends until the +.I TZ +environment variable changes state and +.B tzset +is then called. +.PP +As a side effect, the +.BR ctime , +.B localtime +and +.B mktime +functions also behave as if +.B tzset +were called. +The +.B ctime_r +and +.B localtime_r +functions might (or might not) also behave this way. +This is for compatibility with older platforms, as required by POSIX. .SH FILES .ta \w'/usr/share/zoneinfo/posixrules\0\0'u /etc/localtime local timezone file @@ -303,11 +331,11 @@ continue to exist in this form in future releases of this code. If /usr/share/zoneinfo/GMT is absent, UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present. .SH SEE ALSO -getenv(3), -newstrftime(3), -newtzset(3), -time(2), -tzfile(5) +.BR getenv (3), +.BR newstrftime (3), +.BR newtzset (3), +.BR time (2), +.BR tzfile (5). .SH NOTES The return values of .BR asctime , @@ -317,20 +345,6 @@ and .B localtime point to static data overwritten by each call. -The -.B tzname -variable (once set) and the -.B tm_zone -field of a returned -.B "struct tm" -both point to an array of characters that -can be freed or overwritten by later calls to the functions -.BR localtime , -.BR tzfree , -and -.BR tzset , -if these functions affect the timezone information that specifies the -abbreviation in question. The remaining functions and data are thread-safe. .PP The diff --git a/newctime.3.txt b/newctime.3.txt index 01ec922f1461..be0cb316d21d 100644 --- a/newctime.3.txt +++ b/newctime.3.txt @@ -7,16 +7,16 @@ NAME SYNOPSIS #include - extern char *tzname[]; /* (optional) */ - [[deprecated]] char *ctime(time_t const *clock); + /* Only in POSIX.1-2017 and earlier. */ char *ctime_r(time_t const *clock, char *buf); double difftime(time_t time1, time_t time0); [[deprecated]] char *asctime(struct tm const *tm); + /* Only in POSIX.1-2017 and earlier. */ char *asctime_r(struct tm const *restrict tm, char *restrict result); @@ -68,9 +68,7 @@ DESCRIPTION The localtime and gmtime functions return pointers to "tm" structures, described below. The localtime function corrects for the time zone and any time zone adjustments (such as Daylight Saving Time in the United - States). After filling in the "tm" structure, localtime sets the - tm_isdst'th element of tzname to a pointer to a string that's the time - zone abbreviation to be used with localtime's return value. + States). The gmtime function converts to Coordinated Universal Time. @@ -96,15 +94,22 @@ DESCRIPTION set to represent the specified calendar time, but with their values forced to their normal ranges; the final value of tm_mday is not set until tm_mon and tm_year are determined. The mktime function returns - the specified calendar time; If the calendar time cannot be - represented, it returns -1. + the specified calendar time. If the calendar time cannot be + represented, it returns -1 without updating the structure. To + distinguish failure from a valid -1 return, you can set tm_wday or + tm_yday to a negative value before calling mktime; if that value is + still negative when mktime returns, the calendar time could not be + represented. The difftime function returns the difference between two calendar times, (time1 - time0), expressed in seconds. The ctime_r, localtime_r, gmtime_r, and asctime_r functions are like their unsuffixed counterparts, except that they accept an additional - argument specifying where to store the result if successful. + argument specifying where to store the result if successful. The + ctime_r and asctime_r functions are present only on systems supporting + POSIX.1-2017 and earlier, as they are removed in POSIX.1-2024 and user + code can define these functions with other meanings. The localtime_rz and mktime_z functions are like their unsuffixed counterparts, except that they accept an extra initial zone argument @@ -136,11 +141,17 @@ DESCRIPTION The field's name is derived from Greenwich Mean Time, a precursor of UT. - In struct tm the tm_zone and tm_gmtoff fields exist, and are filled in, - only if arrangements to do so were made when the library containing - these functions was created. Similarly, the tzname variable is - optional; also, there is no guarantee that tzname will continue to - exist in this form in future releases of this code. + In platforms conforming to POSIX.1-2024 the struct tm the tm_zone and + tm_gmtoff fields exist, and are filled in. For localtime_rz and + mktime_rz the storage lifetime of the strings addressed by tm_zone + extends until the corresponding timezone_t object is freed via tzfree. + For the other functions the lifetime extends until the TZ environment + variable changes state and tzset is then called. + + As a side effect, the ctime, localtime and mktime functions also behave + as if tzset were called. The ctime_r and localtime_r functions might + (or might not) also behave this way. This is for compatibility with + older platforms, as required by POSIX. FILES /etc/localtime local timezone file @@ -152,16 +163,12 @@ FILES /usr/share/zoneinfo/GMT0 if present. SEE ALSO - getenv(3), newstrftime(3), newtzset(3), time(2), tzfile(5) + getenv(3), newstrftime(3), newtzset(3), time(2), tzfile(5). NOTES The return values of asctime, ctime, gmtime, and localtime point to - static data overwritten by each call. The tzname variable (once set) - and the tm_zone field of a returned struct tm both point to an array of - characters that can be freed or overwritten by later calls to the - functions localtime, tzfree, and tzset, if these functions affect the - timezone information that specifies the abbreviation in question. The - remaining functions and data are thread-safe. + static data overwritten by each call. The remaining functions and data + are thread-safe. The asctime, asctime_r, ctime, and ctime_r functions behave strangely for years before 1000 or after 9999. The 1989 and 1999 editions of the diff --git a/newstrftime.3 b/newstrftime.3 index 704318ea2693..a9997a092d0a 100644 --- a/newstrftime.3 +++ b/newstrftime.3 @@ -91,11 +91,11 @@ as specified by brackets in the description. If a bracketed member name is followed by .q + , .B strftime -can use the named member even though POSIX.1-2017 does not list it; +can use the named member even though POSIX.1-2024 does not list it; if the name is followed by .q \*- , .B strftime -ignores the member even though POSIX.1-2017 lists it +ignores the member even though POSIX.1-2024 lists it which means portable code should set it. For portability, .BI * timeptr @@ -137,8 +137,8 @@ is replaced by the locale's appropriate date and time representation. .IR tm_hour , .IR tm_min , .IR tm_sec , -.IR tm_gmtoff +, -.IR tm_zone +, +.IR tm_gmtoff , +.IR tm_zone , .IR tm_isdst \*-]. .TP %D @@ -326,8 +326,8 @@ is replaced by the locale's appropriate time representation. .IR tm_hour , .IR tm_min , .IR tm_sec , -.IR tm_gmtoff +, -.IR tm_zone +, +.IR tm_gmtoff , +.IR tm_zone , .IR tm_isdst \*-]. .TP %x @@ -355,7 +355,7 @@ is replaced by the year without century as a decimal number [00,99]. %Z is replaced by the time zone abbreviation, or by the empty string if this is not determinable. -.RI [ tm_zone +, +.RI [ tm_zone , .IR tm_isdst \*-] .TP %z @@ -369,7 +369,7 @@ but local time is indeterminate; by convention this is used for locations while uninhabited, and corresponds to a zero offset when the time zone abbreviation begins with .q "\*-" . -.RI [ tm_gmtoff +, +.RI [ tm_gmtoff , .IR tm_zone +, .IR tm_isdst \*-] .TP @@ -398,7 +398,7 @@ also behaves as if were called. This is for compatibility with older platforms, as required by POSIX; it is not needed for -.BR tzset 's +.BR strftime 's own use. .SH "RETURN VALUE" If the conversion is successful, @@ -428,11 +428,11 @@ conversion and the number of seconds since the Epoch cannot be represented in a .c time_t . .SH SEE ALSO -date(1), -getenv(3), -newctime(3), -newtzset(3), -time(2), -tzfile(5) +.BR date (1), +.BR getenv (3), +.BR newctime (3), +.BR newtzset (3), +.BR time (2), +.BR tzfile (5). .SH BUGS There is no conversion specification for the phase of the moon. diff --git a/newstrftime.3.txt b/newstrftime.3.txt index ee7ed3031188..72331daae2e8 100644 --- a/newstrftime.3.txt +++ b/newstrftime.3.txt @@ -26,9 +26,9 @@ DESCRIPTION which are then copied into the array. The characters depend on the values of zero or more members of *timeptr as specified by brackets in the description. If a bracketed member name is followed by "+", - strftime can use the named member even though POSIX.1-2017 does not + strftime can use the named member even though POSIX.1-2024 does not list it; if the name is followed by "-", strftime ignores the member - even though POSIX.1-2017 lists it which means portable code should set + even though POSIX.1-2024 lists it which means portable code should set it. For portability, *timeptr should be initialized as if by a successful call to gmtime, localtime, mktime, timegm, or similar functions. @@ -48,7 +48,7 @@ DESCRIPTION %c is replaced by the locale's appropriate date and time representation. [tm_year, tm_yday, tm_mon, tm_mday, tm_wday, - tm_hour, tm_min, tm_sec, tm_gmtoff+, tm_zone+, tm_isdst-]. + tm_hour, tm_min, tm_sec, tm_gmtoff, tm_zone, tm_isdst-]. %D is equivalent to %m/%d/%y. [tm_year, tm_mon, tm_mday] @@ -139,7 +139,7 @@ DESCRIPTION %X is replaced by the locale's appropriate time representation. [tm_year-, tm_yday-, tm_mon-, tm_mday-, tm_wday-, tm_hour, - tm_min, tm_sec, tm_gmtoff+, tm_zone+, tm_isdst-]. + tm_min, tm_sec, tm_gmtoff, tm_zone, tm_isdst-]. %x is replaced by the locale's appropriate date representation. [tm_year, tm_yday, tm_mon, tm_mday, tm_wday, tm_hour-, tm_min-, @@ -152,7 +152,7 @@ DESCRIPTION [00,99]. [tm_year] %Z is replaced by the time zone abbreviation, or by the empty - string if this is not determinable. [tm_zone+, tm_isdst-] + string if this is not determinable. [tm_zone, tm_isdst-] %z is replaced by the offset from the Prime Meridian in the format +HHMM or -HHMM (ISO 8601) as appropriate, with positive values @@ -161,7 +161,7 @@ DESCRIPTION -0000 is used when the time is Universal Time but local time is indeterminate; by convention this is used for locations while uninhabited, and corresponds to a zero offset when the time zone - abbreviation begins with "-". [tm_gmtoff+, tm_zone+, tm_isdst-] + abbreviation begins with "-". [tm_gmtoff, tm_zone+, tm_isdst-] %% is replaced by a single %. @@ -171,7 +171,7 @@ DESCRIPTION As a side effect, strftime also behaves as if tzset were called. This is for compatibility with older platforms, as required by POSIX; it is - not needed for tzset's own use. + not needed for strftime's own use. RETURN VALUE If the conversion is successful, strftime returns the number of bytes @@ -194,7 +194,7 @@ ERRORS since the Epoch cannot be represented in a time_t. SEE ALSO - date(1), getenv(3), newctime(3), newtzset(3), time(2), tzfile(5) + date(1), getenv(3), newctime(3), newtzset(3), time(2), tzfile(5). BUGS There is no conversion specification for the phase of the moon. diff --git a/newtzset.3 b/newtzset.3 index b1384f32df0b..661fb25be098 100644 --- a/newtzset.3 +++ b/newtzset.3 @@ -15,6 +15,14 @@ tzset \- initialize time conversion information .PP .B void tzset(void); .PP +/\(** Optional and obsolescent: \(**/ +.br +.B extern char *tzname[]; +.br +.B extern long timezone; +.br +.B extern int daylight; +.PP .B cc ... \*-ltz .fi .SH DESCRIPTION @@ -165,7 +173,7 @@ describes when the change back happens. Each .I time field describes when, in current local time, the change to the other time is made. -As an extension to POSIX.1-2017, daylight saving is assumed to be in effect +Daylight saving is assumed to be in effect all year if it begins January 1 at 00:00 and ends December 31 at 24:00 plus the difference between daylight saving and standard time, leaving no room for standard time in the calendar. @@ -212,11 +220,7 @@ The .I time has the same format as .I offset -except that POSIX.1-2017 does not allow a leading sign (\c -.q "\*-" -or -.q "+" ). -As an extension to POSIX.1-2017, the hours part of +except that the hours part of .I time can range from \-167 through 167; this allows for unusual rules such as @@ -229,8 +233,7 @@ is not given, is .LP Here are some examples of .I TZ -values that directly specify the timezone; they use some of the -extensions to POSIX.1-2017. +values that directly specify the timezone. .TP .B EST5 stands for US Eastern Standard @@ -346,6 +349,22 @@ if the implied call to fails, .B tzset falls back on UT. +.PP +As a side effect, the +.B tzset +function sets some external variables if the platform defines them. +It sets +.BR tzname [0] +and +.BR tzname [1] +to pointers to strings that are time zone abbreviations to be used with +standard and daylight saving time, respectively. +It also sets +.B timezone +to be the number of seconds that standard time is west of the Prime Meridian, +and +.B daylight +to be zero if daylight saving time is never in effect, non-zero otherwise. .SH "RETURN VALUE" If successful, the .B tzalloc @@ -384,8 +403,29 @@ and If /usr/share/zoneinfo/GMT is absent, UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present. .SH SEE ALSO -getenv(3), -newctime(3), -newstrftime(3), -time(2), -tzfile(5) +.BR getenv (3), +.BR newctime (3), +.BR newstrftime (3), +.BR time (2), +.BR tzfile (5). +.SH NOTES +Portable code should not rely on the contents of the external variables +.BR tzname , +.B timezone +and +.B daylight +as their contents are unspecified (and do not make sense in general) +when a geographical TZ is used. +In multithreaded applications behavior is undefined if one thread accesses +one of these variables while another thread invokes +.BR tzset . +A future version of POSIX is planned to remove these variables; +callers can instead use the +.I tm_gmtoff +and +.I tm_zone +members of +.B struct tm, +or use +.B strftime +with "%z" or "%Z". diff --git a/newtzset.3.txt b/newtzset.3.txt index 957a2577bbce..e86b64ee9cca 100644 --- a/newtzset.3.txt +++ b/newtzset.3.txt @@ -12,6 +12,11 @@ SYNOPSIS void tzset(void); + /* Optional and obsolescent: */ + extern char *tzname[]; + extern long timezone; + extern int daylight; + cc ... -ltz DESCRIPTION @@ -88,12 +93,11 @@ DESCRIPTION standard to daylight saving time occurs and the second date describes when the change back happens. Each time field describes when, in current local time, the change - to the other time is made. As an extension to - POSIX.1-2017, daylight saving is assumed to be in effect - all year if it begins January 1 at 00:00 and ends - December 31 at 24:00 plus the difference between daylight - saving and standard time, leaving no room for standard - time in the calendar. + to the other time is made. Daylight saving is assumed to + be in effect all year if it begins January 1 at 00:00 and + ends December 31 at 24:00 plus the difference between + daylight saving and standard time, leaving no room for + standard time in the calendar. The format of date is one of the following: @@ -114,15 +118,13 @@ DESCRIPTION is the first week in which the d'th day occurs. Day zero is Sunday. - The time has the same format as offset except that - POSIX.1-2017 does not allow a leading sign ("-" or "+"). - As an extension to POSIX.1-2017, the hours part of time - can range from -167 through 167; this allows for unusual - rules such as "the Saturday before the first Sunday of - March". The default, if time is not given, is 02:00:00. + The time has the same format as offset except that the + hours part of time can range from -167 through 167; this + allows for unusual rules such as "the Saturday before the + first Sunday of March". The default, if time is not + given, is 02:00:00. - Here are some examples of TZ values that directly specify the timezone; - they use some of the extensions to POSIX.1-2017. + Here are some examples of TZ values that directly specify the timezone. EST5 stands for US Eastern Standard Time (EST), 5 hours behind UT, without daylight saving. @@ -183,6 +185,14 @@ DESCRIPTION getenv fails, tzset acts like tzalloc(nullptr); if the implied call to tzalloc fails, tzset falls back on UT. + As a side effect, the tzset function sets some external variables if + the platform defines them. It sets tzname[0] and tzname[1] to pointers + to strings that are time zone abbreviations to be used with standard + and daylight saving time, respectively. It also sets timezone to be + the number of seconds that standard time is west of the Prime Meridian, + and daylight to be zero if daylight saving time is never in effect, + non-zero otherwise. + RETURN VALUE If successful, the tzalloc function returns a nonnull pointer to the newly allocated object. Otherwise, it returns a null pointer and sets @@ -208,6 +218,16 @@ FILES /usr/share/zoneinfo/GMT0 if present. SEE ALSO - getenv(3), newctime(3), newstrftime(3), time(2), tzfile(5) + getenv(3), newctime(3), newstrftime(3), time(2), tzfile(5). + +NOTES + Portable code should not rely on the contents of the external variables + tzname, timezone and daylight as their contents are unspecified (and do + not make sense in general) when a geographical TZ is used. In + multithreaded applications behavior is undefined if one thread accesses + one of these variables while another thread invokes tzset. A future + version of POSIX is planned to remove these variables; callers can + instead use the tm_gmtoff and tm_zone members of struct tm, or use + strftime with "%z" or "%Z". Time Zone Database newtzset(3) diff --git a/private.h b/private.h index 0dac6af4e3cb..c33041049f4c 100644 --- a/private.h +++ b/private.h @@ -19,19 +19,22 @@ /* PORT_TO_C89 means the code should work even if the underlying compiler and library support only C89 plus C99's 'long long' - and perhaps a few other extensions to C89. SUPPORT_C89 means the - tzcode library should support C89 callers in addition to the usual - support for C99-and-later callers; however, C89 support can trigger - latent bugs in C99-and-later callers. These macros are obsolescent, - and the plan is to remove them along with any code needed only when - they are nonzero. A good time to do that might be in the year 2029 + and perhaps a few other extensions to C89. + + This macro is obsolescent, and the plan is to remove it along with + associated code. A good time to do that might be in the year 2029 because RHEL 7 (whose GCC defaults to C89) extended life cycle support (ELS) is scheduled to end on 2028-06-30. */ #ifndef PORT_TO_C89 # define PORT_TO_C89 0 #endif + +/* SUPPORT_C89 means the tzcode library should support C89 callers + in addition to the usual support for C99-and-later callers. + This defaults to 1 as POSIX requires, even though that can trigger + latent bugs in callers. */ #ifndef SUPPORT_C89 -# define SUPPORT_C89 0 +# define SUPPORT_C89 1 #endif #ifndef __STDC_VERSION__ @@ -69,10 +72,6 @@ ** You can override these in your C compiler options, e.g. '-DHAVE_GETTEXT=1'. */ -#ifndef HAVE_DECL_ASCTIME_R -# define HAVE_DECL_ASCTIME_R 1 -#endif - #if !defined HAVE__GENERIC && defined __has_extension # if !__has_extension(c_generic_selections) # define HAVE__GENERIC 0 @@ -236,6 +235,31 @@ # include /* for R_OK, and other POSIX goodness */ #endif /* HAVE_UNISTD_H */ +/* SUPPORT_POSIX2008 means the tzcode library should support + POSIX.1-2017-and-earlier callers in addition to the usual support for + POSIX.1-2024-and-later callers; however, this can be + incompatible with POSIX.1-2024-and-later callers. + This macro is obsolescent, and the plan is to remove it + along with any code needed only when it is nonzero. + A good time to do that might be in the year 2034. + This macro's name is SUPPORT_POSIX2008 because _POSIX_VERSION == 200809 + in POSIX.1-2017, a minor revision of POSIX.1-2008. */ +#ifndef SUPPORT_POSIX2008 +# if defined _POSIX_VERSION && _POSIX_VERSION <= 200809 +# define SUPPORT_POSIX2008 1 +# else +# define SUPPORT_POSIX2008 0 +# endif +#endif + +#ifndef HAVE_DECL_ASCTIME_R +# if SUPPORT_POSIX2008 +# define HAVE_DECL_ASCTIME_R 1 +# else +# define HAVE_DECL_ASCTIME_R 0 +# endif +#endif + #ifndef HAVE_STRFTIME_L # if _POSIX_VERSION < 200809 # define HAVE_STRFTIME_L 0 @@ -460,14 +484,6 @@ typedef unsigned long uintmax_t; # define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r) #endif -#if 3 <= __GNUC__ -# define ATTRIBUTE_MALLOC __attribute__((malloc)) -# define ATTRIBUTE_FORMAT(spec) __attribute__((format spec)) -#else -# define ATTRIBUTE_MALLOC /* empty */ -# define ATTRIBUTE_FORMAT(spec) /* empty */ -#endif - #if (defined __has_c_attribute \ && (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__)) # define HAVE___HAS_C_ATTRIBUTE true @@ -535,24 +551,27 @@ typedef unsigned long uintmax_t; # endif #endif #ifndef ATTRIBUTE_REPRODUCIBLE -# if 3 <= __GNUC__ -# define ATTRIBUTE_REPRODUCIBLE __attribute__((pure)) -# else -# define ATTRIBUTE_REPRODUCIBLE /* empty */ -# endif +# define ATTRIBUTE_REPRODUCIBLE /* empty */ #endif -#if HAVE___HAS_C_ATTRIBUTE -# if __has_c_attribute(unsequenced) -# define ATTRIBUTE_UNSEQUENCED [[unsequenced]] -# endif +/* GCC attributes that are useful in tzcode. + __attribute__((pure)) is stricter than [[reproducible]], + so the latter is an adequate substitute in non-GCC C23 platforms. */ +#if __GNUC__ < 3 +# define ATTRIBUTE_FORMAT(spec) /* empty */ +# define ATTRIBUTE_PURE ATTRIBUTE_REPRODUCIBLE +#else +# define ATTRIBUTE_FORMAT(spec) __attribute__((format spec)) +# define ATTRIBUTE_PURE __attribute__((pure)) #endif -#ifndef ATTRIBUTE_UNSEQUENCED -# if 3 <= __GNUC__ -# define ATTRIBUTE_UNSEQUENCED __attribute__((const)) -# else -# define ATTRIBUTE_UNSEQUENCED /* empty */ -# endif + +/* Avoid GCC bug 114833 . + Remove this macro and its uses when the bug is fixed in a GCC release, + because only the latest GCC matters for $(GCC_DEBUG_FLAGS). */ +#ifdef GCC_LINT +# define ATTRIBUTE_PURE_114833 ATTRIBUTE_PURE +#else +# define ATTRIBUTE_PURE_114833 /* empty */ #endif #if (__STDC_VERSION__ < 199901 && !defined restrict \ @@ -604,12 +623,8 @@ typedef time_tz tz_time_t; # undef asctime # define asctime tz_asctime -# undef asctime_r -# define asctime_r tz_asctime_r # undef ctime # define ctime tz_ctime -# undef ctime_r -# define ctime_r tz_ctime_r # undef difftime # define difftime tz_difftime # undef gmtime @@ -654,6 +669,12 @@ typedef time_tz tz_time_t; # define tzfree tz_tzfree # undef tzset # define tzset tz_tzset +# if SUPPORT_POSIX2008 +# undef asctime_r +# define asctime_r tz_asctime_r +# undef ctime_r +# define ctime_r tz_ctime_r +# endif # if HAVE_STRFTIME_L # undef strftime_l # define strftime_l tz_strftime_l @@ -679,10 +700,12 @@ typedef time_tz tz_time_t; # define DEPRECATED_IN_C23 ATTRIBUTE_DEPRECATED # endif DEPRECATED_IN_C23 char *asctime(struct tm const *); -char *asctime_r(struct tm const *restrict, char *restrict); DEPRECATED_IN_C23 char *ctime(time_t const *); +#if SUPPORT_POSIX2008 +char *asctime_r(struct tm const *restrict, char *restrict); char *ctime_r(time_t const *, char *); -ATTRIBUTE_UNSEQUENCED double difftime(time_t, time_t); +#endif +double difftime(time_t, time_t); size_t strftime(char *restrict, size_t, char const *restrict, struct tm const *restrict); # if HAVE_STRFTIME_L @@ -713,7 +736,7 @@ void tzset(void); time_t timegm(struct tm *); #endif -#if !HAVE_DECL_ASCTIME_R && !defined asctime_r +#if !HAVE_DECL_ASCTIME_R && !defined asctime_r && SUPPORT_POSIX2008 extern char *asctime_r(struct tm const *restrict, char *restrict); #endif @@ -798,10 +821,10 @@ timezone_t tzalloc(char const *); void tzfree(timezone_t); # if STD_INSPIRED # if TZ_TIME_T || !defined posix2time_z -ATTRIBUTE_REPRODUCIBLE time_t posix2time_z(timezone_t, time_t); +ATTRIBUTE_PURE time_t posix2time_z(timezone_t, time_t); # endif # if TZ_TIME_T || !defined time2posix_z -ATTRIBUTE_REPRODUCIBLE time_t time2posix_z(timezone_t, time_t); +ATTRIBUTE_PURE time_t time2posix_z(timezone_t, time_t); # endif # endif #endif @@ -973,8 +996,9 @@ enum { /* How many years to generate (in zic.c) or search through (in localtime.c). This is two years larger than the obvious 400, to avoid edge cases. - E.g., suppose a non-POSIX.1-2017 rule applies from 2012 on with transitions - in March and September, plus one-off transitions in November 2013. + E.g., suppose a rule applies from 2012 on with transitions + in March and September, plus one-off transitions in November 2013, + and suppose the rule cannot be expressed as a proleptic TZ string. If zic looked only at the last 400 years, it would set max_year=2413, with the intent that the 400 years 2014 through 2413 will be repeated. The last transition listed in the tzfile would be in 2413-09, diff --git a/theory.html b/theory.html index 516d2a525111..d3573ede0dfb 100644 --- a/theory.html +++ b/theory.html @@ -89,13 +89,15 @@ The tz code is upwards compatible with POSIX, an international standard for UNIX-like systems. -As of this writing, the current edition of POSIX is: The Open Group Base Specifications Issue 7, IEEE Std 1003.1-2017, 2018 -Edition. -Because the database's scope encompasses real-world changes to civil -timekeeping, its model for describing time is more complex than the -standard and daylight saving times supported by POSIX.1-2017. +Edition), POSIX.1-2024 requires support for the +tz database, which has a +model for describing civil time that is more complex than the +standard and daylight saving times required by POSIX.1-2017. A tz timezone corresponds to a ruleset that can have more than two changes per year, these changes need not merely flip back and forth between two alternatives, and the rules themselves @@ -159,7 +161,7 @@ among the following goals:

-Names normally have the form +Names normally have the format AREA/LOCATION, where AREA is a continent or ocean, and LOCATION is a specific location within the area. @@ -187,7 +189,7 @@ in decreasing order of importance: href="https://en.wikipedia.org/wiki/ASCII">ASCII letters, '.', '-' and '_'. Do not use digits, as that might create an ambiguity with POSIX.1-2017 + href="https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03">POSIX's proleptic TZ strings. A file name component must not exceed 14 characters or start with '-'. @@ -378,7 +380,8 @@ nowadays distributions typically use it and no great weight should be attached to whether a link is defined in backward or in some other file. The source file etcetera defines names that may be useful -on platforms that do not support POSIX.1-2017-style TZ strings; +on platforms that do not support proleptic TZ strings +like <+08>-8; no other source file other than backward contains links to its zones. One of etcetera's names is Etc/UTC, @@ -425,8 +428,8 @@ in decreasing order of importance: In other words, in the C locale the POSIX extended regular expression [-+[:alnum:]]{3,6} should match the abbreviation. - This guarantees that all abbreviations could have been specified by a - POSIX.1-2017 TZ string. + This guarantees that all abbreviations could have been specified + explicitly by a POSIX proleptic TZ string.

  • @@ -578,6 +581,11 @@ in decreasing order of importance: some sense undefined; this notation is derived from Internet RFC 3339. + (The abbreviation 'Z' that + Internet + RFC 9557 uses for this concept + would violate the POSIX requirement + of at least three characters in an abbreviation.)
  • @@ -775,7 +783,7 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes the Western 06:00 to be 12:00. These practices are largely outside the scope of the tz code and data, which provide only limited support for date and time localization - such as that required by POSIX.1-2017. + such as that required by POSIX. If DST is not used a different time zone can often do the trick; for example, in Kenya a TZ setting like <-03>3 or America/Cayenne starts @@ -866,29 +874,62 @@ Code compatible with this package is already part of many platforms, where the primary use of this package is to update obsolete time-related files. To do this, you may need to compile the time zone compiler -'zic' supplied with this package instead of using the -system 'zic', since the format of zic's +zic supplied with this package instead of using the +system zic, since the format of zic's input is occasionally extended, and a platform may still be shipping an older zic.

    -

    POSIX.1-2017 properties and limitations

    +

    +In POSIX, time display in a process is controlled by the +environment variable TZ, which can have two forms: +

      +
    • + A proleptic TZ value + like CET-1CEST,M3.5.0,M10.5.0/3 uses a complex + notation that specifies a single standard time along with daylight + saving rules that apply to all years past, present, and future. +
    • +
    • + A geographical TZ value + like Europe/Berlin 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 tz database. +
    • +
    + +

    POSIX.1-2017 properties and limitations

    +

    +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. +

    + +
      +
    • + POSIX.1-2017 does not require support for geographical TZ, + and there is no convenient and efficient way to determine + the UT offset and time zone abbreviation of arbitrary + timestamps, particularly for timezones + that do not fit into the POSIX model. +
    • - In POSIX.1-2017, time display in a process is controlled by the - environment variable TZ. - Unfortunately, the POSIX.1-2017 - TZ string takes a form that is hard to describe and - is error-prone in practice. - Also, POSIX.1-2017 TZ strings cannot deal with daylight + The proleptic TZ string, + which is all that POSIX.1-2017 requires, + has a format that is hard to describe and is error-prone in practice. + Also, proleptic TZ strings cannot deal with daylight saving time rules not based on the Gregorian calendar (as in Morocco), or with situations where more than two time zone abbreviations or UT offsets are used in an area.

      - The POSIX.1-2017 TZ string takes the following form: + A proleptic TZ string has the following format:

      @@ -955,7 +996,7 @@ an older zic.

      - Here is an example POSIX.1-2017 TZ string for New + Here is an example proleptic TZ string for New Zealand after 2007. It says that standard time (NZST) is 12 hours ahead of UT, and that daylight saving time @@ -966,26 +1007,46 @@ an older zic.

      TZ='NZST-12NZDT,M9.5.0,M4.1.0/3'

      - This POSIX.1-2017 TZ string is hard to remember, and + This proleptic TZ string is hard to remember, and mishandles some timestamps before 2008. - With this package you can use this instead: + With this package you can use a geographical TZ instead:

      TZ='Pacific/Auckland'
    • +
    + +

    +POSIX.1-2017 also has the limitations of POSIX.1-2024, +discussed in the next section. +

    + +

    POSIX.1-2024 properties and limitations

    +

    +POSIX.1-2024 extends POSIX.1-2017 in the following significant ways: +

    +
    • - POSIX does not define the DST transitions - for TZ values like - "EST5EDT". - Traditionally the current US DST rules - were used to interpret such values, but this meant that the - US DST rules were compiled into each - time conversion package, and when - US time conversion rules changed (as in the United - States in 1987 and again in 2007), all packages that - interpreted TZ values had to be updated - to ensure proper results. + POSIX.1-2024 requires support for geographical TZ. + Earlier POSIX editions require support only for proleptic TZ.
    • +
    • + POSIX.1-2024 requires struct tm + to have a UT offset member tm_gmtoff + and a time zone abbreviation member tm_zone. + Earlier POSIX editions lack this requirement. +
    • +
    • + DST transition times can range from −167:59:59 + to 167:59:59 instead of merely from 00:00:00 to 24:59:59. + This allows for proleptic TZ strings + like "<-02>2<-01>,M3.5.0/-1,M10.5.0/0" + where the transition time −1:00 means 23:00 the previous day. +
    • +
    +

    +However POSIX.1-2024, like earlier POSIX editions, has some limitations: +

    • The TZ environment variable is process-global, which makes it hard to write efficient, thread-safe applications that @@ -1003,16 +1064,34 @@ an older zic. handling daylight saving time shifts – as might be required to limit phone calls to off-peak hours.
    • -
    • - POSIX.1-2017 provides no convenient and efficient way to determine - the UT offset and time zone abbreviation of arbitrary - timestamps, particularly for timezones - that do not fit into the POSIX model. -
    • POSIX requires that time_t clock counts exclude leap seconds.
    • +
    • + POSIX does not define the DST transitions + for TZ values like + "EST5EDT". + Traditionally the current US DST rules + were used to interpret such values, but this meant that the + US DST rules were compiled into each + time conversion package, and when + US time conversion rules changed (as in the United + States in 1987 and again in 2007), all packages that + interpreted TZ values had to be updated + to ensure proper results. +
    • +
    + +

    Extensions to POSIX in the +tz code

    +

    + The tz code defines some properties + left unspecified by POSIX, and attempts to support some + extensions to POSIX. +

    + +
    • The tz code attempts to support all the time_t implementations allowed by POSIX. @@ -1026,21 +1105,14 @@ an older zic. and 40-bit integers are also used occasionally. Although earlier POSIX versions allowed time_t to be a floating-point type, this was not supported by any practical system, - and POSIX.1-2013 and the tz code both + and POSIX.1-2013+ and the tz code both require time_t to be an integer type.
    • -
    - -

    Extensions to POSIX.1-2017 in the -tz code

    -

    Music

      diff --git a/tz-link.html b/tz-link.html index 9fb57c9058a9..be2aae5489d6 100644 --- a/tz-link.html +++ b/tz-link.html @@ -81,10 +81,11 @@ C Library (used in title="Berkeley Software Distribution">BSD, NetBSD, OpenBSD, -Chromium OS, +ChromiumOS, Cygwin, MariaDB, MINIX, +musl libc, MySQL, webOS, @@ -112,9 +113,9 @@ eastern time but with different DST rules in 1975; and other entries represent smaller regions like Starke County, Indiana, which switched from central to eastern time in 1991 and switched back in 2006. -To use the database on an extended POSIX.1-2017 +title="Portable Operating System Interface">POSIX.1-2024 implementation set the TZ environment variable to the location's full name, e.g., TZ="America/New_York".

      @@ -192,9 +193,10 @@ After obtaining the code and data files, see the README file for what to do next. The code lets you compile the tz source files into machine-readable binary files, one for each location. The binary files -are in a special timezone information format (TZif) -specified by Internet -RFC 8536. +are in a special format specified by +The +Time Zone Information Format (TZif) +(Internet RFC 8536). The code also lets you read a TZif file and interpret timestamps for that location.

      @@ -205,13 +207,11 @@ location.

      The tz code and data are by no means authoritative. If you find errors, please -send changes to tz@iana.org, -the time zone mailing list. You can also subscribe to it -and browse the archive of old -messages. -Metadata for mailing list +email changes to tz@iana.org, +the time zone mailing list. See +the mailing +list's main page to subscribe or to browse its archive of old messages. +Metadata for mailing list discussions and corresponding data changes can be generated automatically.

      @@ -226,7 +226,7 @@ the process by tailoring the generic instructions in the tz README file and installing the latest data yourself. System-specific instructions for installing the latest tz data have also been published -for AIX, +for AIX, Android, LF, which can be modified by common text editors such as GNU Emacs, -gedit, and +gedit, and vim. Specialized source-file editing can be done via the Sublime @@ -261,8 +261,8 @@ Studio Code.

      For further information about updates, please see Procedures for -Maintaining the Time Zone Database (Internet RFC 6557). More detail can be +Maintaining the Time Zone Database (Internet RFC 6557). +More detail can be found in Theory and pragmatics of the tz code and data. A0 TimeZone Migration @@ -400,7 +400,7 @@ variant xCal title="Extensible Markup Language">XML format, and a variant jCal (Internet RFC 7265) -uses JSON format.

    @@ -413,7 +413,7 @@ distributions you can generally work around compatibility problems by running the command make rearguard_tarballs and compiling from the resulting tarballs instead.

      -
    • Vzic is a Vzic is a C program that compiles tz source into iCalendar-compatible VTIMEZONE files. @@ -440,11 +440,9 @@ transition in the tz database.
    • The Time Zone Database Parser is a C++ parser and -runtime library with API -adopted by -C++20, -the current iteration of the C++ standard. +runtime library with a std::chrono API +that is a standard part of C++. It is freely available under the MIT license.
    • International Components for @@ -467,8 +465,8 @@ freely available under the MIT license.
    • The TZUpdater tool compiles tz source into the format used by -OpenJDK and -Oracle JDK. +OpenJDK and +Oracle JDK. Although its source code is proprietary, its executable is available under the Java SE Timezone Updater License Agreement.
    • @@ -490,7 +488,7 @@ are alternatives to TZUpdater. IANA Updater's license is unclear; ZIUpdater is licensed under the GPL.
    • Time4A: Advanced date and time library for Android and -Time4J: Advanced date, +Time4J: Advanced date, time and interval library for Java compile tz source into a binary format. Time4A is available under the Apache License and Time4J is @@ -516,7 +514,7 @@ many of which also support runtimes lacking the timeZone option. href="https://github.com/formatjs/date-time-format-timezone">Intl.DateTimeFormat timezone polyfill is freely available under a BSD-style license.
    • -
    • The date-fns +
    • The date-fns library manipulates timezone-aware timestamps in browsers and in Node.js. It is freely available under the MIT license.
    • @@ -552,9 +550,9 @@ objects let programs access an abstract view of tzdb data, and are designed to replace JavaScript's problematic Date objects when working with dates and times. -
    • JuliaTime contains a +
    • JuliaTime contains a compiler from tz source into -Julia. It is freely available +Julia. It is freely available under the MIT license.
    • TZDBIANA Time Zone Database for Delphi/Delphi and FPC. It is freely available under a BSD-style license.
    • -
    • pytz – World Timezone +
    • pytz – World Timezone Definitions for Python compiles tz source into Python. It is freely available under a BSD-style license. @@ -621,11 +619,11 @@ License.
    • posix_tz_db package contains Python code to generate CSV and JSON tables that map -tz settings to POSIX.1-2017-like approximations. +tz settings to proleptic TZ approximations. For example, it maps "Africa/Cairo" to "EET-2EEST,M4.5.5/0,M10.5.4/24", 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.
    • Timelib is a C library that reads TZif files and converts @@ -649,7 +647,7 @@ that represent tzdb timezones. Python is freely available under the Python Software Foundation License. -A companion PyPI module +A companion PyPI module tzdata supplies TZif data if the underlying system data cannot be found; it is freely available under the Apache License.
    • @@ -897,9 +895,10 @@ summarizes and cites historical DST regulations. 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.
      Israel
      -
      The Interior Ministry periodically issues announcements (in Hebrew).
      +
      Israel Timezone Files +lists official time-change announcements and laws since 1940, +almost all in Hebrew.
      Malaysia
      See Singapore below.
      Mexico
      @@ -1081,6 +1080,20 @@ In practice the two configurations also agree for timestamps before 1972 even though the historical situation is messy, partly because neither UTC nor TAI is well-defined for sufficiently old timestamps. +
    • The +NTP Leap Second File covers the text file +leap-seconds.list, which lists the currently known leap seconds. +The IERS maintains this file, and a copy is distributed by +tzdb for use by NTP implementations like +classic +ntpd +and NTPsec. +The tz database also distributes leap second +information in a differently-formatted leapseconds text file, +as well as in the "right" configuration in binary form; for +example, right/UTC can be used +by chrony, +another NTP implementation.
    • Leap Smear discusses how to gradually adjust POSIX clocks near a leap second so that they disagree with UTC by at most a @@ -1088,7 +1101,7 @@ half second, even though every POSIX minute has exactly sixty seconds. This approach works with the default tz "posix" configuration, is supported by -the NTP reference implementation, NTP implementations, supports conversion between UTC and smeared POSIX timestamps, and is used by major cloud service providers. However, according to @@ -1111,11 +1124,18 @@ without Leap Seconds gives pointers on this contentious issue. The General Conference on Weights and Measures decided in 2022 -to discontinue the use of leap seconds by 2035, replacing them with an -as-yet-undetermined scheme some time after the year 2135. +to discontinue the use of leap seconds by 2035, and requested that no +discontinuous adjustments be made to UTC for at least a century. The World Radiocommunication Conference resolved in 2023 to cooperate with this process. +A proposal +to change the leap-second adjustments to Coordinated Universal Time +(doi:10.1088/1681-7575/ad6266) +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.
    @@ -1153,9 +1173,12 @@ headers.
  • Date and Time on the Internet: Timestamps (Internet RFC 3339) -specifies an ISO 8601 -profile for use in new Internet -protocols.
  • +specifies an ISO 8601 profile for use in new Internet protocols. +An extension, Date +and Time on the Internet: Timestamps with Additional Information +(Internet RFC 9557) extends this profile +to let you specify the tzdb timezone of a timestamp +via suffixes like "[Asia/Tokyo]".
  • Date & Time Formats on the Web 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.
  • Numeric time zone abbreviations typically count hours east of UT, e.g., +09 for Japan and -−10 for Hawaii. However, the POSIX -TZ environment variable uses the opposite convention. +−10 for Hawaii. However, POSIX proleptic +TZ settings use the opposite convention. For example, one might use TZ="JST-9" and TZ="HST10" diff --git a/tzfile.5 b/tzfile.5 index 867348d6726d..6e2fd70b6767 100644 --- a/tzfile.5 +++ b/tzfile.5 @@ -42,7 +42,7 @@ or Fifteen bytes containing zeros reserved for future use. .IP \(bu Six four-byte integer values, in the following order: -.RS "\w' \(bu 'u" +.RS "\w'\(bu 'u" .TP "\w' 'u" .B tzh_ttisutcnt The number of UT/local indicators stored in the file. @@ -66,6 +66,7 @@ in the file (must not be zero). The number of bytes of time zone abbreviation strings stored in the file. .RE +.RE .PP The above header is followed by the following fields, whose lengths depend on the contents of the header: @@ -85,7 +86,7 @@ described in the file is associated with the time period starting with the same-indexed transition time and continuing up to but not including the next transition time. (The last time type is present only for consistency checking with the -POSIX.1-2017-style TZ string described below.) +proleptic TZ string described below.) These values serve as indices into the next field. .IP \(bu .B tzh_typecnt @@ -134,8 +135,7 @@ Also, in realistic applications is in the range [\-89999, 93599] (i.e., more than \-25 hours and less than 26 hours); this allows easy support by implementations that already support the POSIX-required range [\-24:59:59, 25:59:59]. -.RS "\w' 'u" -.IP \(bu "\w'\(bu 'u" +.IP \(bu .B tzh_charcnt bytes that represent time zone designations, which are null-terminated byte strings, each indexed by the @@ -187,12 +187,12 @@ must also be set. The standard/wall and UT/local indicators were designed for transforming a TZif file's transition times into transitions appropriate for another time zone specified via -a POSIX.1-2017-style TZ string that lacks rules. +a proleptic TZ string that lacks rules. For example, when TZ="EET\*-2EEST" and there is no TZif file "EET\*-2EEST", the idea was to adapt the transition times from a TZif file with the well-known name "posixrules" that is present only for this purpose and is a copy of the file "Europe/Brussels", a file with a different UT offset. -POSIX does not specify this obsolete transformational behavior, +POSIX does not specify the details of this obsolete transformational behavior, the default rules are installation-dependent, and no implementation is known to support this feature for timestamps past 2037, so users desiring (say) Greek time should instead specify @@ -217,12 +217,12 @@ identical in format except that eight bytes are used for each transition time or leap second time. (Leap second counts remain four bytes.) After the second header and data comes a newline-enclosed string -in the style of the contents of a POSIX.1-2017 TZ environment variable, +in the style of the contents of a proleptic TZ, for use in handling instants after the last transition time stored in the file or for all instants if the file has no transitions. The TZ string is empty (i.e., nothing between the newlines) -if there is no POSIX.1-2017-style representation for such instants. +if there is no proleptic representation for such instants. If nonempty, the TZ string must agree with the local time type after the last transition time if present in the eight-byte data; for example, given the string @@ -235,13 +235,14 @@ Also, if there is at least one transition, time type 0 is associated with the time period from the indefinite past up to but not including the earliest transition time. .SS Version 3 format -For version-3-format timezone files, the TZ string may -use two minor extensions to the POSIX.1-2017 TZ format, as described in -.BR newtzset (3). -First, the hours part of its transition times may be signed and range from -\-167 through 167 instead of the POSIX-required unsigned values +For version-3-format timezone files, a TZ string (see +.BR newtzset (3)) +may use the following POSIX.1-2024 extensions to POSIX.1-2017: +First, as in TZ="<\*-02>2<\*-01>,M3.5.0/\*-1,M10.5.0/0", +the hours part of its transition times may be signed and range from +\-167 through 167 instead of being limited to unsigned values from 0 through 24. -Second, DST is in effect all year if it starts +Second, as in TZ="XXX3EDT4,0/0,J365/23", DST is in effect all year if it starts January 1 at 00:00 and ends December 31 at 24:00 plus the difference between daylight saving and standard time. .SS Version 4 format @@ -354,7 +355,8 @@ version 2+ data even if the reader's native timestamps have only .IP \(bu Some readers designed for version 2 might mishandle timestamps after a version 3 or higher file's last transition, because -they cannot parse extensions to POSIX.1-2017 in the TZ-like string. +they cannot parse the POSIX.1-2024 extensions to POSIX.1-2017 +in the proleptic TZ string. As a partial workaround, a writer can output more transitions than necessary, so that only far-future timestamps are mishandled by version 2 readers. @@ -386,6 +388,18 @@ timestamps from the time type of the last transition. As a partial workaround, a writer can output more transitions than necessary. .IP \(bu +Some stripped-down readers ignore everything but the footer, +and use its proleptic TZ string to calculate all timestamps. +Although this approach often works for current and future timestamps, +it obviously has problems with past timestamps, +and even for current timestamps it can fail for settings like +TZ="Africa/Casablanca". This corresponds to a TZif file +containing explicit transitions through the year 2087, +followed by a footer containing the TZ string +.q <+01>\*-1 , +which should be used only for timestamps after the last +explicit transition. +.IP \(bu Some readers do not use time type 0 for timestamps before the first transition, in that they infer a time type using a heuristic that does not always select time type 0. diff --git a/tzfile.5.txt b/tzfile.5.txt index ed1763ae956b..7ebcf5a35b88 100644 --- a/tzfile.5.txt +++ b/tzfile.5.txt @@ -24,276 +24,284 @@ DESCRIPTION o Six four-byte integer values, in the following order: - tzh_ttisutcnt - The number of UT/local indicators stored in the file. (UT - is Universal Time.) + tzh_ttisutcnt + The number of UT/local indicators stored in the file. (UT is + Universal Time.) - tzh_ttisstdcnt - The number of standard/wall indicators stored in the file. + tzh_ttisstdcnt + The number of standard/wall indicators stored in the file. - tzh_leapcnt - The number of leap seconds for which data entries are stored - in the file. + tzh_leapcnt + The number of leap seconds for which data entries are stored + in the file. - tzh_timecnt - The number of transition times for which data entries are - stored in the file. + tzh_timecnt + The number of transition times for which data entries are + stored in the file. - tzh_typecnt - The number of local time types for which data entries are - stored in the file (must not be zero). + tzh_typecnt + The number of local time types for which data entries are + stored in the file (must not be zero). - tzh_charcnt - The number of bytes of time zone abbreviation strings stored - in the file. + tzh_charcnt + The number of bytes of time zone abbreviation strings stored + in the file. - The above header is followed by the following fields, whose lengths - depend on the contents of the header: + The above header is followed by the following fields, whose lengths + depend on the contents of the header: - o tzh_timecnt four-byte signed integer values sorted in ascending - order. These values are written in network byte order. Each is - used as a transition time (as returned by time(2)) at which the - rules for computing local time change. + o tzh_timecnt four-byte signed integer values sorted in ascending + order. These values are written in network byte order. Each is + used as a transition time (as returned by time(2)) at which the + rules for computing local time change. - o tzh_timecnt one-byte unsigned integer values; each one but the - last tells which of the different types of local time types - described in the file is associated with the time period - starting with the same-indexed transition time and continuing up - to but not including the next transition time. (The last time - type is present only for consistency checking with the - POSIX.1-2017-style TZ string described below.) These values - serve as indices into the next field. + o tzh_timecnt one-byte unsigned integer values; each one but the + last tells which of the different types of local time types + described in the file is associated with the time period starting + with the same-indexed transition time and continuing up to but not + including the next transition time. (The last time type is + present only for consistency checking with the proleptic TZ string + described below.) These values serve as indices into the next + field. - o tzh_typecnt ttinfo entries, each defined as follows: + o tzh_typecnt ttinfo entries, each defined as follows: - struct ttinfo { - int32_t tt_utoff; - unsigned char tt_isdst; - unsigned char tt_desigidx; - }; + struct ttinfo { + int32_t tt_utoff; + unsigned char tt_isdst; + unsigned char tt_desigidx; + }; - Each structure is written as a four-byte signed integer value - for tt_utoff, in network byte order, followed by a one-byte - boolean for tt_isdst and a one-byte value for tt_desigidx. In - each structure, tt_utoff gives the number of seconds to be added - to UT, tt_isdst tells whether tm_isdst should be set by - localtime(3) and tt_desigidx serves as an index into the array - of time zone abbreviation bytes that follow the ttinfo entries - in the file; if the designated string is "-00", the ttinfo entry - is a placeholder indicating that local time is unspecified. The - tt_utoff value is never equal to -2**31, to let 32-bit clients - negate it without overflow. Also, in realistic applications - tt_utoff is in the range [-89999, 93599] (i.e., more than -25 - hours and less than 26 hours); this allows easy support by - implementations that already support the POSIX-required range - [-24:59:59, 25:59:59]. + Each structure is written as a four-byte signed integer value for + tt_utoff, in network byte order, followed by a one-byte boolean + for tt_isdst and a one-byte value for tt_desigidx. In each + structure, tt_utoff gives the number of seconds to be added to UT, + tt_isdst tells whether tm_isdst should be set by localtime(3) and + tt_desigidx serves as an index into the array of time zone + abbreviation bytes that follow the ttinfo entries in the file; if + the designated string is "-00", the ttinfo entry is a placeholder + indicating that local time is unspecified. The tt_utoff value is + never equal to -2**31, to let 32-bit clients negate it without + overflow. Also, in realistic applications tt_utoff is in the + range [-89999, 93599] (i.e., more than -25 hours and less than 26 + hours); this allows easy support by implementations that already + support the POSIX-required range [-24:59:59, 25:59:59]. - o tzh_charcnt bytes that represent time zone designations, which - are null-terminated byte strings, each indexed by the - tt_desigidx values mentioned above. The byte strings can - overlap if one is a suffix of the other. The encoding of - these strings is not specified. + o tzh_charcnt bytes that represent time zone designations, which are + null-terminated byte strings, each indexed by the tt_desigidx + values mentioned above. The byte strings can overlap if one is a + suffix of the other. The encoding of these strings is not + specified. - o tzh_leapcnt pairs of four-byte values, written in network byte - order; the first value of each pair gives the nonnegative time - (as returned by time(2)) at which a leap second occurs or at - which the leap second table expires; the second is a signed - integer specifying the correction, which is the total number - of leap seconds to be applied during the time period starting - at the given time. The pairs of values are sorted in strictly - ascending order by time. Each pair denotes one leap second, - either positive or negative, except that if the last pair has - the same correction as the previous one, the last pair denotes - the leap second table's expiration time. Each leap second is - at the end of a UTC calendar month. The first leap second has - a nonnegative occurrence time, and is a positive leap second - if and only if its correction is positive; the correction for - each leap second after the first differs from the previous - leap second by either 1 for a positive leap second, or -1 for - a negative leap second. If the leap second table is empty, - the leap-second correction is zero for all timestamps; - otherwise, for timestamps before the first occurrence time, - the leap-second correction is zero if the first pair's - correction is 1 or -1, and is unspecified otherwise (which can - happen only in files truncated at the start). + o tzh_leapcnt pairs of four-byte values, written in network byte + order; the first value of each pair gives the nonnegative time (as + returned by time(2)) at which a leap second occurs or at which the + leap second table expires; the second is a signed integer + specifying the correction, which is the total number of leap + seconds to be applied during the time period starting at the given + time. The pairs of values are sorted in strictly ascending order + by time. Each pair denotes one leap second, either positive or + negative, except that if the last pair has the same correction as + the previous one, the last pair denotes the leap second table's + expiration time. Each leap second is at the end of a UTC calendar + month. The first leap second has a nonnegative occurrence time, + and is a positive leap second if and only if its correction is + positive; the correction for each leap second after the first + differs from the previous leap second by either 1 for a positive + leap second, or -1 for a negative leap second. If the leap second + table is empty, the leap-second correction is zero for all + timestamps; otherwise, for timestamps before the first occurrence + time, the leap-second correction is zero if the first pair's + correction is 1 or -1, and is unspecified otherwise (which can + happen only in files truncated at the start). - o tzh_ttisstdcnt standard/wall indicators, each stored as a one- - byte boolean; they tell whether the transition times - associated with local time types were specified as standard - time or local (wall clock) time. + o tzh_ttisstdcnt standard/wall indicators, each stored as a one-byte + boolean; they tell whether the transition times associated with + local time types were specified as standard time or local (wall + clock) time. - o tzh_ttisutcnt UT/local indicators, each stored as a one-byte - boolean; they tell whether the transition times associated - with local time types were specified as UT or local time. If - a UT/local indicator is set, the corresponding standard/wall - indicator must also be set. + o tzh_ttisutcnt UT/local indicators, each stored as a one-byte + boolean; they tell whether the transition times associated with + local time types were specified as UT or local time. If a + UT/local indicator is set, the corresponding standard/wall + indicator must also be set. - The standard/wall and UT/local indicators were designed for - transforming a TZif file's transition times into transitions - appropriate for another time zone specified via a - POSIX.1-2017-style TZ string that lacks rules. For example, when - TZ="EET-2EEST" and there is no TZif file "EET-2EEST", the idea was - to adapt the transition times from a TZif file with the well-known - name "posixrules" that is present only for this purpose and is a - copy of the file "Europe/Brussels", a file with a different UT - offset. POSIX does not specify this obsolete transformational - behavior, the default rules are installation-dependent, and no - implementation is known to support this feature for timestamps past - 2037, so users desiring (say) Greek time should instead specify - TZ="Europe/Athens" for better historical coverage, falling back on - TZ="EET-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required - and older timestamps need not be handled accurately. + The standard/wall and UT/local indicators were designed for + transforming a TZif file's transition times into transitions + appropriate for another time zone specified via a proleptic TZ string + that lacks rules. For example, when TZ="EET-2EEST" and there is no + TZif file "EET-2EEST", the idea was to adapt the transition times from + a TZif file with the well-known name "posixrules" that is present only + for this purpose and is a copy of the file "Europe/Brussels", a file + with a different UT offset. POSIX does not specify the details of this + obsolete transformational behavior, the default rules are installation- + dependent, and no implementation is known to support this feature for + timestamps past 2037, so users desiring (say) Greek time should instead + specify TZ="Europe/Athens" for better historical coverage, falling back + on TZ="EET-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required + and older timestamps need not be handled accurately. - The localtime(3) function normally uses the first ttinfo structure - in the file if either tzh_timecnt is zero or the time argument is - less than the first transition time recorded in the file. + The localtime(3) function normally uses the first ttinfo structure in + the file if either tzh_timecnt is zero or the time argument is less + than the first transition time recorded in the file. Version 2 format - For version-2-format timezone files, the above header and data are - followed by a second header and data, identical in format except that - eight bytes are used for each transition time or leap second time. - (Leap second counts remain four bytes.) After the second header and - data comes a newline-enclosed string in the style of the contents of a - POSIX.1-2017 TZ environment variable, for use in handling instants - after the last transition time stored in the file or for all instants - if the file has no transitions. The TZ string is empty (i.e., nothing - between the newlines) if there is no POSIX.1-2017-style representation - for such instants. If nonempty, the TZ string must agree with the - local time type after the last transition time if present in the eight- - byte data; for example, given the string "WET0WEST,M3.5.0/1,M10.5.0" - then if a last transition time is in July, the transition's local time - type must specify a daylight-saving time abbreviated "WEST" that is one - hour east of UT. Also, if there is at least one transition, time type - 0 is associated with the time period from the indefinite past up to but - not including the earliest transition time. + For version-2-format timezone files, the above header and data are + followed by a second header and data, identical in format except that + eight bytes are used for each transition time or leap second time. + (Leap second counts remain four bytes.) After the second header and + data comes a newline-enclosed string in the style of the contents of a + proleptic TZ, for use in handling instants after the last transition + time stored in the file or for all instants if the file has no + transitions. The TZ string is empty (i.e., nothing between the + newlines) if there is no proleptic representation for such instants. + If nonempty, the TZ string must agree with the local time type after + the last transition time if present in the eight-byte data; for + example, given the string "WET0WEST,M3.5.0/1,M10.5.0" then if a last + transition time is in July, the transition's local time type must + specify a daylight-saving time abbreviated "WEST" that is one hour east + of UT. Also, if there is at least one transition, time type 0 is + associated with the time period from the indefinite past up to but not + including the earliest transition time. Version 3 format - For version-3-format timezone files, the TZ string may use two minor - extensions to the POSIX.1-2017 TZ format, as described in newtzset(3). - First, the hours part of its transition times may be signed and range - from -167 through 167 instead of the POSIX-required unsigned values - from 0 through 24. Second, DST is in effect all year if it starts - January 1 at 00:00 and ends December 31 at 24:00 plus the difference + For version-3-format timezone files, a TZ string (see newtzset(3)) may + use the following POSIX.1-2024 extensions to POSIX.1-2017: First, as in + TZ="<-02>2<-01>,M3.5.0/-1,M10.5.0/0", the hours part of its transition + times may be signed and range from -167 through 167 instead of being + limited to unsigned values from 0 through 24. Second, as in + TZ="XXX3EDT4,0/0,J365/23", DST is in effect all year if it starts + January 1 at 00:00 and ends December 31 at 24:00 plus the difference between daylight saving and standard time. Version 4 format - For version-4-format TZif files, the first leap second record can have - a correction that is neither +1 nor -1, to represent truncation of the - TZif file at the start. Also, if two or more leap second transitions - are present and the last entry's correction equals the previous one, - the last entry denotes the expiration of the leap second table instead - of a leap second; timestamps after this expiration are unreliable in - that future releases will likely add leap second entries after the - expiration, and the added leap seconds will change how post-expiration + For version-4-format TZif files, the first leap second record can have + a correction that is neither +1 nor -1, to represent truncation of the + TZif file at the start. Also, if two or more leap second transitions + are present and the last entry's correction equals the previous one, + the last entry denotes the expiration of the leap second table instead + of a leap second; timestamps after this expiration are unreliable in + that future releases will likely add leap second entries after the + expiration, and the added leap seconds will change how post-expiration timestamps are treated. Interoperability considerations Future changes to the format may append more data. - Version 1 files are considered a legacy format and should not be + Version 1 files are considered a legacy format and should not be generated, as they do not support transition times after the year 2038. - Readers that understand only Version 1 must ignore any data that + Readers that understand only Version 1 must ignore any data that extends beyond the calculated end of the version 1 data block. Other than version 1, writers should generate the lowest version number - needed by a file's data. For example, a writer should generate a - version 4 file only if its leap second table either expires or is - truncated at the start. Likewise, a writer not generating a version 4 - file should generate a version 3 file only if TZ string extensions are + needed by a file's data. For example, a writer should generate a + version 4 file only if its leap second table either expires or is + truncated at the start. Likewise, a writer not generating a version 4 + file should generate a version 3 file only if TZ string extensions are necessary to accurately model transition times. - The sequence of time changes defined by the version 1 header and data - block should be a contiguous sub-sequence of the time changes defined - by the version 2+ header and data block, and by the footer. This - guideline helps obsolescent version 1 readers agree with current - readers about timestamps within the contiguous sub-sequence. It also - lets writers not supporting obsolescent readers use a tzh_timecnt of + The sequence of time changes defined by the version 1 header and data + block should be a contiguous sub-sequence of the time changes defined + by the version 2+ header and data block, and by the footer. This + guideline helps obsolescent version 1 readers agree with current + readers about timestamps within the contiguous sub-sequence. It also + lets writers not supporting obsolescent readers use a tzh_timecnt of zero in the version 1 data block to save space. - When a TZif file contains a leap second table expiration time, TZif - readers should either refuse to process post-expiration timestamps, or - process them as if the expiration time did not exist (possibly with an + When a TZif file contains a leap second table expiration time, TZif + readers should either refuse to process post-expiration timestamps, or + process them as if the expiration time did not exist (possibly with an error indication). Time zone designations should consist of at least three (3) and no more - than six (6) ASCII characters from the set of alphanumerics, "-", and - "+". This is for compatibility with POSIX requirements for time zone + than six (6) ASCII characters from the set of alphanumerics, "-", and + "+". This is for compatibility with POSIX requirements for time zone abbreviations. - When reading a version 2 or higher file, readers should ignore the + When reading a version 2 or higher file, readers should ignore the version 1 header and data block except for the purpose of skipping over them. - Readers should calculate the total lengths of the headers and data + Readers should calculate the total lengths of the headers and data blocks and check that they all fit within the actual file size, as part of a validity check for the file. - When a positive leap second occurs, readers should append an extra - second to the local minute containing the second just before the leap - second. If this occurs when the UTC offset is not a multiple of 60 - seconds, the leap second occurs earlier than the last second of the - local minute and the minute's remaining local seconds are numbered + When a positive leap second occurs, readers should append an extra + second to the local minute containing the second just before the leap + second. If this occurs when the UTC offset is not a multiple of 60 + seconds, the leap second occurs earlier than the last second of the + local minute and the minute's remaining local seconds are numbered through 60 instead of the usual 59; the UTC offset is unaffected. Common interoperability issues - This section documents common problems in reading or writing TZif - files. Most of these are problems in generating TZif files for use by + This section documents common problems in reading or writing TZif + files. Most of these are problems in generating TZif files for use by older readers. The goals of this section are: - o to help TZif writers output files that avoid common pitfalls in + o to help TZif writers output files that avoid common pitfalls in older or buggy TZif readers, - o to help TZif readers avoid common pitfalls when reading files + o to help TZif readers avoid common pitfalls when reading files generated by future TZif writers, and o to help any future specification authors see what sort of problems arise when the TZif format is changed. - When new versions of the TZif format have been defined, a design goal - has been that a reader can successfully use a TZif file even if the - file is of a later TZif version than what the reader was designed for. - When complete compatibility was not achieved, an attempt was made to - limit glitches to rarely used timestamps and allow simple partial - workarounds in writers designed to generate new-version data useful - even for older-version readers. This section attempts to document - these compatibility issues and workarounds, as well as to document + When new versions of the TZif format have been defined, a design goal + has been that a reader can successfully use a TZif file even if the + file is of a later TZif version than what the reader was designed for. + When complete compatibility was not achieved, an attempt was made to + limit glitches to rarely used timestamps and allow simple partial + workarounds in writers designed to generate new-version data useful + even for older-version readers. This section attempts to document + these compatibility issues and workarounds, as well as to document other common bugs in readers. Interoperability problems with TZif include the following: - o Some readers examine only version 1 data. As a partial - workaround, a writer can output as much version 1 data as - possible. However, a reader should ignore version 1 data, and - should use version 2+ data even if the reader's native timestamps + o Some readers examine only version 1 data. As a partial + workaround, a writer can output as much version 1 data as + possible. However, a reader should ignore version 1 data, and + should use version 2+ data even if the reader's native timestamps have only 32 bits. - o Some readers designed for version 2 might mishandle timestamps - after a version 3 or higher file's last transition, because they - cannot parse extensions to POSIX.1-2017 in the TZ-like string. As - a partial workaround, a writer can output more transitions than - necessary, so that only far-future timestamps are mishandled by - version 2 readers. + o Some readers designed for version 2 might mishandle timestamps + after a version 3 or higher file's last transition, because they + cannot parse the POSIX.1-2024 extensions to POSIX.1-2017 in the + proleptic TZ string. As a partial workaround, a writer can output + more transitions than necessary, so that only far-future + timestamps are mishandled by version 2 readers. - o Some readers designed for version 2 do not support permanent - daylight saving time with transitions after 24:00 - e.g., a TZ - string "EST5EDT,0/0,J365/25" denoting permanent Eastern Daylight - Time (-04). As a workaround, a writer can substitute standard - time for two time zones east, e.g., "XXX3EDT4,0/0,J365/23" for a - time zone with a never-used standard time (XXX, -03) and negative - daylight saving time (EDT, -04) all year. Alternatively, as a - partial workaround a writer can substitute standard time for the + o Some readers designed for version 2 do not support permanent + daylight saving time with transitions after 24:00 - e.g., a TZ + string "EST5EDT,0/0,J365/25" denoting permanent Eastern Daylight + Time (-04). As a workaround, a writer can substitute standard + time for two time zones east, e.g., "XXX3EDT4,0/0,J365/23" for a + time zone with a never-used standard time (XXX, -03) and negative + daylight saving time (EDT, -04) all year. Alternatively, as a + partial workaround a writer can substitute standard time for the next time zone east - e.g., "AST4" for permanent Atlantic Standard Time (-04). - o Some readers designed for version 2 or 3, and that require strict - conformance to RFC 8536, reject version 4 files whose leap second + o Some readers designed for version 2 or 3, and that require strict + conformance to RFC 8536, reject version 4 files whose leap second tables are truncated at the start or that end in expiration times. o Some readers ignore the footer, and instead predict future - timestamps from the time type of the last transition. As a - partial workaround, a writer can output more transitions than + timestamps from the time type of the last transition. As a + partial workaround, a writer can output more transitions than necessary. + o Some stripped-down readers ignore everything but the footer, and + use its proleptic TZ string to calculate all timestamps. Although + this approach often works for current and future timestamps, it + obviously has problems with past timestamps, and even for current + timestamps it can fail for settings like TZ="Africa/Casablanca". + This corresponds to a TZif file containing explicit transitions + through the year 2087, followed by a footer containing the TZ + string "<+01>-1", which should be used only for timestamps after + the last explicit transition. + o Some readers do not use time type 0 for timestamps before the first transition, in that they infer a time type using a heuristic that does not always select time type 0. As a partial workaround, diff --git a/tzfile.h b/tzfile.h index 3155010ed17f..b15414665443 100644 --- a/tzfile.h +++ b/tzfile.h @@ -76,14 +76,16 @@ struct tzhead { ** If tzh_version is '2' or greater, the above is followed by a second instance ** of tzhead and a second instance of the data in which each coded transition ** time uses 8 rather than 4 chars, -** then a POSIX-TZ-environment-variable-style string for use in handling +** then a POSIX.1-2017 proleptic TZ string for use in handling ** instants after the last transition time stored in the file ** (with nothing between the newlines if there is no POSIX.1-2017 ** representation for such instants). ** -** If tz_version is '3' or greater, the above is extended as follows. +** If tz_version is '3' or greater, the TZ string can be any POSIX.1-2024 +** proleptic TZ string, which means the above is extended as follows. ** First, the TZ string's hour offset may range from -167 -** through 167 as compared to the POSIX-required 0 through 24. +** through 167 as compared to the range 0 through 24 required +** by POSIX.1-2017 and earlier. ** Second, its DST start time may be January 1 at 00:00 and its stop ** time December 31 at 24:00 plus the difference between DST and ** standard time, indicating DST all year. diff --git a/tzselect.ksh b/tzselect.ksh index 38941bbc55e7..ca3d82c6aab6 100644 --- a/tzselect.ksh +++ b/tzselect.ksh @@ -20,12 +20,6 @@ REPORT_BUGS_TO=tz@iana.org # Korn Shell # MirBSD Korn Shell # -# For portability to Solaris 10 /bin/sh (supported by Oracle through -# January 2027) this script avoids some POSIX features and common -# extensions, such as $(...), $((...)), ! CMD, unquoted ^, ${#ID}, -# ${ID##PAT}, ${ID%%PAT}, and $10. Although some of these constructs -# work sometimes, it's simpler to avoid them entirely. -# # This script also uses several features of POSIX awk. # If your host lacks awk, or has an old awk that does not conform to POSIX, # you can use any of the following free programs instead: @@ -45,7 +39,6 @@ set -f # Specify default values for environment variables if they are unset. : ${AWK=awk} -: ${PWD=`pwd`} : ${TZDIR=$PWD} # Output one argument as-is to standard output, with trailing newline. @@ -54,13 +47,6 @@ say() { printf '%s\n' "$1" } -# Check for awk POSIX compliance. -($AWK -v x=y 'BEGIN { exit 123 }') <>/dev/null >&0 2>&0 -[ $? = 123 ] || { - say >&2 "$0: Sorry, your '$AWK' program is not POSIX compatible." - exit 1 -} - coord= location_limit=10 zonetabtype=zone1970 @@ -117,8 +103,7 @@ then else doselect() { # Field width of the prompt numbers. - print_nargs_length="BEGIN {print length(\"$#\");}" - select_width=`$AWK "$print_nargs_length"` + select_width=${##} select_i= @@ -129,14 +114,14 @@ else select_i=0 for select_word do - select_i=`$AWK "BEGIN { print $select_i + 1 }"` + select_i=$(($select_i + 1)) printf >&2 "%${select_width}d) %s\\n" $select_i "$select_word" done;; *[!0-9]*) echo >&2 'Please enter a number in range.';; *) if test 1 -le $select_i && test $select_i -le $#; then - shift `$AWK "BEGIN { print $select_i - 1 }"` + shift $(($select_i - 1)) select_result=$1 break fi @@ -170,7 +155,7 @@ do esac done -shift `$AWK "BEGIN { print $OPTIND - 1 }"` +shift $(($OPTIND - 1)) case $# in 0) ;; *) say >&2 "$0: $1: unknown argument"; exit 1 @@ -178,11 +163,13 @@ esac # translit=true to try transliteration. # This is false if U+12345 CUNEIFORM SIGN URU TIMES KI has length 1 -# which means awk (and presumably the shell) do not need transliteration. -if $AWK 'BEGIN { u12345 = "\360\222\215\205"; exit length(u12345) == 1 }'; then - translit=true -else - translit=false +# which means the shell and (presumably) awk do not need transliteration. +# It is true if the byte string has some other length in characters, or +# if this is a POSIX.1-2017 or earlier shell that does not support $'...'. +CUNEIFORM_SIGN_URU_TIMES_KI=$'\360\222\215\205' +if test ${#CUNEIFORM_SIGN_URU_TIMES_KI} = 1 +then translit=false +else translit=true fi # Read into shell variable $1 the contents of file $2. @@ -192,10 +179,10 @@ fi # if that does not work, fall back on 'cat'. read_file() { { $translit && { - eval "$1=\`(iconv -f UTF-8 -t //TRANSLIT) 2>/dev/null <\"\$2\"\`" || - eval "$1=\`(iconv -f UTF-8) 2>/dev/null <\"\$2\"\`" + eval "$1=\$( (iconv -f UTF-8 -t //TRANSLIT) 2>/dev/null <\"\$2\")" || + eval "$1=\$( (iconv -f UTF-8) 2>/dev/null <\"\$2\")" }; } || - eval "$1=\`cat <\"\$2\"\`" || { + eval "$1=\$(cat <\"\$2\")" || { say >&2 "$0: time zone files are not set up correctly" exit 1 } @@ -403,7 +390,7 @@ while echo >&2 \ 'Please select a continent, ocean, "coord", "TZ", "time", or "now".' - quoted_continents=` + quoted_continents=$( $AWK ' function handle_entry(entry) { entry = substr(entry, 1, index(entry, "/") - 1) @@ -433,12 +420,12 @@ while sort -u | tr '\n' ' ' echo '' - ` + ) eval ' doselect '"$quoted_continents"' \ "coord - I want to use geographical coordinates." \ - "TZ - I want to specify the timezone using a POSIX.1-2017 TZ string." \ + "TZ - I want to specify the timezone using a proleptic TZ string." \ "time - I know local time already." \ "now - Like \"time\", but configure only for timestamps from now on." continent=$select_result @@ -462,16 +449,17 @@ while case $continent in TZ) - # Ask the user for a POSIX.1-2017 TZ string. Check that it conforms. + # Ask the user for a proleptic TZ string. Check that it conforms. check_POSIX_TZ_string=' BEGIN { tz = substr(ARGV[1], 2) ARGV[1] = "" tzname = ("(<[[:alnum:]+-][[:alnum:]+-][[:alnum:]+-]+>" \ "|[[:alpha:]][[:alpha:]][[:alpha:]]+)") - time = ("(2[0-4]|[0-1]?[0-9])" \ - "(:[0-5][0-9](:[0-5][0-9])?)?") - offset = "[-+]?" time + sign = "[-+]?" + hhmm = "(:[0-5][0-9](:[0-5][0-9])?)?" + offset = sign "(2[0-4]|[0-1]?[0-9])" hhmm + time = sign "(16[0-7]|(1[0-5]|[0-9]?)[0-9])" hhmm mdate = "M([1-9]|1[0-2])\\.[1-5]\\.[0-6]" jdate = ("((J[1-9]|[0-9]|J?[1-9][0-9]" \ "|J?[1-2][0-9][0-9])|J?3[0-5][0-9]|J?36[0-5])") @@ -492,7 +480,7 @@ while read tz $AWK "$check_POSIX_TZ_string" ="$tz" do - say >&2 "'$tz' is not a conforming POSIX.1-2017 timezone string." + say >&2 "'$tz' is not a conforming POSIX proleptic TZ string." done TZ_for_date=$tz;; *) @@ -507,14 +495,14 @@ while '74 degrees 3 minutes west.' read coord esac - distance_table=` + distance_table=$( $AWK \ "$output_distances_or_times" \ ="$coord" ="$TZ_COUNTRY_TABLE" ="$TZ_ZONE_TABLE" | sort -n | $AWK "{print} NR == $location_limit { exit }" - ` - regions=` + ) + regions=$( $AWK ' BEGIN { distance_table = substr(ARGV[1], 2) @@ -526,13 +514,13 @@ while } } ' ="$distance_table" - ` + ) echo >&2 'Please select one of the following timezones,' echo >&2 'listed roughly in increasing order' \ "of distance from $coord". doselect $regions region=$select_result - tz=` + tz=$( $AWK ' BEGIN { distance_table = substr(ARGV[1], 2) @@ -546,22 +534,22 @@ while } } ' ="$distance_table" ="$region" - `;; + );; *) case $continent in now|time) minute_format='%a %b %d %H:%M' - old_minute=`TZ=UTC0 date +"$minute_format"` + old_minute=$(TZ=UTC0 date +"$minute_format") for i in 1 2 3 do - time_table_command=` + time_table_command=$( $AWK \ -v output_times=1 \ "$output_distances_or_times" \ = = ="$TZ_ZONE_TABLE" - ` - time_table=`eval "$time_table_command"` - new_minute=`TZ=UTC0 date +"$minute_format"` + ) + time_table=$(eval "$time_table_command") + new_minute=$(TZ=UTC0 date +"$minute_format") case $old_minute in "$new_minute") break esac @@ -569,11 +557,11 @@ while done echo >&2 "The system says Universal Time is $new_minute." echo >&2 "Assuming that's correct, what is the local time?" - sorted_table=`say "$time_table" | sort -k2n -k2,5 -k1n` || { + sorted_table=$(say "$time_table" | sort -k2n -k2,5 -k1n) || { say >&2 "$0: cannot sort time table" exit 1 } - eval doselect ` + eval doselect $( $AWK ' BEGIN { sorted_table = substr(ARGV[1], 2) @@ -590,10 +578,10 @@ while } } ' ="$sorted_table" - ` + ) time=$select_result continent_re='^' - zone_table=` + zone_table=$( $AWK ' BEGIN { time = substr(ARGV[1], 2) @@ -609,13 +597,13 @@ while } } ' ="$time" ="$time_table" - ` - countries=` + ) + countries=$( $AWK \ "$output_country_list" \ ="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" | sort -f - ` + ) ;; *) continent_re="^$continent/" @@ -623,16 +611,16 @@ while esac # Get list of names of countries in the continent or ocean. - countries=` + countries=$( $AWK \ "$output_country_list" \ ="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" | sort -f - ` + ) # If all zone table entries have comments, and there are # at most 22 entries, asked based on those comments. # This fits the prompt onto old-fashioned 24-line screens. - regions=` + regions=$( $AWK ' BEGIN { TZ_ZONE_TABLE = substr(ARGV[1], 2) @@ -653,7 +641,7 @@ while print comment[i] } ' ="$zone_table" - ` + ) # If there's more than one country, ask the user which one. case $countries in @@ -669,7 +657,7 @@ while # Get list of timezones in the country. - regions=` + regions=$( $AWK ' BEGIN { country = substr(ARGV[1], 2) @@ -696,7 +684,7 @@ while } } ' ="$country" ="$TZ_COUNTRY_TABLE" ="$zone_table" - ` + ) # If there's more than one region, ask the user which one. case $regions in @@ -707,7 +695,7 @@ while esac # Determine tz from country and region. - tz=` + tz=$( $AWK ' BEGIN { country = substr(ARGV[1], 2) @@ -735,7 +723,7 @@ while } } ' ="$country" ="$region" ="$TZ_COUNTRY_TABLE" ="$zone_table" - ` + ) esac # Make sure the corresponding zoneinfo file exists. @@ -754,14 +742,11 @@ while extra_info= for i in 1 2 3 4 5 6 7 8 do - TZdate=`LANG=C TZ="$TZ_for_date" date` - UTdate=`LANG=C TZ=UTC0 date` - if $AWK ' - function getsecs(d) { - return match(d, /.*:[0-5][0-9]/) ? substr(d, RLENGTH - 1, 2) : "" - } - BEGIN { exit getsecs(ARGV[1]) != getsecs(ARGV[2]) } - ' ="$TZdate" ="$UTdate" + TZdate=$(LANG=C TZ="$TZ_for_date" date) + UTdate=$(LANG=C TZ=UTC0 date) + TZsecsetc=${TZdate##*[0-5][0-9]:} + UTsecsetc=${UTdate##*[0-5][0-9]:} + if test "${TZsecsetc%%[!0-9]*}" = "${UTsecsetc%%[!0-9]*}" then extra_info=" Selected time is now: $TZdate. @@ -801,7 +786,7 @@ done case $SHELL in *csh) file=.login line="setenv TZ '$tz'";; -*) file=.profile line="TZ='$tz'; export TZ" +*) file=.profile line="export TZ='$tz'" esac test -t 1 && say >&2 " diff --git a/version b/version index 04fe6744432f..699e50d4d38e 100644 --- a/version +++ b/version @@ -1 +1 @@ -2024a +2024b diff --git a/workman.sh b/workman.sh index 6e2da3a80c8d..29f317cb40c4 100644 --- a/workman.sh +++ b/workman.sh @@ -7,8 +7,7 @@ if (type nroff && type perl) >/dev/null 2>&1; then # Tell groff not to emit SGR escape sequences (ANSI color escapes). - GROFF_NO_SGR=1 - export GROFF_NO_SGR + export GROFF_NO_SGR=1 echo ".am TH .hy 0 diff --git a/zdump.8 b/zdump.8 index c3f0bba60ba8..38dd861424a6 100644 --- a/zdump.8 +++ b/zdump.8 @@ -152,7 +152,8 @@ tabbed columns line up.) .nf .sp .if \n(.g .ft CR -.in +2 +.if t .in +.5i +.if n .in +2 .nr w \w'1896-01-13 'u+\n(.i .ta \w'1896-01-13\0\0'u +\w'12:01:26\0\0'u +\w'-103126\0\0'u +\w'HWT\0\0'u TZ="Pacific/Honolulu" diff --git a/zdump.c b/zdump.c index 7d99cc74bd30..e817873337c0 100644 --- a/zdump.c +++ b/zdump.c @@ -89,7 +89,7 @@ static bool warned; static bool errout; static char const *abbr(struct tm const *); -ATTRIBUTE_REPRODUCIBLE static intmax_t delta(struct tm *, struct tm *); +static intmax_t delta(struct tm *, struct tm *); static void dumptime(struct tm const *); static time_t hunt(timezone_t, time_t, time_t, bool); static void show(timezone_t, char *, time_t, bool); @@ -97,7 +97,7 @@ static void showextrema(timezone_t, char *, time_t, struct tm *, time_t); static void showtrans(char const *, struct tm const *, time_t, char const *, char const *); static const char *tformat(void); -ATTRIBUTE_REPRODUCIBLE static time_t yeartot(intmax_t); +ATTRIBUTE_PURE_114833 static time_t yeartot(intmax_t); /* Is C an ASCII digit? */ static bool @@ -134,7 +134,7 @@ size_overflow(void) /* Return A + B, exiting if the result would overflow either ptrdiff_t or size_t. A and B are both nonnegative. */ -ATTRIBUTE_REPRODUCIBLE static ptrdiff_t +ATTRIBUTE_PURE_114833 static ptrdiff_t sumsize(ptrdiff_t a, ptrdiff_t b) { #ifdef ckd_add @@ -162,7 +162,7 @@ xstrsize(char const *str) /* Return a pointer to a newly allocated buffer of size SIZE, exiting on failure. SIZE should be positive. */ -ATTRIBUTE_MALLOC static void * +static void * xmalloc(ptrdiff_t size) { void *p = malloc(size); @@ -932,7 +932,7 @@ showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi) # include /* A substitute for snprintf that is good enough for zdump. */ -ATTRIBUTE_FORMAT((printf, 3, 4)) static int +static int my_snprintf(char *s, size_t size, char const *format, ...) { int n; diff --git a/zic.8 b/zic.8 index 0ad373a2dd17..00e2536bb8dd 100644 --- a/zic.8 +++ b/zic.8 @@ -171,7 +171,7 @@ boundaries, particularly if causes a TZif file to contain explicit entries for .RI pre- hi transitions rather than concisely representing them -with an extended POSIX.1-2017 TZ string. +with a proleptic TZ string. Also see the .B "\*-b slim" option for another way to shrink output size. @@ -181,10 +181,10 @@ Generate redundant trailing explicit transitions for timestamps that occur less than .I hi seconds since the Epoch, even though the transitions could be -more concisely represented via the extended POSIX.1-2017 TZ string. +more concisely represented via the proleptic TZ string. This option does not affect the represented timestamps. Although it accommodates nonstandard TZif readers -that ignore the extended POSIX.1-2017 TZ string, +that ignore the proleptic TZ string, it increases the size of the altered output files. .TP .BI "\*-t " file @@ -245,10 +245,10 @@ for .PP The output file does not contain all the information about the long-term future of a timezone, because the future cannot be summarized as -an extended POSIX.1-2017 TZ string. For example, as of 2023 this problem +a proleptic TZ string. For example, as of 2023 this problem occurs for Morocco's daylight-saving rules, as these rules are based on predictions for when Ramadan will be observed, something that -an extended POSIX.1-2017 TZ string cannot represent. +a proleptic TZ string cannot represent. .PP The output contains data that may not be handled properly by client code designed for older @@ -558,12 +558,14 @@ begin the field with a minus sign if time must be subtracted from UT. .TP .B RULES The name of the rules that apply in the timezone or, -alternatively, a field in the same format as a rule-line SAVE column, +alternatively, a field in the same format as a rule-line +.B SAVE +field, giving the amount of time to be added to local standard time and whether the resulting time is standard or daylight saving. -If this field is +Standard time applies if this field is .B \*- -then standard time always applies. +or for timestamps occurring before any rule takes effect. When an amount of time is given, only the sum of standard time and this amount matters. .TP @@ -571,9 +573,13 @@ this amount matters. The format for time zone abbreviations. The pair of characters .B %s -is used to show where the -.q "variable part" -of the time zone abbreviation goes. +shows where to put the time zone abbreviation's variable part, +which is taken from the +.B LETTER/S +field of the corresponding rule; +any timestamps that precede the earliest rule use the +.B LETTER/S +of the earliest standard-time rule (which in this case must exist). Alternatively, a format can use the pair of characters .B %z to stand for the UT offset in the form @@ -663,7 +669,7 @@ Rule US 1967 1973 - Apr lastSun 2:00 1:00 D .ta \w'# Zone\0\0'u +\w'America/Menominee\0\0'u +\w'STDOFF\0\0'u +\w'RULES\0\0'u +\w'FORMAT\0\0'u # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Menominee \*-5:00 \*- EST 1973 Apr 29 2:00 - \*-6:00 US C%sT + \*-6:00 US C%sT .sp .in .fi @@ -767,16 +773,16 @@ or if the leap second time given by the other fields should be interpreted as local (wall clock) time. .PP -Rolling leap seconds were implemented back when it was not -clear whether common practice was rolling or stationary, -with concerns that one would see +Rolling leap seconds would let one see Times Square ball drops where there'd be a .q "3... 2... 1... leap... Happy New Year" countdown, placing the leap second at midnight New York time rather than midnight UTC. -However, this countdown style does not seem to have caught on, -which means rolling leap seconds are not used in practice; -also, they are not supported if the +Although stationary leap seconds are the common practice, +rolling leap seconds can be useful in specialized applications +like SMPTE timecodes that may prefer to put leap second +discontinuities at the end of a local broadcast day. +However, rolling leap seconds are not supported if the .B \*-r option is used. .PP diff --git a/zic.8.txt b/zic.8.txt index acef001bbafd..c72f8512548d 100644 --- a/zic.8.txt +++ b/zic.8.txt @@ -77,16 +77,16 @@ OPTIONS due to the need to represent the timestamp range boundaries, particularly if hi causes a TZif file to contain explicit entries for pre-hi transitions rather than concisely - representing them with an extended POSIX.1-2017 TZ string. Also - see the -b slim option for another way to shrink output size. + representing them with a proleptic TZ string. Also see the -b + slim option for another way to shrink output size. - -R @hi Generate redundant trailing explicit transitions for timestamps + -R @hi Generate redundant trailing explicit transitions for timestamps that occur less than hi seconds since the Epoch, even though the - transitions could be more concisely represented via the extended - POSIX.1-2017 TZ string. This option does not affect the + transitions could be more concisely represented via the + proleptic TZ string. This option does not affect the represented timestamps. Although it accommodates nonstandard - TZif readers that ignore the extended POSIX.1-2017 TZ string, it - increases the size of the altered output files. + TZif readers that ignore the proleptic TZ string, it increases + the size of the altered output files. -t file When creating local time information, put the configuration link @@ -97,34 +97,33 @@ OPTIONS The input specifies a link to a link, something not supported by some older parsers, including zic itself through release 2022e. - A year that appears in a data file is outside the range of + A year that appears in a data file is outside the range of representable years. A time of 24:00 or more appears in the input. Pre-1998 versions - of zic prohibit 24:00, and pre-2007 versions prohibit times + of zic prohibit 24:00, and pre-2007 versions prohibit times greater than 24:00. - A rule goes past the start or end of the month. Pre-2004 + A rule goes past the start or end of the month. Pre-2004 versions of zic prohibit this. A time zone abbreviation uses a %z format. Pre-2015 versions of zic do not support this. - A timestamp contains fractional seconds. Pre-2018 versions of + A timestamp contains fractional seconds. Pre-2018 versions of zic do not support this. The input contains abbreviations that are mishandled by pre-2018 - versions of zic due to a longstanding coding bug. These - abbreviations include "L" for "Link", "mi" for "min", "Sa" for + versions of zic due to a longstanding coding bug. These + abbreviations include "L" for "Link", "mi" for "min", "Sa" for "Sat", and "Su" for "Sun". - The output file does not contain all the information about the - long-term future of a timezone, because the future cannot be - summarized as an extended POSIX.1-2017 TZ string. For example, - as of 2023 this problem occurs for Morocco's daylight-saving - rules, as these rules are based on predictions for when Ramadan - will be observed, something that an extended POSIX.1-2017 TZ - string cannot represent. + The output file does not contain all the information about the + long-term future of a timezone, because the future cannot be + summarized as a proleptic TZ string. For example, as of 2023 + this problem occurs for Morocco's daylight-saving rules, as + these rules are based on predictions for when Ramadan will be + observed, something that a proleptic TZ string cannot represent. The output contains data that may not be handled properly by client code designed for older zic output formats. These @@ -309,24 +308,28 @@ FILES RULES The name of the rules that apply in the timezone or, alternatively, a field in the same format as a rule-line SAVE - column, giving the amount of time to be added to local standard + field, giving the amount of time to be added to local standard time and whether the resulting time is standard or daylight - saving. If this field is - then standard time always applies. - When an amount of time is given, only the sum of standard time - and this amount matters. + saving. Standard time applies if this field is - or for + timestamps occurring before any rule takes effect. When an + amount of time is given, only the sum of standard time and this + amount matters. - FORMAT The format for time zone abbreviations. The pair of characters - %s is used to show where the "variable part" of the time zone - abbreviation goes. Alternatively, a format can use the pair of - characters %z to stand for the UT offset in the form +-hh, - +-hhmm, or +-hhmmss, using the shortest form that does not lose - information, where hh, mm, and ss are the hours, minutes, and - seconds east (+) or west (-) of UT. Alternatively, a slash (/) - separates standard and daylight abbreviations. To conform to - POSIX, a time zone abbreviation should contain only alphanumeric - ASCII characters, "+" and "-". By convention, the time zone - abbreviation "-00" is a placeholder that means local time is - unspecified. + FORMAT The format for time zone abbreviations. The pair of characters + %s shows where to put the time zone abbreviation's variable + part, which is taken from the LETTER/S field of the + corresponding rule; any timestamps that precede the earliest + rule use the LETTER/S of the earliest standard-time rule (which + in this case must exist). Alternatively, a format can use the + pair of characters %z to stand for the UT offset in the form + +-hh, +-hhmm, or +-hhmmss, using the shortest form that does not + lose information, where hh, mm, and ss are the hours, minutes, + and seconds east (+) or west (-) of UT. Alternatively, a slash + (/) separates standard and daylight abbreviations. To conform + to POSIX, a time zone abbreviation should contain only + alphanumeric ASCII characters, "+" and "-". By convention, the + time zone abbreviation "-00" is a placeholder that means local + time is unspecified. UNTIL The time at which the UT offset or the rule(s) change for a location. It takes the form of one to four fields YEAR [MONTH @@ -369,7 +372,7 @@ FILES Rule US 1967 1973 - Apr lastSun 2:00 1:00 D # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Menominee -5:00 - EST 1973 Apr 29 2:00 - -6:00 US C%sT + -6:00 US C%sT Here, an incorrect reading would be there were two clock changes on 1973-04-29, the first from 02:00 EST (-05) to 01:00 CST (-06), and the @@ -421,14 +424,14 @@ FILES second time given by the other fields should be interpreted as local (wall clock) time. - Rolling leap seconds were implemented back when it was not clear - whether common practice was rolling or stationary, with concerns that - one would see Times Square ball drops where there'd be a "3... 2... - 1... leap... Happy New Year" countdown, placing the leap second at - midnight New York time rather than midnight UTC. However, this - countdown style does not seem to have caught on, which means rolling - leap seconds are not used in practice; also, they are not supported if - the -r option is used. + Rolling leap seconds would let one see Times Square ball drops where + there'd be a "3... 2... 1... leap... Happy New Year" countdown, placing + the leap second at midnight New York time rather than midnight UTC. + Although stationary leap seconds are the common practice, rolling leap + seconds can be useful in specialized applications like SMPTE timecodes + that may prefer to put leap second discontinuities at the end of a + local broadcast day. However, rolling leap seconds are not supported + if the -r option is used. The expiration line, if present, has the form: @@ -442,7 +445,7 @@ FILES in UTC for the leap second table. EXTENDED EXAMPLE - Here is an extended example of zic input, intended to illustrate many + Here is an extended example of zic input, intended to illustrate many of its features. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -463,29 +466,29 @@ EXTENDED EXAMPLE Link Europe/Zurich Europe/Vaduz - In this example, the EU rules are for the European Union and for its - predecessor organization, the European Communities. The timezone is - named Europe/Zurich and it has the alias Europe/Vaduz. This example - says that Zurich was 34 minutes and 8 seconds east of UT until - 1853-07-16 at 00:00, when the legal offset was changed to 7 degrees 26 - minutes 22.50 seconds, which works out to 0:29:45.50; zic treats this - by rounding it to 0:29:46. After 1894-06-01 at 00:00 the UT offset - became one hour and Swiss daylight saving rules (defined with lines - beginning with "Rule Swiss") apply. From 1981 to the present, EU - daylight saving rules have applied, and the UTC offset has remained at + In this example, the EU rules are for the European Union and for its + predecessor organization, the European Communities. The timezone is + named Europe/Zurich and it has the alias Europe/Vaduz. This example + says that Zurich was 34 minutes and 8 seconds east of UT until + 1853-07-16 at 00:00, when the legal offset was changed to 7 degrees 26 + minutes 22.50 seconds, which works out to 0:29:45.50; zic treats this + by rounding it to 0:29:46. After 1894-06-01 at 00:00 the UT offset + became one hour and Swiss daylight saving rules (defined with lines + beginning with "Rule Swiss") apply. From 1981 to the present, EU + daylight saving rules have applied, and the UTC offset has remained at one hour. In 1941 and 1942, daylight saving time applied from the first Monday in - May at 01:00 to the first Monday in October at 02:00. The pre-1981 EU - daylight-saving rules have no effect here, but are included for + May at 01:00 to the first Monday in October at 02:00. The pre-1981 EU + daylight-saving rules have no effect here, but are included for completeness. Since 1981, daylight saving has begun on the last Sunday - in March at 01:00 UTC. Until 1995 it ended the last Sunday in - September at 01:00 UTC, but this changed to the last Sunday in October + in March at 01:00 UTC. Until 1995 it ended the last Sunday in + September at 01:00 UTC, but this changed to the last Sunday in October starting in 1996. - For purposes of display, "LMT" and "BMT" were initially used, - respectively. Since Swiss rules and later EU rules were applied, the - time zone abbreviation has been CET for standard time and CEST for + For purposes of display, "LMT" and "BMT" were initially used, + respectively. Since Swiss rules and later EU rules were applied, the + time zone abbreviation has been CET for standard time and CEST for daylight saving time. FILES @@ -496,15 +499,15 @@ FILES Default timezone information directory. NOTES - For areas with more than two types of local time, you may need to use - local standard time in the AT field of the earliest transition time's - rule to ensure that the earliest transition time recorded in the + For areas with more than two types of local time, you may need to use + local standard time in the AT field of the earliest transition time's + rule to ensure that the earliest transition time recorded in the compiled file is correct. - If, for a particular timezone, a clock advance caused by the start of - daylight saving coincides with and is equal to a clock retreat caused - by a change in UT offset, zic produces a single transition to daylight - saving at the new UT offset without any change in local (wall clock) + If, for a particular timezone, a clock advance caused by the start of + daylight saving coincides with and is equal to a clock retreat caused + by a change in UT offset, zic produces a single transition to daylight + saving at the new UT offset without any change in local (wall clock) time. To get separate transitions use multiple zone continuation lines specifying transition instants using universal time. diff --git a/zic.c b/zic.c index 00f00e307a30..cf8e79dff46d 100644 --- a/zic.c +++ b/zic.c @@ -470,7 +470,7 @@ size_overflow(void) memory_exhausted(_("size overflow")); } -ATTRIBUTE_REPRODUCIBLE static ptrdiff_t +ATTRIBUTE_PURE_114833 static ptrdiff_t size_sum(size_t a, size_t b) { #ifdef ckd_add @@ -484,7 +484,7 @@ size_sum(size_t a, size_t b) size_overflow(); } -ATTRIBUTE_REPRODUCIBLE static ptrdiff_t +ATTRIBUTE_PURE_114833 static ptrdiff_t size_product(ptrdiff_t nitems, ptrdiff_t itemsize) { #ifdef ckd_mul @@ -499,7 +499,7 @@ size_product(ptrdiff_t nitems, ptrdiff_t itemsize) size_overflow(); } -ATTRIBUTE_REPRODUCIBLE static ptrdiff_t +ATTRIBUTE_PURE_114833 static ptrdiff_t align_to(ptrdiff_t size, ptrdiff_t alignment) { ptrdiff_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits); @@ -523,7 +523,7 @@ memcheck(void *ptr) return ptr; } -ATTRIBUTE_MALLOC static void * +static void * emalloc(size_t size) { return memcheck(malloc(size)); @@ -535,7 +535,7 @@ erealloc(void *ptr, size_t size) return memcheck(realloc(ptr, size)); } -ATTRIBUTE_MALLOC static char * +static char * estrdup(char const *str) { return memcheck(strdup(str)); @@ -1435,7 +1435,7 @@ relname(char const *target, char const *linkname) /* Return true if A and B must have the same parent dir if A and B exist. Return false if this is not necessarily true (though it might be true). Keep it simple, and do not inspect the file system. */ -static bool +ATTRIBUTE_PURE_114833 static bool same_parent_dirs(char const *a, char const *b) { for (; *a == *b; a++, b++) @@ -2982,10 +2982,10 @@ rule_cmp(struct rule const *a, struct rule const *b) return a->r_dayofmonth - b->r_dayofmonth; } -/* Store into RESULT a POSIX.1-2017 TZ string that represent the future +/* Store into RESULT a proleptic TZ string that represent the future predictions for the zone ZPFIRST with ZONECOUNT entries. Return a compatibility indicator (a TZDB release year) if successful, a - negative integer if no such TZ string exissts. */ + negative integer if no such TZ string exists. */ static int stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) { @@ -3177,8 +3177,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) if (noise) { if (!*envvar) warning("%s %s", - _("no POSIX.1-2017 environment variable" - " for zone"), + _("no proleptic TZ string for zone"), zpfirst->z_name); else if (compat != 0) { /* Circa-COMPAT clients, and earlier clients, might @@ -3442,7 +3441,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) if (do_extend) { /* ** If we're extending the explicitly listed observations for - ** 400 years because we can't fill the POSIX.1-2017 TZ field, + ** 400 years because we can't fill the proleptic TZ field, ** check whether we actually ended up explicitly listing ** observations through that period. If there aren't any ** near the end of the 400-year period, add a redundant @@ -3627,7 +3626,7 @@ lowerit(char a) } /* case-insensitive equality */ -ATTRIBUTE_REPRODUCIBLE static bool +ATTRIBUTE_PURE_114833 static bool ciequal(register const char *ap, register const char *bp) { while (lowerit(*ap) == lowerit(*bp++)) @@ -3636,7 +3635,7 @@ ciequal(register const char *ap, register const char *bp) return false; } -ATTRIBUTE_REPRODUCIBLE static bool +ATTRIBUTE_PURE_114833 static bool itsabbr(register const char *abbr, register const char *word) { if (lowerit(*abbr) != lowerit(*word)) @@ -3652,7 +3651,7 @@ itsabbr(register const char *abbr, register const char *word) /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */ -ATTRIBUTE_REPRODUCIBLE static bool +ATTRIBUTE_PURE_114833 static bool ciprefix(char const *abbr, char const *word) { do @@ -3762,7 +3761,7 @@ time_overflow(void) exit(EXIT_FAILURE); } -ATTRIBUTE_REPRODUCIBLE static zic_t +ATTRIBUTE_PURE_114833 static zic_t oadd(zic_t t1, zic_t t2) { #ifdef ckd_add @@ -3776,7 +3775,7 @@ oadd(zic_t t1, zic_t t2) time_overflow(); } -ATTRIBUTE_REPRODUCIBLE static zic_t +ATTRIBUTE_PURE_114833 static zic_t tadd(zic_t t1, zic_t t2) { #ifdef ckd_add