diff --git a/contrib/tzcode/CONTRIBUTING b/contrib/tzcode/CONTRIBUTING --- a/contrib/tzcode/CONTRIBUTING +++ b/contrib/tzcode/CONTRIBUTING @@ -23,10 +23,10 @@ "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 @@ * 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/contrib/tzcode/Makefile b/contrib/tzcode/Makefile --- a/contrib/tzcode/Makefile +++ b/contrib/tzcode/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 @@ 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 @@ # 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 @@ # 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 @@ # 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 @@ # -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 @@ # -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 @@ # # * 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 @@ -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 @@ # 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 @@ # # -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 @@ # # -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 @@ # 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 @@ # 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 @@ # 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 @@ # 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 @@ 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 @@ 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 @@ '$(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 @@ # 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 @@ # 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 @@ # 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 @@ $(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 @@ $(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 @@ } 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 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 @@ 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 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 @@ 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 @@ 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 @@ 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-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 @@ 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 @@ # 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_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 @@ 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 @@ : 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 @@ 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 @@ 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 @@ 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 @@ $(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 @@ .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/contrib/tzcode/NEWS b/contrib/tzcode/NEWS --- a/contrib/tzcode/NEWS +++ b/contrib/tzcode/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 @@ * 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 @@ 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/contrib/tzcode/asctime.c b/contrib/tzcode/asctime.c --- a/contrib/tzcode/asctime.c +++ b/contrib/tzcode/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 @@ -27,8 +27,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"; /* @@ -62,6 +62,18 @@ 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) { @@ -118,6 +130,7 @@ return asctime_r(timeptr, buf_asctime); } +asctime_static char * ctime_r(const time_t *timep, char *buf) { diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c --- a/contrib/tzcode/localtime.c +++ b/contrib/tzcode/localtime.c @@ -125,7 +125,7 @@ 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 @@ -149,11 +149,6 @@ 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 { @@ -217,8 +212,9 @@ ** 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 @@ -773,58 +769,6 @@ 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; } @@ -870,7 +814,7 @@ ** 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; @@ -891,7 +835,7 @@ ** 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; @@ -1143,7 +1087,7 @@ } /* -** 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. */ @@ -1378,7 +1322,7 @@ /* ** 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) { @@ -1407,7 +1351,6 @@ sp->timecnt = 0; init_ttinfo(&sp->ttis[0], -stdoffset, false, 0); } - sp->defaulttype = 0; sp->charcnt = charcnt; cp = sp->chars; memcpy(cp, stdname, stdlen); @@ -1474,7 +1417,6 @@ 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); @@ -1579,8 +1521,8 @@ } /* -** 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 @@ -1598,8 +1540,7 @@ ** ** 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. @@ -1667,7 +1608,7 @@ 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; @@ -2482,7 +2423,7 @@ } #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) @@ -2500,7 +2441,7 @@ # 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/contrib/tzcode/newctime.3 b/contrib/tzcode/newctime.3 --- a/contrib/tzcode/newctime.3 +++ b/contrib/tzcode/newctime.3 @@ -9,16 +9,16 @@ .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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ .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/contrib/tzcode/newstrftime.3 b/contrib/tzcode/newstrftime.3 --- a/contrib/tzcode/newstrftime.3 +++ b/contrib/tzcode/newstrftime.3 @@ -91,11 +91,11 @@ 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 @@ .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 @@ .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 @@ %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 @@ 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 @@ 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 @@ 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/contrib/tzcode/newtzset.3 b/contrib/tzcode/newtzset.3 --- a/contrib/tzcode/newtzset.3 +++ b/contrib/tzcode/newtzset.3 @@ -15,6 +15,14 @@ .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 @@ .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 @@ .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 @@ .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 @@ 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 @@ 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/contrib/tzcode/private.h b/contrib/tzcode/private.h --- a/contrib/tzcode/private.h +++ b/contrib/tzcode/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 @@ # 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 @@ # 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 @@ # 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 @@ -656,6 +671,12 @@ # 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 @@ -681,10 +702,12 @@ # 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 @@ -715,7 +738,7 @@ 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 @@ -803,10 +826,10 @@ 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 @@ -978,8 +1001,9 @@ /* 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/contrib/tzcode/theory.html b/contrib/tzcode/theory.html --- a/contrib/tzcode/theory.html +++ b/contrib/tzcode/theory.html @@ -89,13 +89,15 @@ href="https://en.wikipedia.org/wiki/POSIX">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 @@

-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 @@ 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 @@ 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 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 @@ 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 @@ 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 @@ 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 @@

      - 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 @@

      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 @@ 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 @@ 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

    @@ -413,7 +413,7 @@ 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 @@
    • 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 @@
    • 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 @@ 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 @@ 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 @@ 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/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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@
  • 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 @@ 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/contrib/tzcode/tzfile.h b/contrib/tzcode/tzfile.h --- a/contrib/tzcode/tzfile.h +++ b/contrib/tzcode/tzfile.h @@ -78,14 +78,16 @@ ** 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/contrib/tzcode/tzfile.5 b/contrib/tzcode/tzfile.5 --- a/contrib/tzcode/tzfile.5 +++ b/contrib/tzcode/tzfile.5 @@ -74,7 +74,7 @@ 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. .It Va tzh_typecnt .Vt ttinfo @@ -167,12 +167,12 @@ 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 @@ -197,12 +197,12 @@ 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 @@ -215,13 +215,14 @@ 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 -.Xr 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 +.Xr 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 @@ -336,7 +337,8 @@ .It 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. @@ -368,6 +370,18 @@ As a partial workaround, a writer can output more transitions than necessary. .It +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 +.Dq <+01>\*-1 , +which should be used only for timestamps after the last +explicit transition. +.It 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/contrib/tzcode/tzselect.ksh b/contrib/tzcode/tzselect.ksh --- a/contrib/tzcode/tzselect.ksh +++ b/contrib/tzcode/tzselect.ksh @@ -20,12 +20,6 @@ # 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 @@ # 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ # 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 @@ # 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ '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 @@ } } ' ="$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 @@ } } ' ="$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 @@ 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 @@ } } ' ="$sorted_table" - ` + ) time=$select_result continent_re='^' - zone_table=` + zone_table=$( $AWK ' BEGIN { time = substr(ARGV[1], 2) @@ -609,13 +597,13 @@ } } ' ="$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 @@ 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 @@ print comment[i] } ' ="$zone_table" - ` + ) # If there's more than one country, ask the user which one. case $countries in @@ -669,7 +657,7 @@ # Get list of timezones in the country. - regions=` + regions=$( $AWK ' BEGIN { country = substr(ARGV[1], 2) @@ -696,7 +684,7 @@ } } ' ="$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 @@ esac # Determine tz from country and region. - tz=` + tz=$( $AWK ' BEGIN { country = substr(ARGV[1], 2) @@ -735,7 +723,7 @@ } } ' ="$country" ="$region" ="$TZ_COUNTRY_TABLE" ="$zone_table" - ` + ) esac # Make sure the corresponding zoneinfo file exists. @@ -754,14 +742,11 @@ 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 @@ 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/contrib/tzcode/version b/contrib/tzcode/version --- a/contrib/tzcode/version +++ b/contrib/tzcode/version @@ -1 +1 @@ -2024a +2024b diff --git a/contrib/tzcode/workman.sh b/contrib/tzcode/workman.sh --- a/contrib/tzcode/workman.sh +++ b/contrib/tzcode/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/contrib/tzcode/zdump.c b/contrib/tzcode/zdump.c --- a/contrib/tzcode/zdump.c +++ b/contrib/tzcode/zdump.c @@ -89,7 +89,7 @@ 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 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 @@ /* 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 @@ /* 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); @@ -934,7 +934,7 @@ # 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/contrib/tzcode/zic.8 b/contrib/tzcode/zic.8 --- a/contrib/tzcode/zic.8 +++ b/contrib/tzcode/zic.8 @@ -156,7 +156,7 @@ .Em pre- .Ar hi transitions rather than concisely representing them -with an extended POSIX.1-2017 TZ string. +with a proleptic TZ string. Also see the .Fl b Cm slim option for another way to shrink output size. @@ -165,10 +165,10 @@ that occur less than .Ar 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. .It Fl t Ar file When creating local time information, put the configuration link in @@ -227,11 +227,10 @@ .It 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. .It The output contains data that may not be handled properly by client code designed for older @@ -535,21 +534,27 @@ begin the field with a minus sign if time must be subtracted from UT. .It 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 +.Ar 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 -.Ql \- -then standard time always applies. +Standard time applies if this field is +.Ql \*- +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. .It FORMAT The format for time zone abbreviations. The pair of characters .Ql %s -is used to show where the -.Dq "variable part" -of the time zone abbreviation goes. +shows where to put the time zone abbreviation's variable part, +which is taken from the +.Ar LETTER/S +field of the corresponding rule; +any timestamps that precede the earliest rule use the +.Ar LETTER/S +of the earliest standard-time rule (which in this case must exist). Alternatively, a format can use the pair of characters .Ql %z to stand for the UT offset in the form @@ -633,13 +638,12 @@ seconds is instead assumed to take effect simultaneously. For example: .Bd -literal -offset indent -# Rule NAME FROM TO \*- IN ON AT SAVE LETTER/S +# Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule US 1967 2006 - Oct lastSun 2:00 0 S Rule US 1967 1973 - Apr lastSun 2:00 1:00 D - -# Zone\0\0NAME STDOFF RULES FORMAT [UNTIL] -Zone\0\0America/Menominee \*-5:00 \*- EST 1973 Apr 29 2:00 - \*-6:00 US C%sT +# Zone NAME STDOFF RULES FORMAT [UNTIL] +Zone America/Menominee -5:00 - EST 1973 Apr 29 2:00 + -6:00 US C%sT .Ed Here, an incorrect reading would be there were two clock changes on 1973-04-29, the first from 02:00 EST (\-05) to 01:00 CST (\-06), @@ -730,16 +734,16 @@ 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 .Dq "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 .Fl r option is used. .Pp diff --git a/contrib/tzcode/zic.c b/contrib/tzcode/zic.c --- a/contrib/tzcode/zic.c +++ b/contrib/tzcode/zic.c @@ -472,7 +472,7 @@ 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 @@ -486,7 +486,7 @@ size_overflow(); } -ATTRIBUTE_REPRODUCIBLE static ptrdiff_t +ATTRIBUTE_PURE_114833 static ptrdiff_t size_product(ptrdiff_t nitems, ptrdiff_t itemsize) { #ifdef ckd_mul @@ -501,7 +501,7 @@ size_overflow(); } -ATTRIBUTE_REPRODUCIBLE static ptrdiff_t +ATTRIBUTE_PURE_114833 static ptrdiff_t align_to(ptrdiff_t size, ptrdiff_t alignment) { size_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits); @@ -525,7 +525,7 @@ return ptr; } -ATTRIBUTE_MALLOC static void * +static void * emalloc(size_t size) { return memcheck(malloc(size)); @@ -537,7 +537,7 @@ return memcheck(realloc(ptr, size)); } -ATTRIBUTE_MALLOC static char * +static char * estrdup(char const *str) { return memcheck(strdup(str)); @@ -1475,7 +1475,7 @@ /* 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++) @@ -3034,10 +3034,10 @@ 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) { @@ -3229,8 +3229,7 @@ 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 @@ -3494,7 +3493,7 @@ 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 @@ -3679,7 +3678,7 @@ } /* 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++)) @@ -3688,7 +3687,7 @@ 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)) @@ -3704,7 +3703,7 @@ /* 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 @@ -3814,7 +3813,7 @@ exit(EXIT_FAILURE); } -ATTRIBUTE_REPRODUCIBLE static zic_t +ATTRIBUTE_PURE_114833 static zic_t oadd(zic_t t1, zic_t t2) { #ifdef ckd_add @@ -3828,7 +3827,7 @@ time_overflow(); } -ATTRIBUTE_REPRODUCIBLE static zic_t +ATTRIBUTE_PURE_114833 static zic_t tadd(zic_t t1, zic_t t2) { #ifdef ckd_add