diff options
| -rw-r--r-- | CONTRIBUTING | 36 | ||||
| -rw-r--r-- | Makefile | 196 | ||||
| -rw-r--r-- | NEWS | 135 | ||||
| -rw-r--r-- | README | 14 | ||||
| -rw-r--r-- | SECURITY | 2 | ||||
| -rw-r--r-- | calendars | 27 | ||||
| -rw-r--r-- | date.1 | 2 | ||||
| -rw-r--r-- | date.1.txt | 10 | ||||
| -rw-r--r-- | date.c | 7 | ||||
| -rw-r--r-- | localtime.c | 869 | ||||
| -rw-r--r-- | newctime.3 | 22 | ||||
| -rw-r--r-- | newctime.3.txt | 18 | ||||
| -rw-r--r-- | newstrftime.3 | 2 | ||||
| -rw-r--r-- | newstrftime.3.txt | 124 | ||||
| -rw-r--r-- | newtzset.3 | 18 | ||||
| -rw-r--r-- | newtzset.3.txt | 193 | ||||
| -rw-r--r-- | private.h | 346 | ||||
| -rw-r--r-- | theory.html | 367 | ||||
| -rw-r--r-- | time2posix.3.txt | 4 | ||||
| -rw-r--r-- | tz-art.html | 415 | ||||
| -rw-r--r-- | tz-how-to.html | 178 | ||||
| -rw-r--r-- | tz-link.html | 289 | ||||
| -rw-r--r-- | tzfile.5 | 21 | ||||
| -rw-r--r-- | tzfile.5.txt | 442 | ||||
| -rw-r--r-- | tzfile.h | 2 | ||||
| -rw-r--r-- | tzselect.8.txt | 38 | ||||
| -rw-r--r-- | tzselect.ksh | 15 | ||||
| -rw-r--r-- | version | 2 | ||||
| -rw-r--r-- | workman.sh | 36 | ||||
| -rw-r--r-- | zdump.8.txt | 124 | ||||
| -rw-r--r-- | zdump.c | 18 | ||||
| -rw-r--r-- | zic.8 | 56 | ||||
| -rw-r--r-- | zic.8.txt | 534 | ||||
| -rw-r--r-- | zic.c | 457 |
34 files changed, 3106 insertions, 1913 deletions
diff --git a/CONTRIBUTING b/CONTRIBUTING index f6edbd3be7d3..c5fa803f7275 100644 --- a/CONTRIBUTING +++ b/CONTRIBUTING @@ -10,26 +10,27 @@ warning, the data entries do not cover all of civil time before 1970, and undoubtedly errors remain in the code and data. Feel free to fill gaps or fix mistakes, and please email improvements to <tz@iana.org> for use in the future. In your email, please give -reliable sources that reviewers can check. +reliable sources that reviewers can check. The mailing list and its +archives are public, so please do not send confidential information. ## Contributing technical changes To email small changes, please run a POSIX shell command like -'diff -u old/europe new/europe >myfix.patch', and attach -'myfix.patch' to the email. +‘diff -u old/europe new/europe >myfix.patch’, and attach +‘myfix.patch’ to the email. For more-elaborate or possibly controversial changes, such as renaming, adding or removing zones, please read -"Theory and pragmatics of the tz code and data" +“Theory and pragmatics of the tz code and data” <https://www.iana.org/time-zones/repository/theory.html>. It is also good to browse the mailing list archives <https://lists.iana.org/hyperkitty/list/tz@iana.org/> for examples of patches that tend to work well. Changes should contain commentary citing reliable sources. -Citations should use "https:" URLs if available. +Citations should use ‘https:’ URLs if available. For changes that fix sensitive security-related bugs, please see the -distribution's 'SECURITY' file. +distribution’s SECURITY file. Please submit changes against either the latest release <https://www.iana.org/time-zones> or the main branch of the development @@ -54,11 +55,11 @@ If you use Git the following workflow may be helpful: git checkout -b mybranch - * Sleuth by using 'git blame'. For example, when fixing data for - Africa/Sao_Tome, if the command 'git blame africa' outputs a line - '2951fa3b (Paul Eggert 2018-01-08 09:03:13 -0800 1068) Zone - Africa/Sao_Tome 0:26:56 - LMT 1884', commit 2951fa3b should - provide some justification for the 'Zone Africa/Sao_Tome' line. + * Sleuth by using ‘git blame’. For example, when fixing data for + Africa/Sao_Tome, if the command ‘git blame africa’ outputs a line + ‘2951fa3b (Paul Eggert 2018-01-08 09:03:13 -0800 1068) Zone + Africa/Sao_Tome 0:26:56 - LMT 1884’, commit 2951fa3b should + provide some justification for the ‘Zone Africa/Sao_Tome’ line. * Edit source files. Include commentary that justifies the changes by citing reliable sources. @@ -69,28 +70,31 @@ If you use Git the following workflow may be helpful: ./zdump -v America/Los_Angeles Although builds assume only basic POSIX, they use extra features - if available. 'make check' accesses validator.w3.org unless you - lack 'curl' or use 'make CURL=:'. If you have the latest GCC, - "make CFLAGS='$(GCC_DEBUG_FLAGS)'" does extra checking. + if available. ‘make check’ accesses validator.w3.org unless you + lack ‘curl’ or use ‘make CURL=:’. If you have the latest GCC, + ‘make CFLAGS='$(GCC_DEBUG_FLAGS)'’ does extra checking. * For each separable change, commit it in the new branch, e.g.: git add northamerica git commit - See recent 'git log' output for the commit-message style. + See recent ‘git log’ output for the commit-message style. * Create patch files 0001-..., 0002-..., ... git format-patch main + * Check that the patch files and your email setup contain only + information that you want to make public. + * After reviewing the patch files, send the patches to <tz@iana.org> for others to review. git send-email main For an archived example of such an email, see - "[PROPOSED] Fix off-by-1 error for Jamaica and T&C before 1913" + “[PROPOSED] Fix off-by-1 error for Jamaica and T&C before 1913” <https://mm.icann.org/pipermail/tz/2018-February/026122.html>. * Start anew by getting current with the main branch again @@ -3,17 +3,30 @@ # 2009-05-17 by Arthur David Olson. # Request POSIX conformance; this must be the first non-comment line. .POSIX: +# By default, builds of code and data assume POSIX.1-2001 or later; +# this assumption can be relaxed by tailoring the build as described below. # On older platforms you may need to scrounge for POSIX conformance. # For example, on Solaris 10 (2005) with Sun Studio 12 aka Sun C 5.9 (2007), # use 'PATH=/usr/xpg4/bin:$PATH make CC=c99'. +# Reproducible builds of distribution tarballs also need a copy of the +# Git repository, and assume the behavior of the following programs +# (or later versions): +# Git 2.7.0 (2016) +# GNU Coreutils 6.3 (2006) +# GNU Tar 1.14 (2004) +# GnuPG 1.4 (2004) +# Although tzdb does not come with a software bill of materials, +# you should be able to construct one based on the above information, +# your platform, and the way you use this Makefile. # To affect how this Makefile works, you can run a shell script like this: # # #!/bin/sh -# make CC='gcc -std=gnu23' "$@" +# make CFLAGS='-O2 -DHAVE_GETTEXT=0' "$@" # -# This example script is appropriate for a circa 2024 GNU/Linux system -# where a non-default setting enables this package's optional use of C23. +# This example script is appropriate for a GNU/Linux system +# which needs more optimization than default, and which does not want +# gettext's internationalization of diagnostics. # # Alternatively, you can simply edit this Makefile to tailor the following # macro definitions. @@ -150,8 +163,9 @@ TIME_T_ALTERNATIVES_TAIL = int_least32_t.ck uint_least32_t.ck \ # below. If you want both sets of data available, with leap seconds counted # normally, use # REDO= right_posix -# below. POSIX mandates that leap seconds not be counted; for compatibility -# with it, use "posix_only" or "posix_right". Use POSIX time on systems with +# below. POSIX mandates that leap seconds not be counted, and a +# nonnegative TZ_CHANGE_INTERVAL also assumes this, so to be compatible with +# these, use "posix_only" or "posix_right". Use POSIX time on systems with # leap smearing; this can work better than unsmeared "right" time with # applications that are not leap second aware, and is closer to unsmeared # "right" time than unsmeared POSIX time is (e.g., 0.5 vs 1.0 s max error). @@ -206,6 +220,12 @@ PACKRATLIST= UTF8_LOCALE= en_US.utf8 +# Extra flags for producing man page files like tzfile.5.txt. +# These flags are used only if groff (or mandoc) is present. +# Each option should begin with "-" and should lack shell metacharacters. +# Plausible options include -Tascii and -Tutf8. +MANFLAGS= -Tutf8 + # Non-default libraries needed to link. # On some hosts, this should have -lintl unless CFLAGS has -DHAVE_GETTEXT=0. LDLIBS= @@ -219,14 +239,19 @@ LDLIBS= # -DEPOCH_OFFSET=N if the 'time' function returns a value N greater # than what POSIX specifies, assuming local time is UT. # For example, N is 252460800 on AmigaOS. +# -DFREE_PRESERVES_ERRNO=[01] if the 'free' function munges or preserves errno +# (default is guessed) # -DHAVE_DECL_ASCTIME_R=0 if <time.h> does not declare asctime_r # on POSIX platforms predating POSIX.1-2024 # -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ' # -DHAVE_DECL_TIMEGM=0 if <time.h> does not declare timegm # -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows) +# -DHAVE_FCHMOD=0 if your system lacks the fchmod function # -DHAVE__GENERIC=0 if _Generic does not work* +# -DHAVE_GETEUID=0 if gete?[ug]id do not work # -DHAVE_GETRANDOM if getrandom works (e.g., GNU/Linux), # -DHAVE_GETRANDOM=0 to avoid using getrandom +# -DHAVE_GETRESUID=0 if getres[ug]id do not work # -DHAVE_GETTEXT if gettext works (e.g., GNU/Linux, FreeBSD, Solaris), # where LDLIBS also needs to contain -lintl on some hosts; # -DHAVE_GETTEXT=0 to avoid using gettext @@ -234,28 +259,43 @@ LDLIBS= # ctime_r and asctime_r incompatibly with POSIX.1-2017 and earlier # (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined). # -DHAVE_INTTYPES_H=0 if <inttypes.h> does not work*+ +# -DHAVE_ISSETUGID=1 if issetugid works, 0 otherwise (default is guessed) +# If 0, you may also use -DHAVE_SYS_AUXV_H=1 if <sys/auxv.h> works, +# 0 otherwise (default is guessed). # -DHAVE_LINK=0 if your system lacks a link function # -DHAVE_LOCALTIME_R=0 if your system lacks a localtime_r function # -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz # localtime_rz can make zdump significantly faster, but is nonstandard. # -DHAVE_MALLOC_ERRNO=0 if malloc etc. do not set errno on failure. +# -DHAVE_MEMPCPY=1 if your system has mempcpy, 0 if not (default is guessed) # -DHAVE_POSIX_DECLS=0 if your system's include files do not declare -# functions like 'link' or variables like 'tzname' required by POSIX +# variables like 'tzname' required by POSIX +# -DHAVE_PWD_H=0 if your system lacks pwd.h, grp.h and corresponding functions +# If 0, you may also need -Dgid_t=G -Duid_t=U +# to define gid_t and uid_t to be types G and U. # -DHAVE_SETENV=0 if your system lacks the setenv function +# -DHAVE_SETMODE=[01] if your system lacks or has the setmode and getmode +# functions (default is guessed) # -DHAVE_SNPRINTF=0 if your system lacks the snprintf function+ # -DHAVE_STDCKDINT_H=0 if neither <stdckdint.h> nor substitutes like # __builtin_add_overflow work* # -DHAVE_STDINT_H=0 if <stdint.h> does not work*+ # -DHAVE_STRFTIME_L if <time.h> declares locale_t and strftime_l # -DHAVE_STRDUP=0 if your system lacks the strdup function +# -DHAVE_STRNLEN=0 if your system lacks the strnlen function+ # -DHAVE_STRTOLL=0 if your system lacks the strtoll function+ +# -DHAVE_STRUCT_STAT_ST_CTIM=0 if struct stat lacks a member st_ctim+ +# -DHAVE_STRUCT_TIMESPEC=0 if your system lacks struct timespec+ # -DHAVE_SYMLINK=0 if your system lacks the symlink function # -DHAVE_SYS_STAT_H=0 if <sys/stat.h> does not work* +# If 0, you may also need -Dmode_t=M to define mode_t to be type M. # -DHAVE_TZSET=0 if your system lacks a tzset function # -DHAVE_UNISTD_H=0 if <unistd.h> does not work* # -DHAVE_UTMPX_H=0 if <utmpx.h> does not work* # -Dlocale_t=XXX if your system uses XXX instead of locale_t # -DMKTIME_MIGHT_OVERFLOW if mktime might fail due to time_t overflow +# -DOPENAT_TZDIR if tzset should use openat on TZDIR then a relative open. +# See localtime.c for details. # -DPORT_TO_C89 if tzcode should also run on mostly-C89 platforms+ # Typically it is better to use a later standard. For example, # with GCC 4.9.4 (2016), prefer '-std=gnu11' to '-DPORT_TO_C89'. @@ -274,8 +314,36 @@ LDLIBS= # -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires; # not needed by the main-program tz code, which is single-threaded. # Append other compiler flags as needed, e.g., -pthread on GNU/Linux. +# The following options can also be used: +# -DTHREAD_PREFER_SINGLE to prefer speed in single-threaded apps, +# at some cost in CPU time and energy in multi-threaded apps. +# The following options can also be used: +# -DHAVE___ISTHREADED=1 if there is an extern int __isthreaded +# variable, 0 otherwise (default is guessed) +# -DHAVE_SYS_SINGLE_THREADED_H=0 if <sys/single_threaded.h> works, +# 0 otherwise (default is guessed) +# -DTHREAD_RWLOCK to use read-write locks intead of mutexes. +# This can improve paralellism and thus save real time +# if many threads call tzcode functions simultaneously. +# It also costs CPU time and thus energy. +# -DTHREAD_TM_MULTI to have gmtime, localtime, and offtime +# return different struct tm * addresses in different threads. +# This supports unportable programs that call +# gmtime/localtime/offtime when they should call +# gmtime_r/localtime_r/offtime_r to avoid races. +# Because the corresponding storage is freed on thread exit, +# this option is incompatible with POSIX.1-2024 and earlier. +# It also costs CPU time and memory. # -Dtime_tz=\"T\" to use T as the time_t type, rather than the system time_t # This is intended for internal use only; it mangles external names. +# -DTZ_CHANGE_INTERVAL=N if functions depending on TZ should check +# no more often than every N seconds for TZif file changes. +# If N is negative (the default), no such checking is done. +# This option is intended for platforms that want localtime etc. +# to respond to changes to a file selected by TZ, including to +# TZDEFAULT (normally /etc/localtime) if TZ is unset. +# On these platforms, REDO should be "posix_only" or "posix_right". +# This option does not affect tzalloc-allocated objects. # -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is "tz" # -DTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory; # the default is system-supplied, typically "/usr/lib/locale" @@ -314,7 +382,7 @@ LDLIBS= # Select instrumentation via "make GCC_INSTRUMENT='whatever'". GCC_INSTRUMENT = \ -fsanitize=undefined -fsanitize-address-use-after-scope \ - -fsanitize-undefined-trap-on-error -fstack-protector + -fsanitize-trap=all -fstack-protector # Omit -fanalyzer from GCC_DEBUG_FLAGS, as it makes GCC too slow. GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \ $(GCC_INSTRUMENT) \ @@ -393,7 +461,9 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \ # functions to be added to the time conversion library. # "offtime" is like "gmtime" except that it accepts a second (long) argument # that gives an offset to add to the time_t when converting it. -# I.e., "offtime" is like calling "localtime_rz" with a fixed-offset zone. +# "offtime_r" is to "offtime" what "gmtime_r" is to "gmtime". +# I.e., "offtime" and "offtime_r" are like calling "localtime_rz" +# with a fixed-offset zone. # "timelocal" is nearly equivalent to "mktime". # "timeoff" is like "timegm" except that it accepts a second (long) argument # that gives an offset to use when converting to a time_t. @@ -451,6 +521,11 @@ leaplist_URI = \ https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list # The file is generated by the IERS Earth Orientation Centre, in Paris. leaplist_TZ = Europe/Paris +# +# To fetch leap-seconds.list from NIST via a less-secure protocol +# and with less-volatile metadata, use these settings: +#leaplist_URI = ftp://ftp.boulder.nist.gov/pub/time/leap-seconds.list +#leaplist_TZ = America/Denver # The zic command and its arguments. @@ -510,13 +585,10 @@ SAFE_CHARSET3= 'abcdefghijklmnopqrstuvwxyz{|}~' SAFE_CHARSET= $(SAFE_CHARSET1)$(SAFE_CHARSET2)$(SAFE_CHARSET3) SAFE_CHAR= '[]'$(SAFE_CHARSET)'-]' -# These non-alphabetic, non-ASCII printable characters are Latin-1, -# and so are likely displayable even in editors like XEmacs 21 -# that have limited display capabilities. -UNUSUAL_OK_LATIN_1 = ¡¢£¤¥¦§¨©«¬®¯°±²³´¶·¸¹»¼½¾¿×÷ -# Non-ASCII non-letters that OK_CHAR allows, as these characters are -# useful in commentary. -UNUSUAL_OK_CHARSET= $(UNUSUAL_OK_LATIN_1) +# These non-alphabetic, non-ASCII printable characters are +# used in commentary or in generated *.txt files +# and are not likely to cause confusion. +UNUSUAL_OK_CHARSET= §«°±»½¾×–‘’“”•→−≤★⟨⟩⯪ # Put this in a bracket expression to match spaces. s = [:space:] @@ -525,9 +597,6 @@ s = [:space:] # This is the same as SAFE_CHAR, except that UNUSUAL_OK_CHARSET and # multibyte letters are also allowed so that commentary can contain a # few safe symbols and people's names and can quote non-English sources. -# Other non-letters are limited to ASCII renderings for the -# convenience of maintainers using XEmacs 21.5.34, which by default -# mishandles Unicode characters U+0100 and greater. OK_CHAR= '[][:alpha:]$(UNUSUAL_OK_CHARSET)'$(SAFE_CHARSET)'-]' # SAFE_LINE matches a line of safe characters. @@ -874,9 +943,9 @@ UTF8_LOCALE_MISSING = \ character-set.ck: $(ENCHILADA) $(UTF8_LOCALE_MISSING) || { \ sharp='#' && \ - ! grep -Env $(SAFE_LINE) $(MANS) date.1 $(MANTXTS) \ - $(MISC) $(SOURCES) $(WEB_PAGES) \ - CONTRIBUTING LICENSE README SECURITY \ + ! grep -Env $(SAFE_LINE) $(MANS) date.1 \ + $(MISC) $(SOURCES) \ + LICENSE \ version tzdata.zi && \ ! grep -Env $(SAFE_LINE)'|^UNUSUAL_OK_'$(OK_CHAR)'*$$' \ Makefile && \ @@ -888,11 +957,9 @@ character-set.ck: $(ENCHILADA) white-space.ck: $(ENCHILADA) $(UTF8_LOCALE_MISSING) || { \ - enchilada='$(ENCHILADA)' && \ patfmt=' \t|[\f\r\v]' && pat=$$(printf "$$patfmt\\n") && \ ! grep -En "$$pat|[$s]\$$" \ - $${enchilada%leap-seconds.list*} \ - $${enchilada#*leap-seconds.list}; \ + $(ENCHILADA:leap-seconds.list=); \ } touch $@ @@ -959,8 +1026,10 @@ now.ck: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab ./zdump -i -t 0,$$future \ $$(find "$$PWD/$@d" -name Etc -prune \ -o -type f ! -name '*.tab' -print) \ - >$@d/zdump-1970.tab + >$@d/zdump-1970.tab && \ $(AWK) \ + -v now=$$now \ + -v now_out=$@.out \ -v zdump_table=$@d/zdump-now.tab \ -f checknow.awk zonenow.tab $(AWK) \ @@ -970,7 +1039,8 @@ now.ck: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab -v zdump_table=$@d/zdump-1970.tab \ -f checknow.awk rm -fr $@d - touch $@ + touch $@.out + mv $@.out $@ tables.ck: checktab.awk $(YDATA) backward zone.tab zone1970.tab for tab in $(ZONETABLES); do \ @@ -1031,7 +1101,7 @@ zishrink-posix.ck zishrink-right.ck: \ clean_misc: rm -fr *.ckd *.dir - rm -f *.ck *.core *.o *.out core core.* \ + rm -f *.ck *.core *.o *.out *.t core core.* \ date tzdir.h tzselect version.h zdump zic libtz.a clean: clean_misc rm -fr tzdb-*/ @@ -1059,7 +1129,7 @@ zdump.8.txt: zdump.8 zic.8.txt: zic.8 $(MANTXTS): workman.sh - LC_ALL=C sh workman.sh $(@:.txt=) >$@.out + LC_ALL=C sh workman.sh $(MANFLAGS) $(@:.txt=) >$@.out mv $@.out $@ # Set file timestamps deterministically if possible, @@ -1108,7 +1178,7 @@ set-timestamps.out: $(EIGHT_YARDS) if git diff --quiet HEAD $$file; then \ time=$$(TZ=UTC0 git log -1 \ --format='tformat:%cd' \ - --date='format:%Y-%m-%dT%H:%M:%SZ' \ + --date='format-local:%Y-%m-%dT%H:%M:%SZ' \ $$file) && \ echo "+ touch -md $$time $$file" && \ touch -md $$time $$file; \ @@ -1207,12 +1277,12 @@ $(TIME_T_ALTERNATIVES): $(VERSION_DEPS) touch $@ TRADITIONAL_ASC = \ - tzcode$(VERSION).tar.gz.asc \ - tzdata$(VERSION).tar.gz.asc + tzcode$(VERSION).tar.gz.asc.t \ + tzdata$(VERSION).tar.gz.asc.t REARGUARD_ASC = \ - tzdata$(VERSION)-rearguard.tar.gz.asc + tzdata$(VERSION)-rearguard.tar.gz.asc.t ALL_ASC = $(TRADITIONAL_ASC) $(REARGUARD_ASC) \ - tzdb-$(VERSION).tar.lz.asc + tzdb-$(VERSION).tar.lz.asc.t tarballs rearguard_tarballs tailored_tarballs traditional_tarballs \ signatures rearguard_signatures traditional_signatures: \ @@ -1224,29 +1294,31 @@ signatures rearguard_signatures traditional_signatures: \ # other means. Ordinarily these rules are used only by the above # non-_version rules, which set VERSION on the 'make' command line. tarballs_version: traditional_tarballs_version rearguard_tarballs_version \ - tzdb-$(VERSION).tar.lz + tzdb-$(VERSION).tar.lz.t rearguard_tarballs_version: \ - tzdata$(VERSION)-rearguard.tar.gz + tzdata$(VERSION)-rearguard.tar.gz.t traditional_tarballs_version: \ - tzcode$(VERSION).tar.gz tzdata$(VERSION).tar.gz + tzcode$(VERSION).tar.gz.t tzdata$(VERSION).tar.gz.t tailored_tarballs_version: \ - tzdata$(VERSION)-tailored.tar.gz + tzdata$(VERSION)-tailored.tar.gz.t signatures_version: $(ALL_ASC) rearguard_signatures_version: $(REARGUARD_ASC) traditional_signatures_version: $(TRADITIONAL_ASC) -tzcode$(VERSION).tar.gz: set-timestamps.out +tzcode$(VERSION).tar.gz.t: set-timestamps.out $(SETUP_TAR) && \ $$TAR -cf - \ $(COMMON) $(DOCS) $(SOURCES) | \ - gzip $(GZIPFLAGS) >$@.out - mv $@.out $@ + gzip $(GZIPFLAGS) >$(@:.t=) + $(SET_TIMESTAMP) $(@:.t=) $(COMMON) $(DOCS) $(SOURCES) + touch $@ -tzdata$(VERSION).tar.gz: set-timestamps.out +tzdata$(VERSION).tar.gz.t: set-timestamps.out $(SETUP_TAR) && \ $$TAR -cf - $(TZDATA_DIST) | \ - gzip $(GZIPFLAGS) >$@.out - mv $@.out $@ + gzip $(GZIPFLAGS) >$(@:.t=) + $(SET_TIMESTAMP) $(@:.t=) $(TZDATA_DIST) + touch $@ # Create empty files with a reproducible timestamp. CREATE_EMPTY = TZ=UTC0 touch -mt 202010122253.00 @@ -1255,7 +1327,7 @@ CREATE_EMPTY = TZ=UTC0 touch -mt 202010122253.00 # for backwards compatibility with tz releases 2018e through 2022a. # They should go away eventually. To build rearguard tarballs you # can instead use 'make DATAFORM=rearguard tailored_tarballs'. -tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out +tzdata$(VERSION)-rearguard.tar.gz.t: rearguard.zi set-timestamps.out rm -fr $@.dir mkdir $@.dir ln $(TZDATA_DIST) $@.dir @@ -1273,8 +1345,11 @@ tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out (cd $@.dir && \ $$TAR -cf - \ $(TZDATA_DIST) pacificnew | \ - gzip $(GZIPFLAGS)) >$@.out - mv $@.out $@ + gzip $(GZIPFLAGS)) >$(@:.t=) + $(SET_TIMESTAMP) $(@:.t=) \ + $$(cd $@.dir && \ + ls $(TZDATA_DIST) pacificnew | sed 's,^,$@.dir/,') + touch $@ # Create a tailored tarball suitable for TZUpdater and compatible tools. # For example, 'make DATAFORM=vanguard tailored_tarballs' makes a tarball @@ -1283,7 +1358,7 @@ tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out # traditional tarball, as data entries are put into 'etcetera' even if they # came from some other source file. However, the effect should be the same # for ordinary use, which reads all the source files. -tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out +tzdata$(VERSION)-tailored.tar.gz.t: set-timestamps.out rm -fr $@.dir mkdir $@.dir : The dummy pacificnew pacifies TZUpdater 2.3.1 and earlier. @@ -1295,7 +1370,7 @@ tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out cd $@.dir && \ $(CREATE_EMPTY) $(PRIMARY_YDATA) $(NDATA) backward \ $$pacificnew - (grep '^#' tzdata.zi && echo && cat $(DATAFORM).zi) \ + (sed '/^#/!d' tzdata.zi && echo && cat $(DATAFORM).zi) \ >$@.dir/etcetera touch -mr tzdata.zi $@.dir/etcetera sed -n \ @@ -1316,24 +1391,29 @@ tzdata$(VERSION)-tailored.tar.gz: set-timestamps.out ln $$links $@.dir $(SETUP_TAR) && \ (cd $@.dir && \ - $$TAR -cf - * | gzip $(GZIPFLAGS)) >$@.out - mv $@.out $@ + $$TAR -cf - *) | gzip $(GZIPFLAGS) >$(@:.t=) + $(SET_TIMESTAMP) $(@:.t=) \ + $$(cd $@.dir && ls * | sed 's,^,$@.dir/,') + touch $@ -tzdb-$(VERSION).tar.lz: set-timestamps.out set-tzs-timestamp.out +tzdb-$(VERSION).tar.lz.t: set-timestamps.out set-tzs-timestamp.out rm -fr tzdb-$(VERSION) mkdir tzdb-$(VERSION) ln $(ENCHILADA) tzdb-$(VERSION) $(SET_TIMESTAMP) tzdb-$(VERSION) tzdb-$(VERSION)/* $(SETUP_TAR) && \ - $$TAR -cf - tzdb-$(VERSION) | lzip -9 >$@.out - mv $@.out $@ + $$TAR -cf - tzdb-$(VERSION) | lzip -9 >$(@:.t=) + $(SET_TIMESTAMP) $(@:.t=) tzdb-$(VERSION) + touch $@ -tzcode$(VERSION).tar.gz.asc: tzcode$(VERSION).tar.gz -tzdata$(VERSION).tar.gz.asc: tzdata$(VERSION).tar.gz -tzdata$(VERSION)-rearguard.tar.gz.asc: tzdata$(VERSION)-rearguard.tar.gz -tzdb-$(VERSION).tar.lz.asc: tzdb-$(VERSION).tar.lz +tzcode$(VERSION).tar.gz.asc.t: tzcode$(VERSION).tar.gz.t +tzdata$(VERSION).tar.gz.asc.t: tzdata$(VERSION).tar.gz.t +tzdata$(VERSION)-rearguard.tar.gz.asc.t: tzdata$(VERSION)-rearguard.tar.gz.t +tzdb-$(VERSION).tar.lz.asc.t: tzdb-$(VERSION).tar.lz.t $(ALL_ASC): - $(GPG) --armor --detach-sign $? + $(GPG) --armor --detach-sign $(?:.t=) + $(SET_TIMESTAMP) $(@:.t=) $(?:.t=) + touch $@ TYPECHECK_CFLAGS = $(CFLAGS) -DTYPECHECK -D__time_t_defined -D_TIME_T typecheck: long-long.ck unsigned.ck @@ -1,5 +1,140 @@ News for the tz database +Release 2025c - 2025-12-10 14:42:37 -0800 + + Briefly: + Several code changes for compatibility with FreeBSD. + + Changes to past timestamps + + Baja California agreed with California’s DST rules in 1953 and in + 1961 through 1975, instead of observing standard time all year. + (Thanks to Alois Treindl.) + + Changes to build procedure + + Files in distributed tarballs now have correct commit times. + Formerly, the committer’s time zone was incorrectly ignored. + + Distribution products (*.asc, *.gz, and *.lz) now have + reproducible timestamps. Formerly, only the contents of the + compressed tarballs had reproducible timestamps. + + By default, distributed formatted man pages (*.txt) now use UTF-8 + and are left-adjusted more consistently. A new Makefile macro + MANFLAGS can override these defaults. (Thanks to G. Branden + Robinson for inspiring these changes.) + + Changes to code + + An unset TZ is no longer invalid when /etc/localtime is missing, + and is abbreviated "UTC" not "-00". This reverts to 2024b behavior. + (Problem and patch reported by Dag-Erling Smørgrav.) + + New function offtime_r, short for fixed-offset localtime_rz. + It is defined if STD_INSPIRED is defined. + (Patch from Dag-Erling Smørgrav.) + + tzset etc. are now more cautious about questionable TZ settings. + Privileged programs now reject TZ settings that start with '/', + unless they are TZDEFAULT (default "/etc/localtime") or + start with TZDIR then '/' (default "/usr/share/zoneinfo/"). + Unprivileged programs now require files to be regular files + and reject relative names containing ".." directory components; + formerly, only privileged programs did those two things. + These changes were inspired by similar behavior in FreeBSD. + On NetBSD, unprivileged programs now use O_REGULAR to check + whether a TZ setting starting with '/' names a regular file, + avoiding a minor security race still present elsewhere. + TZ strings taken from tzalloc arguments are now treated with + no less caution than TZ strings taken from the environment, as + the old undocumented behavior would have been hard to explain. + tzset etc. no longer use the ‘access’ system call to check access; + instead they now use the system calls issetugid, getauxval, + getresuid/getresgid, and geteuid/getegid/getuid/getgid (whichever + first works) to test whether a program is privileged. + Compile with -DHAVE_SYS_AUXV_H=[01] to enable or disable + <sys/auxv.h> which (if it defines AT_SECURE) enables getauxval, + and compile with -DHAVE_ISSETUGID=[01], -DHAVE_GETRESUID=[01], and + -DHAVE_GETEUID=[01] to enable or disable the other calls’ use. + + The new CFLAGS option -DTZ_CHANGE_INTERVAL=N makes tzset etc. + check for TZif file changes if the in-memory data are N seconds + old or more, and are derived from the TZ environment variable. + This is intended for platforms that want tzset etc. to reflect + changes to whatever file TZ selects (including changes to + /etc/localtime if TZ is unset). If N is negative (the default) + these checks are omitted; this is the traditional behavior. + + The new CFLAGS options -DHAVE_STRUCT_STAT_ST_CTIM=0 and + -DHAVE_STRUCT_TIMESPEC=0 port to non-POSIX.1-2008 platforms + that lack st_ctim and struct timespec, respectively. + + tzset etc. now treat ' ' like '_' in time zone abbreviations, + just as they treat other invalid bytes. This continues the + transition begun in release 96k, which removed spaces in tzdata + because the spaces break time string parsers. + + The new CFLAGS option -DTHREAD_PREFER_SINGLE causes tzcode + in single-threaded processes to avoid locks, as FreeBSD does. + This can save time in single-threaded apps. The threadedness + testing costs CPU time and energy in multi-threaded apps. + New options -DHAVE___ISTHREADED and -DHAVE_SYS_SINGLE_THREADED_H + can help configure how to test for single-threadedness. + + The new CFLAGS option -DTHREAD_RWLOCK uses read-write locks, as + macOS does, instead of mutexes. This saves real time when TZ is + rarely changing and many threads call tzcode simultaneously. + It costs more CPU time and energy. + + The new CFLAGS option -TTHREAD_TM_MULTI causes localtime to return + a pointer to thread-specific memory, as FreeBSD does, instead of + to the same memory in all threads. This supports unportable + programs that incorrectly use localtime instead of localtime_r. + This option affects gmtime and offtime similarly to localtime. + Because the corresponding storage is freed on thread exit, this + option is incompatible with POSIX.1-2024 and earlier. It also + costs CPU time and memory. + + tzfree now preserves errno, consistently with POSIX.1-2024 ‘free’. + + tzcode now uses mempcpy if available, guessing its availability. + Compile with -DHAVE_MEMPCPY=1 or 0 to override the guess. + + tzcode now uses strnlen to improve asymptotic performance a bit. + Compile with -DHAVE_STRNLEN=0 if your platform lacks it. + + tzcode now hand-declares unistd.h-provided symbols like getopt + if HAVE_UNISTD_H=0, not if HAVE_POSIX_DECLS=0. + + tzset etc. now have an experimental OPENAT_TZDIR option; + see Makefile and localtime.c for details. + + On platforms like GNU/Hurd that do not define PATH_MAX, + exceedingly long TZ strings no longer fail merely because they + exceed an arbitrary file name length limit imposed by tzcode. + + zic has new options inspired by FreeBSD. ‘-D’ skips creation of + output ancestor directories, ‘-m MODE’ sets output files’ mode, + and ‘-u OWNER[:GROUP]’ sets output files’ owner and group. + + zic now uses the fdopen function, which was standardized by + POSIX.1-1988 and is now safe to use in portable code. + This replaces its use of the older umask function, which + complicated maintenance. + + Changes to commentary + + The leapseconds file contains commentary about the IERS and NIST + last-modified and expiration timestamps for leap second data. + (Thanks to Judah Levine.) + + Commentary now also uses characters from the set –‘’“”•≤ as this + can be useful and should work with current applications. This + also affects data in iso3166.tab and zone1970.tab, which now + contain strings like “Côte d’Ivoire” instead of “Côte d'Ivoire”. + + Release 2025b - 2025-03-22 13:40:46 -0700 Briefly: @@ -1,8 +1,8 @@ README for the tz distribution -"Where do I set the hands of the clock?" -- Les Tremayne as The King -"Oh that--you can set them any place you want." -- Frank Baxter as The Scientist - (from the Bell System film "About Time") +“Where do I set the hands of the clock?” – Les Tremayne as The King +“Oh that – you can set them any place you want.” – Frank Baxter as The Scientist + (from the Bell System film “About Time”) The Time Zone Database (called tz, tzdb or zoneinfo) contains code and data that represent the history of local time for many representative @@ -13,12 +13,12 @@ and daylight-saving rules. See <https://www.iana.org/time-zones/repository/tz-link.html> or the file tz-link.html for how to acquire the code and data. -Once acquired, read the leading comments in the file "Makefile" +Once acquired, read the leading comments in the file ‘Makefile’ and make any changes needed to make things right for your system, especially when using a platform other than current GNU/Linux. Then run the following commands, substituting your desired -installation directory for "$HOME/tzdir": +installation directory for ‘$HOME/tzdir’: make TOPDIR="$HOME/tzdir" install "$HOME/tzdir/usr/bin/zdump" -v America/Los_Angeles @@ -39,12 +39,12 @@ The information in the time zone data files is by no means authoritative; fixes and enhancements are welcome. Please see the file CONTRIBUTING for details. -Thanks to these Time Zone Caballeros who've made major contributions to the +Thanks to these Time Zone Caballeros who’ve made major contributions to the time conversion package: Keith Bostic; Bob Devine; Paul Eggert; Robert Elz; Guy Harris; Mark Horton; John Mackin; and Bradley White. Thanks also to Michael Bloom, Art Neilson, Stephen Prince, John Sovereign, and Frank Wales for testing work, and to Gwillim Law for checking local mean time data. -Thanks in particular to Arthur David Olson, the project's founder and first +Thanks in particular to Arthur David Olson, the project’s founder and first maintainer, to whom the time zone community owes the greatest debt of all. None of them are responsible for remaining errors. @@ -1,7 +1,7 @@ Please report any sensitive security-related bugs via email to the tzdb designated coordinators, currently Paul Eggert <eggert@cs.ucla.edu> and Tim Parenti <tim@timtimeonline.com>. -Put "tzdb security" at the start of your email's subject line. +Put “tzdb security” at the start of your email’s subject line. We prefer communications to be in English. You should receive a response within a week. If not, please follow up diff --git a/calendars b/calendars index f4ed9e434e50..699de85cbffa 100644 --- a/calendars +++ b/calendars @@ -16,30 +16,9 @@ and (in Paris only) 1871-05-06 through 1871-05-23. Russia -From Chris Carrier (1996-12-02): -On 1929-10-01 the Soviet Union instituted an "Eternal Calendar" -with 30-day months plus 5 holidays, with a 5-day week. -On 1931-12-01 it changed to a 6-day week; in 1934 it reverted to the -Gregorian calendar while retaining the 6-day week; on 1940-06-27 it -reverted to the 7-day week. With the 6-day week the usual days -off were the 6th, 12th, 18th, 24th and 30th of the month. -(Source: Evitiar Zerubavel, _The Seven Day Circle_) - - -Mark Brader reported a similar story in "The Book of Calendars", edited -by Frank Parise (1982, Facts on File, ISBN 0-8719-6467-8), page 377. But: - -From: Petteri Sulonen (via Usenet) -Date: 14 Jan 1999 00:00:00 GMT -... - -If your source is correct, how come documents between 1929 and 1940 were -still dated using the conventional, Gregorian calendar? - -I can post a scan of a document dated December 1, 1934, signed by -Yenukidze, the secretary, on behalf of Kalinin, the President of the -Executive Committee of the Supreme Soviet, if you like. - +Soviet Russia adopted the Gregorian calendar on 1918-02-14. +It also used 5- and 6-day work weeks at times, in parallel with the +Gregorian calendar; see <https://en.wikipedia.org/wiki/Soviet_calendar>. Sweden (and Finland) @@ -4,8 +4,6 @@ .SH NAME date \- show and set date and time .SH SYNOPSIS -.if n .nh -.if n .na .B date [ .B \-u diff --git a/date.1.txt b/date.1.txt index c3f34e2036ff..1dbcb18d93a5 100644 --- a/date.1.txt +++ b/date.1.txt @@ -15,12 +15,12 @@ DESCRIPTION abbreviation for the time zone specified in the TZ environment variable if set). The exact output format depends on the locale. - If a command-line argument starts with a plus sign ("+"), the rest of + If a command-line argument starts with a plus sign (“+”), the rest of the argument is used as a format that is processed by strftime(3) to determine what to output; a newline character is appended. For example, the shell command: date +"%Y-%m-%d %H:%M:%S %z" - outputs a line like "2025-03-08 14:54:40 -0500" instead. + outputs a line like “2025-03-08 14:54:40 -0500” instead. These options are available: @@ -28,9 +28,9 @@ DESCRIPTION Use Universal Time when setting and showing the date and time. -r seconds - Output the date that corresponds to seconds past the epoch of - 1970-01-01 00:00:00 UTC, where seconds should be an integer, - either decimal, octal (leading 0), or hexadecimal (leading 0x), + Output the date that corresponds to seconds past the epoch of + 1970-01-01 00:00:00 UTC, where seconds should be an integer, + either decimal, octal (leading 0), or hexadecimal (leading 0x), preceded by an optional sign. FILES @@ -31,11 +31,6 @@ #include <locale.h> #include <stdio.h> -#if !HAVE_POSIX_DECLS -extern char * optarg; -extern int optind; -#endif - static int retval = EXIT_SUCCESS; static void display(const char *, time_t); @@ -64,7 +59,7 @@ main(const int argc, char *argv[]) textdomain(TZ_DOMAIN); #endif /* HAVE_GETTEXT */ t = time(NULL); - while ((ch = getopt(argc, argv, "ucr:")) != EOF && ch != -1) { + while ((ch = getopt(argc, argv, "ucr:")) != -1) { switch (ch) { default: usage(); diff --git a/localtime.c b/localtime.c index 96737ca6640c..b80a34138370 100644 --- a/localtime.c +++ b/localtime.c @@ -21,22 +21,202 @@ #if HAVE_SYS_STAT_H # include <sys/stat.h> +# ifndef S_ISREG +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) /* Ancient UNIX. */ +# endif +#else +struct stat { char st_ctime, st_dev, st_ino; }; +# define dev_t char +# define ino_t char +# define fstat(fd, st) (memset(st, 0, sizeof *(st)), 0) +# define stat(name, st) fstat(0, st) +# define S_ISREG(mode) 1 +#endif + +#ifndef HAVE_STRUCT_STAT_ST_CTIM +# define HAVE_STRUCT_STAT_ST_CTIM 1 +#endif +#if !defined st_ctim && defined __APPLE__ && defined __MACH__ +# define st_ctim st_ctimespec +#endif + +#ifndef THREAD_SAFE +# define THREAD_SAFE 0 #endif -#if !defined S_ISREG && defined S_IFREG -/* Ancient UNIX or recent MS-Windows. */ -# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) + +#ifndef THREAD_RWLOCK +# define THREAD_RWLOCK 0 +#endif + +#ifndef THREAD_TM_MULTI +# define THREAD_TM_MULTI 0 #endif -#if defined THREAD_SAFE && THREAD_SAFE +#if THREAD_SAFE # include <pthread.h> + +# ifndef THREAD_PREFER_SINGLE +# define THREAD_PREFER_SINGLE 0 +# endif +# if THREAD_PREFER_SINGLE +# ifndef HAVE___ISTHREADED +# if defined __FreeBSD__ || defined __OpenBSD__ +# define HAVE___ISTHREADED 1 +# else +# define HAVE___ISTHREADED 0 +# endif +# endif +# if HAVE___ISTHREADED +extern int __isthreaded; +# else +# if !defined HAVE_SYS_SINGLE_THREADED_H && defined __has_include +# if __has_include(<sys/single_threaded.h>) +# define HAVE_SYS_SINGLE_THREADED_H 1 +# else +# define HAVE_SYS_SINGLE_THREADED_H 0 +# endif +# endif +# ifndef HAVE_SYS_SINGLE_THREADED_H +# if defined __GLIBC__ && 2 < __GLIBC__ + (32 <= __GLIBC_MINOR__) +# define HAVE_SYS_SINGLE_THREADED_H 1 +# else +# define HAVE_SYS_SINGLE_THREADED_H 0 +# endif +# endif +# if HAVE_SYS_SINGLE_THREADED_H +# include <sys/single_threaded.h> +# endif +# endif +# endif + +/* True if the current process might be multi-threaded, + false if it is definitely single-threaded. + If false, it will be false the next time it is called + unless the caller creates a thread in the meantime. + If true, it might become false the next time it is called + if all other threads exit in the meantime. */ +static bool +is_threaded(void) +{ +# if THREAD_PREFER_SINGLE && HAVE___ISTHREADED + return !!__isthreaded; +# elif THREAD_PREFER_SINGLE && HAVE_SYS_SINGLE_THREADED_H + return !__libc_single_threaded; +# else + return true; +# endif +} + +# if THREAD_RWLOCK +static pthread_rwlock_t locallock = PTHREAD_RWLOCK_INITIALIZER; +static int dolock(void) { return pthread_rwlock_rdlock(&locallock); } +static void dounlock(void) { pthread_rwlock_unlock(&locallock); } +# else static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER; -static int lock(void) { return pthread_mutex_lock(&locallock); } -static void unlock(void) { pthread_mutex_unlock(&locallock); } +static int dolock(void) { return pthread_mutex_lock(&locallock); } +static void dounlock(void) { pthread_mutex_unlock(&locallock); } +# endif +/* Get a lock. Return 0 on success, a positive errno value on failure, + negative if known to be single-threaded so no lock is needed. */ +static int +lock(void) +{ + if (!is_threaded()) + return -1; + return dolock(); +} +static void +unlock(bool threaded) +{ + if (threaded) + dounlock(); +} +#else +static int lock(void) { return -1; } +static void unlock(ATTRIBUTE_MAYBE_UNUSED bool threaded) { } +#endif + +/* If THREADED, upgrade a read lock to a write lock. + Return 0 on success, a positive errno value otherwise. */ +static int +rd2wrlock(ATTRIBUTE_MAYBE_UNUSED bool threaded) +{ +#if THREAD_RWLOCK + if (threaded) { + dounlock(); + return pthread_rwlock_wrlock(&locallock); + } +#endif + return 0; +} + +#if THREAD_SAFE +typedef pthread_once_t once_t; +# define ONCE_INIT PTHREAD_ONCE_INIT #else -static int lock(void) { return 0; } -static void unlock(void) { } +typedef bool once_t; +# define ONCE_INIT false #endif +static void +once(once_t *once_control, void init_routine(void)) +{ +#if THREAD_SAFE + pthread_once(once_control, init_routine); +#else + if (!*once_control) { + *once_control = true; + init_routine(); + } +#endif +} + +enum tm_multi { LOCALTIME_TM_MULTI, GMTIME_TM_MULTI, OFFTIME_TM_MULTI }; + +#if THREAD_SAFE && THREAD_TM_MULTI + +enum { N_TM_MULTI = OFFTIME_TM_MULTI + 1 }; +static pthread_key_t tm_multi_key; +static int tm_multi_key_err; + +static void +tm_multi_key_init(void) +{ + tm_multi_key_err = pthread_key_create(&tm_multi_key, free); +} + +#endif + +/* Return TMP, or a thread-specific struct tm * selected by WHICH. */ +static struct tm * +tm_multi(struct tm *tmp, ATTRIBUTE_MAYBE_UNUSED enum tm_multi which) +{ +#if THREAD_SAFE && THREAD_TM_MULTI + /* It is OK to check is_threaded() separately here; even if it + returns a different value in other places in the caller, + this function's behavior is still valid. */ + if (is_threaded()) { + /* Try to get a thread-specific struct tm *. + Fall back on TMP if this fails. */ + static pthread_once_t tm_multi_once = PTHREAD_ONCE_INIT; + pthread_once(&tm_multi_once, tm_multi_key_init); + if (!tm_multi_key_err) { + struct tm *p = pthread_getspecific(tm_multi_key); + if (!p) { + p = malloc(N_TM_MULTI * sizeof *p); + if (p && pthread_setspecific(tm_multi_key, p) != 0) { + free(p); + p = NULL; + } + } + if (p) + return &p[which]; + } + } +#endif + return tmp; +} + /* Unless intptr_t is missing, pacify gcc -Wcast-qual on char const * exprs. Use this carefully, as the casts disable type checking. This is a macro so that it can be used in static initializers. */ @@ -64,6 +244,47 @@ typedef intmax_t iinntt; #endif static_assert(IINNTT_MIN < INT_MIN && INT_MAX < IINNTT_MAX); +#ifndef HAVE_STRUCT_TIMESPEC +# define HAVE_STRUCT_TIMESPEC 1 +#endif +#if !HAVE_STRUCT_TIMESPEC +struct timespec { time_t tv_sec; long tv_nsec; }; +#endif + +#if !defined CLOCK_MONOTONIC_COARSE && defined CLOCK_MONOTONIC +# define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC +#endif +#ifndef CLOCK_MONOTONIC_COARSE +# undef clock_gettime +# define clock_gettime(id, t) ((t)->tv_sec = time(NULL), (t)->tv_nsec = 0, 0) +#endif + +/* How many seconds to wait before checking the default TZif file again. + Negative means no checking. Default to 61 if DETECT_TZ_CHANGES + (as circa 2025 FreeBSD builds its localtime.c with -DDETECT_TZ_CHANGES), + and to -1 otherwise. */ +#ifndef TZ_CHANGE_INTERVAL +# ifdef DETECT_TZ_CHANGES +# define TZ_CHANGE_INTERVAL 61 +# else +# define TZ_CHANGE_INTERVAL (-1) +# endif +#endif +static_assert(TZ_CHANGE_INTERVAL < 0 || HAVE_SYS_STAT_H); + +/* The change detection interval. */ +#if TZ_CHANGE_INTERVAL < 0 || !defined __FreeBSD__ +enum { tz_change_interval = TZ_CHANGE_INTERVAL }; +#else +/* FreeBSD uses this private-but-extern var in its internal test suite. */ +int __tz_change_interval = TZ_CHANGE_INTERVAL; +# define tz_change_interval __tz_change_interval +#endif + +/* The type of monotonic times. + This is the system time_t, even if USE_TIMEX_T #defines time_t below. */ +typedef time_t monotime_t; + /* On platforms where offtime or mktime might overflow, strftime.c defines USE_TIMEX_T to be true and includes us. This tells us to #define time_t to an internal type timex_t that is @@ -82,16 +303,16 @@ static_assert(IINNTT_MIN < INT_MIN && INT_MAX < IINNTT_MAX); # define time_t timex_t # if MKTIME_FITS_IN(LONG_MIN, LONG_MAX) typedef long timex_t; -# define TIME_T_MIN LONG_MIN -# define TIME_T_MAX LONG_MAX +# define TIME_T_MIN LONG_MIN +# define TIME_T_MAX LONG_MAX # elif MKTIME_FITS_IN(LLONG_MIN, LLONG_MAX) typedef long long timex_t; -# define TIME_T_MIN LLONG_MIN -# define TIME_T_MAX LLONG_MAX +# define TIME_T_MIN LLONG_MIN +# define TIME_T_MAX LLONG_MAX # else typedef intmax_t timex_t; -# define TIME_T_MIN INTMAX_MIN -# define TIME_T_MAX INTMAX_MAX +# define TIME_T_MIN INTMAX_MIN +# define TIME_T_MAX INTMAX_MAX # endif # ifdef TM_GMTOFF @@ -104,14 +325,11 @@ typedef intmax_t timex_t; # endif #endif -#ifndef TZ_ABBR_CHAR_SET -# define TZ_ABBR_CHAR_SET \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" -#endif /* !defined TZ_ABBR_CHAR_SET */ - -#ifndef TZ_ABBR_ERR_CHAR -# define TZ_ABBR_ERR_CHAR '_' -#endif /* !defined TZ_ABBR_ERR_CHAR */ +/* Placeholders for platforms lacking openat. */ +#ifndef AT_FDCWD +# define AT_FDCWD (-1) /* any negative value will do */ +static int openat(int dd, char const *path, int oflag) { unreachable (); } +#endif /* Port to platforms that lack some O_* flags. Unless otherwise specified, the flags are standardized by POSIX. */ @@ -125,12 +343,76 @@ typedef intmax_t timex_t; #ifndef O_CLOFORK # define O_CLOFORK 0 #endif +#ifndef O_DIRECTORY +# define O_DIRECTORY 0 +#endif #ifndef O_IGNORE_CTTY # define O_IGNORE_CTTY 0 /* GNU/Hurd */ #endif #ifndef O_NOCTTY # define O_NOCTTY 0 #endif +#ifndef O_PATH +# define O_PATH 0 +#endif +#ifndef O_REGULAR +# define O_REGULAR 0 +#endif +#ifndef O_RESOLVE_BENEATH +# define O_RESOLVE_BENEATH 0 +#endif +#ifndef O_SEARCH +# define O_SEARCH 0 +#endif + +#if !HAVE_ISSETUGID + +# if !defined HAVE_SYS_AUXV_H && defined __has_include +# if __has_include(<sys/auxv.h>) +# define HAVE_SYS_AUXV_H 1 +# endif +# endif +# ifndef HAVE_SYS_AUXV_H +# if defined __GLIBC__ && 2 < __GLIBC__ + (19 <= __GLIBC_MINOR__) +# define HAVE_SYS_AUXV_H 1 +# else +# define HAVE_SYS_AUXV_H 0 +# endif +# endif +# if HAVE_SYS_AUXV_H +# include <sys/auxv.h> +# endif + +/* Return 1 if the process is privileged, 0 otherwise. */ +static int +issetugid(void) +{ +# if HAVE_SYS_AUXV_H && defined AT_SECURE + unsigned long val; + errno = 0; + val = getauxval(AT_SECURE); + if (val || errno != ENOENT) + return !!val; +# endif +# if HAVE_GETRESUID + { + uid_t ruid, euid, suid; + gid_t rgid, egid, sgid; + if (0 <= getresuid (&ruid, &euid, &suid)) { + if ((ruid ^ euid) | (ruid ^ suid)) + return 1; + if (0 <= getresgid (&rgid, &egid, &sgid)) + return !!((rgid ^ egid) | (rgid ^ sgid)); + } + } +# endif +# if HAVE_GETEUID + return geteuid() != getuid() || getegid() != getgid(); +# else + return 0; +# endif +} +#endif #ifndef WILDABBR /* @@ -173,6 +455,26 @@ static char const *utc = etc_utc + sizeof "Etc/" - 1; # define TZDEFRULESTRING ",M3.2.0,M11.1.0" #endif +/* If compiled with -DOPENAT_TZDIR, then when accessing a relative + name like "America/Los_Angeles", first open TZDIR (default + "/usr/share/zoneinfo") as a directory and then use the result in + openat with "America/Los_Angeles", rather than the traditional + approach of opening "/usr/share/zoneinfo/America/Los_Angeles". + Although the OPENAT_TZDIR approach is less efficient, suffers from + spurious EMFILE and ENFILE failures, and is no more secure in practice, + it is how bleeding edge FreeBSD did things from August 2025 + through at least September 2025. */ +#ifndef OPENAT_TZDIR +# define OPENAT_TZDIR 0 +#endif + +/* If compiled with -DSUPPRESS_TZDIR, do not prepend TZDIR to relative TZ. + This is intended for specialized applications only, due to its + security implications. */ +#ifndef SUPPRESS_TZDIR +# define SUPPRESS_TZDIR 0 +#endif + /* Limit to time zone abbreviation length in proleptic TZ strings. This is distinct from TZ_MAX_CHARS, which limits TZif file contents. It defaults to 254, not 255, so that desigidx_type can be an unsigned char. @@ -259,18 +561,22 @@ static struct tm *timesub(time_t const *, int_fast32_t, struct state const *, struct tm *); static bool tzparse(char const *, struct state *, struct state const *); -#ifdef ALL_STATE +#ifndef ALL_STATE +# define ALL_STATE 0 +#endif + +#if ALL_STATE static struct state * lclptr; static struct state * gmtptr; -#endif /* defined ALL_STATE */ - -#ifndef ALL_STATE +#else static struct state lclmem; static struct state gmtmem; static struct state *const lclptr = &lclmem; static struct state *const gmtptr = &gmtmem; #endif /* State Farm */ +/* Maximum number of bytes in an efficiently-handled TZ string. + Longer strings work, albeit less efficiently. */ #ifndef TZ_STRLEN_MAX # define TZ_STRLEN_MAX 255 #endif /* !defined TZ_STRLEN_MAX */ @@ -296,7 +602,7 @@ static int lcl_is_set; # if SUPPORT_C89 static struct tm tm; -#endif +# endif # if 2 <= HAVE_TZNAME + TZ_TIME_T char *tzname[2] = { UNCONST(wildabbr), UNCONST(wildabbr) }; @@ -460,7 +766,7 @@ scrub_abbrs(struct state *sp) /* Reject overlong abbreviations. */ for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) { - int len = strlen(&sp->chars[i]); + int len = strnlen(&sp->chars[i], TZNAME_MAXIMUM + 1); if (TZNAME_MAXIMUM < len) return EOVERFLOW; i += len + 1; @@ -468,14 +774,75 @@ scrub_abbrs(struct state *sp) /* Replace bogus characters. */ for (i = 0; i < sp->charcnt; ++i) - if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) - sp->chars[i] = TZ_ABBR_ERR_CHAR; + switch (sp->chars[i]) { + case '\0': + case '+': case '-': case '.': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case ':': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': + case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'V': case 'W': case 'X': case 'Y': case 'Z': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + break; + + default: + sp->chars[i] = '_'; + break; + } return 0; } #endif +/* Return true if the TZif file with descriptor FD changed, + or may have changed, since the last time we were called. + Return false if it did not change. + If *ST is valid it is the file's current status; + otherwise, update *ST to the status if possible. */ +static bool +tzfile_changed(int fd, struct stat *st) +{ + /* If old_ctim.tv_sec, these variables hold the corresponding part + of the file's metadata the last time this function was called. */ + static struct timespec old_ctim; + static dev_t old_dev; + static ino_t old_ino; + + if (!st->st_ctime && fstat(fd, st) < 0) { + /* We do not know the file's state, so reset. */ + old_ctim.tv_sec = 0; + return true; + } else { + /* Use the change time, as it changes more reliably; mod time can + be set back with futimens etc. Use subsecond timestamp + resolution if available, as this can help distinguish files on + non-POSIX platforms where st_dev and st_ino are unreliable. */ + struct timespec ctim; +#if HAVE_STRUCT_STAT_ST_CTIM + ctim = st->st_ctim; +#else + ctim.tv_sec = st->st_ctime; + ctim.tv_nsec = 0; +#endif + + if ((ctim.tv_sec ^ old_ctim.tv_sec) | (ctim.tv_nsec ^ old_ctim.tv_nsec) + | (st->st_dev ^ old_dev) | (st->st_ino ^ old_ino)) { + old_ctim = ctim; + old_dev = st->st_dev; + old_ino = st->st_ino; + return true; + } + + return false; + } +} + /* Input buffer for data read from a compiled tz file. */ union input_buffer { /* The first part of the buffer, interpreted as a header. */ @@ -487,8 +854,15 @@ union input_buffer { + 4 * TZ_MAX_TIMES]; }; -/* TZDIR with a trailing '/' rather than a trailing '\0'. */ -static char const tzdirslash[sizeof TZDIR] = TZDIR "/"; +/* TZDIR with a trailing '/'. It is null-terminated if OPENAT_TZDIR. */ +#if !OPENAT_TZDIR +ATTRIBUTE_NONSTRING +#endif +static char const tzdirslash[sizeof TZDIR + OPENAT_TZDIR] = TZDIR "/"; +enum { tzdirslashlen = sizeof TZDIR }; +#ifdef PATH_MAX +static_assert(tzdirslashlen <= PATH_MAX); /* Sanity check; assumed below. */ +#endif /* Local storage needed for 'tzloadbody'. */ union local_storage { @@ -501,33 +875,38 @@ union local_storage { struct state st; } u; - /* The name of the file to be opened. Ideally this would have no - size limits, to support arbitrarily long Zone names. - Limiting Zone names to 1024 bytes should suffice for practical use. - However, there is no need for this to be smaller than struct - file_analysis as that struct is allocated anyway, as the other - union member. */ - char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)]; +#if defined PATH_MAX && !OPENAT_TZDIR && !SUPPRESS_TZDIR + /* The name of the file to be opened. */ + char fullname[PATH_MAX]; +#endif }; /* These tzload flags can be ORed together, and fit into 'char'. */ enum { TZLOAD_FROMENV = 1 }; /* The TZ string came from the environment. */ enum { TZLOAD_TZSTRING = 2 }; /* Read any newline-surrounded TZ string. */ +enum { TZLOAD_TZDIR_SUB = 4 }; /* TZ should be a file under TZDIR. */ /* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS. - Use *LSP for temporary storage. Return 0 on + Use **LSPP for temporary storage. Return 0 on success, an errno value on failure. */ static int tzloadbody(char const *name, struct state *sp, char tzloadflags, - union local_storage *lsp) + union local_storage **lspp) { register int i; register int fid; register int stored; register ssize_t nread; - register bool doaccess; - register union input_buffer *up = &lsp->u.u; + char const *relname; + union local_storage *lsp = *lspp; + union input_buffer *up; register int tzheadsize = sizeof(struct tzhead); + int dd = AT_FDCWD; + int oflags = (O_RDONLY | O_BINARY | O_CLOEXEC | O_CLOFORK + | O_IGNORE_CTTY | O_NOCTTY | O_REGULAR); + int err; + struct stat st; + st.st_ctime = 0; sp->goback = sp->goahead = false; @@ -539,66 +918,117 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags, if (name[0] == ':') ++name; -#ifdef SUPPRESS_TZDIR - /* Do not prepend TZDIR. This is intended for specialized - applications only, due to its security implications. */ - doaccess = true; + + relname = name; + + /* If the program is privileged, NAME is TZDEFAULT or + subsidiary to TZDIR. Also, NAME is not a device. */ + if (name[0] == '/' && strcmp(name, TZDEFAULT) != 0) { + if (!SUPPRESS_TZDIR + && strncmp(relname, tzdirslash, tzdirslashlen) == 0) + for (relname += tzdirslashlen; *relname == '/'; relname++) + continue; + else if (issetugid()) + return ENOTCAPABLE; + else if (!O_REGULAR) { + /* Check for devices, as their mere opening could have + unwanted side effects. Though racy, there is no + portable way to fix the races. This check is needed + only for files not otherwise known to be non-devices. */ + if (stat(name, &st) < 0) + return errno; + if (!S_ISREG(st.st_mode)) + return EINVAL; + } + } + + if (relname[0] != '/') { + if (!OPENAT_TZDIR || !O_RESOLVE_BENEATH) { + /* Fail if a relative name contains a non-terminal ".." component, + as such a name could read a non-directory outside TZDIR + when AT_FDCWD and O_RESOLVE_BENEATH are not available. */ + char const *component; + for (component = relname; component[0]; component++) + if (component[0] == '.' && component[1] == '.' + && component[2] == '/' + && (component == relname || component[-1] == '/')) + return ENOTCAPABLE; + } + + if (OPENAT_TZDIR && !SUPPRESS_TZDIR) { + /* Prefer O_SEARCH or O_PATH if available; + O_RDONLY should be OK too, as TZDIR is invariably readable. + O_DIRECTORY should be redundant but might help + on old platforms that mishandle trailing '/'. */ + dd = open(tzdirslash, + ((O_SEARCH ? O_SEARCH : O_PATH ? O_PATH : O_RDONLY) + | O_BINARY | O_CLOEXEC | O_CLOFORK | O_DIRECTORY)); + if (dd < 0) + return errno; + oflags |= O_RESOLVE_BENEATH; + } + } + + if (!OPENAT_TZDIR && !SUPPRESS_TZDIR && name[0] != '/') { + char *cp; + size_t fullnamesize; +#ifdef PATH_MAX + size_t namesizemax = PATH_MAX - tzdirslashlen; + size_t namelen = strnlen (name, namesizemax); + if (namesizemax <= namelen) + return ENAMETOOLONG; #else - doaccess = name[0] == '/'; + size_t namelen = strlen (name); #endif - if (!doaccess) { - char const *dot; - if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name)) - return ENAMETOOLONG; + fullnamesize = tzdirslashlen + namelen + 1; /* Create a string "TZDIR/NAME". Using sprintf here would pull in stdio (and would fail if the resulting string length exceeded INT_MAX!). */ - memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash); - strcpy(lsp->fullname + sizeof tzdirslash, name); - - /* Set doaccess if NAME contains a ".." file name - component, as such a name could read a file outside - the TZDIR virtual subtree. */ - for (dot = name; (dot = strchr(dot, '.')); dot++) - if ((dot == name || dot[-1] == '/') && dot[1] == '.' - && (dot[2] == '/' || !dot[2])) { - doaccess = true; - break; - } - + if (ALL_STATE || sizeof *lsp < fullnamesize) { + lsp = malloc(max(sizeof *lsp, fullnamesize)); + if (!lsp) + return HAVE_MALLOC_ERRNO ? errno : ENOMEM; + *lspp = lsp; + } + cp = mempcpy(lsp, tzdirslash, tzdirslashlen); + cp = mempcpy(cp, name, namelen); + *cp = '\0'; +#if defined PATH_MAX && !OPENAT_TZDIR && !SUPPRESS_TZDIR name = lsp->fullname; - } - if (doaccess && (tzloadflags & TZLOAD_FROMENV)) { - /* Check for security violations and for devices whose mere - opening could have unwanted side effects. Although these - checks are racy, they're better than nothing and there is - no portable way to fix the races. */ - if (access(name, R_OK) < 0) - return errno; -#ifdef S_ISREG - { - struct stat st; - if (stat(name, &st) < 0) - return errno; - if (!S_ISREG(st.st_mode)) - return EINVAL; - } +#else + name = (char *) lsp; #endif } - fid = open(name, (O_RDONLY | O_BINARY | O_CLOEXEC | O_CLOFORK - | O_IGNORE_CTTY | O_NOCTTY)); - if (fid < 0) - return errno; - nread = read(fid, up->buf, sizeof up->buf); - if (nread < tzheadsize) { - int err = nread < 0 ? errno : EINVAL; - close(fid); + fid = OPENAT_TZDIR ? openat(dd, relname, oflags) : open(name, oflags); + err = errno; + if (0 <= dd) + close(dd); + if (fid < 0) return err; + + /* If detecting changes to the the primary TZif file's state and + the file's status is unchanged, save time by returning now. + Otherwise read the file's contents. Close the file either way. */ + if (0 <= tz_change_interval && (tzloadflags & TZLOAD_FROMENV) + && !tzfile_changed(fid, &st)) + err = -1; + else { + if (ALL_STATE && !lsp) { + lsp = malloc(sizeof *lsp); + if (!lsp) + return HAVE_MALLOC_ERRNO ? errno : ENOMEM; + *lspp = lsp; + } + up = &lsp->u.u; + nread = read(fid, up->buf, sizeof up->buf); + err = tzheadsize <= nread ? 0 : nread < 0 ? errno : EINVAL; } - if (close(fid) < 0) - return errno; + close(fid); + if (err) + return err < 0 ? 0 : err; + for (stored = 4; stored <= 8; stored *= 2) { char version = up->tzhead.tzh_version[0]; bool skip_datablock = stored == 4 && version; @@ -792,9 +1222,11 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags, break; } if (! (j < charcnt)) { - int tsabbrlen = strlen(tsabbr); + int tsabbrlen = strnlen(tsabbr, TZ_MAX_CHARS - j); if (j + tsabbrlen < TZ_MAX_CHARS) { - strcpy(sp->chars + j, tsabbr); + char *cp = sp->chars + j; + cp = mempcpy(cp, tsabbr, tsabbrlen); + *cp = '\0'; charcnt = j + tsabbrlen + 1; ts->ttis[i].tt_desigidx = j; gotabbr++; @@ -845,19 +1277,20 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags, static int tzload(char const *name, struct state *sp, char tzloadflags) { -#ifdef ALL_STATE - union local_storage *lsp = malloc(sizeof *lsp); - if (!lsp) { - return HAVE_MALLOC_ERRNO ? errno : ENOMEM; - } else { - int err = tzloadbody(name, sp, tzloadflags, lsp); - free(lsp); - return err; - } + int r; + union local_storage *lsp0; + union local_storage *lsp; +#if ALL_STATE + lsp = NULL; #else union local_storage ls; - return tzloadbody(name, sp, tzloadflags, &ls); + lsp = &ls; #endif + lsp0 = lsp; + r = tzloadbody(name, sp, tzloadflags, &lsp); + if (lsp != lsp0) + free(lsp); + return r; } static const int mon_lengths[2][MONSPERYEAR] = { @@ -1421,12 +1854,11 @@ tzparse(const char *name, struct state *sp, struct state const *basep) } sp->charcnt = charcnt; cp = sp->chars; - memcpy(cp, stdname, stdlen); - cp += stdlen; + cp = mempcpy(cp, stdname, stdlen); *cp++ = '\0'; if (dstlen != 0) { - memcpy(cp, dstname, dstlen); - *(cp + dstlen) = '\0'; + cp = mempcpy(cp, dstname, dstlen); + *cp = '\0'; } return true; } @@ -1440,6 +1872,22 @@ gmtload(struct state *const sp) #if !USE_TIMEX_T || !defined TM_GMTOFF +/* Return true if primary cached time zone data are fresh, + i.e., if this function is known to have recently returned false. + A call is recent if it occurred less than tz_change_interval seconds ago. + NOW should be the current time. */ +static bool +fresh_tzdata(monotime_t now) +{ + /* If nonzero, the time of the last false return. */ + static monotime_t last_checked; + + if (last_checked && now - last_checked < tz_change_interval) + return true; + last_checked = now; + return false; +} + /* Initialize *SP to a value appropriate for the TZ setting NAME. Respect TZLOADFLAGS. Return 0 on success, an errno value on failure. */ @@ -1460,7 +1908,8 @@ zoneinit(struct state *sp, char const *name, char tzloadflags) return 0; } else { int err = tzload(name, sp, tzloadflags); - if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL)) + if (err != 0 && name && name[0] != ':' && !(tzloadflags & TZLOAD_TZDIR_SUB) + && tzparse(name, sp, NULL)) err = 0; if (err == 0) err = scrub_abbrs(sp); @@ -1468,60 +1917,130 @@ zoneinit(struct state *sp, char const *name, char tzloadflags) } } +/* Like tzset(), but in a critical section. + If THREADED && THREAD_RWLOCK the caller has a read lock, + and this function might upgrade it to a write lock. + If WALL, act as if TZ is unset; although always false in this file, + a wrapper .c file's obsolete and ineffective tzsetwall function can use it. + If tz_change_interval is positive the time is NOW; otherwise ignore NOW. */ static void -tzset_unlocked(void) -{ - char const *name = getenv("TZ"); - struct state *sp = lclptr; - int lcl = name ? strlen(name) < sizeof lcl_TZname : -1; - if (lcl < 0 - ? lcl_is_set < 0 - : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0) - return; -# ifdef ALL_STATE +tzset_unlocked(bool threaded, bool wall, monotime_t now) +{ + char const *name; + struct state *sp; + char tzloadflags; + size_t namelen; + bool writing = false; + + for (;;) { + name = wall ? NULL : getenv("TZ"); + sp = lclptr; + tzloadflags = TZLOAD_FROMENV | TZLOAD_TZSTRING; + namelen = sizeof lcl_TZname + 1; /* placeholder for no name */ + + if (name) { + namelen = strnlen(name, sizeof lcl_TZname); + + /* Abbreviate a string like "/usr/share/zoneinfo/America/Los_Angeles" + to its shorter equivalent "America/Los_Angeles". */ + if (!SUPPRESS_TZDIR && tzdirslashlen < namelen + && memcmp(name, tzdirslash, tzdirslashlen) == 0) { + char const *p = name + tzdirslashlen; + while (*p == '/') + p++; + if (*p && *p != ':') { + name = p; + namelen = strnlen(name, sizeof lcl_TZname); + tzloadflags |= TZLOAD_TZDIR_SUB; + } + } + } + + if ((tz_change_interval <= 0 ? tz_change_interval < 0 : fresh_tzdata(now)) + && (name + ? 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0 + : lcl_is_set < 0)) + return; + + if (!THREAD_RWLOCK || writing) + break; + if (rd2wrlock(threaded) != 0) + return; + writing = true; + } + +# if ALL_STATE if (! sp) lclptr = sp = malloc(sizeof *lclptr); # endif if (sp) { - if (zoneinit(sp, name, TZLOAD_FROMENV | TZLOAD_TZSTRING) != 0) { + int err = zoneinit(sp, name, tzloadflags); + if (err != 0) { zoneinit(sp, "", 0); - strcpy(sp->chars, UNSPEC); + /* Abbreviate with "-00" if there was an error. + Do not treat a missing TZDEFAULT file as an error. */ + if (name || err != ENOENT) + strcpy(sp->chars, UNSPEC); + } + if (namelen < sizeof lcl_TZname) { + char *cp = lcl_TZname; + cp = mempcpy(cp, name, namelen); + *cp = '\0'; } - if (0 < lcl) - strcpy(lcl_TZname, name); } settzname(); - lcl_is_set = lcl; + lcl_is_set = (sizeof lcl_TZname > namelen) - (sizeof lcl_TZname < namelen); } #endif +#if !defined TM_GMTOFF || !USE_TIMEX_T + +/* If tz_change_interval is positive, + return the current time as a monotonically nondecreasing value. + Otherwise the return value does not matter. */ +static monotime_t +get_monotonic_time(void) +{ + struct timespec now; + now.tv_sec = 0; + if (0 < tz_change_interval) + clock_gettime(CLOCK_MONOTONIC_COARSE, &now); + return now.tv_sec; +} +#endif + #if !USE_TIMEX_T + void tzset(void) { - if (lock() != 0) + monotime_t now = get_monotonic_time(); + int err = lock(); + if (0 < err) { + errno = err; return; - tzset_unlocked(); - unlock(); + } + tzset_unlocked(!err, false, now); + unlock(!err); } #endif static void -gmtcheck(void) +gmtcheck1(void) { - static bool gmt_is_set; - if (lock() != 0) - return; - if (! gmt_is_set) { -#ifdef ALL_STATE - gmtptr = malloc(sizeof *gmtptr); +#if ALL_STATE + gmtptr = malloc(sizeof *gmtptr); #endif - if (gmtptr) - gmtload(gmtptr); - gmt_is_set = true; - } - unlock(); + if (gmtptr) + gmtload(gmtptr); +} + +static void +gmtcheck(void) +{ + static once_t gmt_once = ONCE_INIT; + once(&gmt_once, gmtcheck1); } #if NETBSD_INSPIRED && !USE_TIMEX_T @@ -1542,10 +2061,25 @@ tzalloc(char const *name) return sp; } +#ifndef FREE_PRESERVES_ERRNO +# if ((defined _POSIX_VERSION && 202405 <= _POSIX_VERSION) \ + || (defined __GLIBC__ && 2 < __GLIBC__ + (33 <= __GLIBC_MINOR__)) \ + || defined __OpenBSD__ || defined __sun) +# define FREE_PRESERVES_ERRNO 1 +# else +# define FREE_PRESERVES_ERRNO 0 +# endif +#endif + void tzfree(timezone_t sp) { + int err; + if (!FREE_PRESERVES_ERRNO) + err = errno; free(sp); + if (!FREE_PRESERVES_ERRNO) + errno = err; } /* @@ -1686,15 +2220,16 @@ localtime_rz(struct state *restrict sp, time_t const *restrict timep, static struct tm * localtime_tzset(time_t const *timep, struct tm *tmp, bool setname) { + monotime_t now = get_monotonic_time(); int err = lock(); - if (err) { + if (0 < err) { errno = err; return NULL; } - if (setname || !lcl_is_set) - tzset_unlocked(); + if (0 <= tz_change_interval || setname || !lcl_is_set) + tzset_unlocked(!err, false, now); tmp = localsub(lclptr, timep, setname, tmp); - unlock(); + unlock(!err); return tmp; } @@ -1704,7 +2239,7 @@ localtime(const time_t *timep) # if !SUPPORT_C89 static struct tm tm; # endif - return localtime_tzset(timep, &tm, true); + return localtime_tzset(timep, tm_multi(&tm, LOCALTIME_TM_MULTI), true); } struct tm * @@ -1756,7 +2291,7 @@ gmtime(const time_t *timep) # if !SUPPORT_C89 static struct tm tm; # endif - return gmtime_r(timep, &tm); + return gmtime_r(timep, tm_multi(&tm, GMTIME_TM_MULTI)); } # if STD_INSPIRED @@ -1765,14 +2300,19 @@ gmtime(const time_t *timep) Callers can instead use localtime_rz with a fixed-offset zone. */ struct tm * -offtime(const time_t *timep, long offset) +offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp) { gmtcheck(); + return gmtsub(gmtptr, timep, offset, tmp); +} +struct tm * +offtime(time_t const *timep, long offset) +{ # if !SUPPORT_C89 static struct tm tm; # endif - return gmtsub(gmtptr, timep, offset, &tm); + return offtime_r(timep, offset, tm_multi(&tm, OFFTIME_TM_MULTI)); } # endif @@ -2020,8 +2560,8 @@ mktmcpy(struct tm *dest, struct tm const *src) static time_t time2sub(struct tm *const tmp, - struct tm *(*funcp)(struct state const *, time_t const *, - int_fast32_t, struct tm *), + struct tm *funcp(struct state const *, time_t const *, + int_fast32_t, struct tm *), struct state const *sp, const int_fast32_t offset, bool *okayp, @@ -2239,8 +2779,8 @@ label: static time_t time2(struct tm * const tmp, - struct tm *(*funcp)(struct state const *, time_t const *, - int_fast32_t, struct tm *), + struct tm *funcp(struct state const *, time_t const *, + int_fast32_t, struct tm *), struct state const *sp, const int_fast32_t offset, bool *okayp) @@ -2258,8 +2798,8 @@ time2(struct tm * const tmp, static time_t time1(struct tm *const tmp, - struct tm *(*funcp)(struct state const *, time_t const *, - int_fast32_t, struct tm *), + struct tm *funcp(struct state const *, time_t const *, + int_fast32_t, struct tm *), struct state const *sp, const int_fast32_t offset) { @@ -2347,15 +2887,16 @@ static time_t mktime(struct tm *tmp) { + monotime_t now = get_monotonic_time(); time_t t; int err = lock(); - if (err) { + if (0 < err) { errno = err; return -1; } - tzset_unlocked(); + tzset_unlocked(!err, false, now); t = mktime_tzname(lclptr, tmp, true); - unlock(); + unlock(!err); return t; } @@ -2464,16 +3005,17 @@ time2posix_z(struct state *sp, time_t t) time_t time2posix(time_t t) { + monotime_t now = get_monotonic_time(); int err = lock(); - if (err) { + if (0 < err) { errno = err; return -1; } - if (!lcl_is_set) - tzset_unlocked(); + if (0 <= tz_change_interval || !lcl_is_set) + tzset_unlocked(!err, false, now); if (lclptr) t = time2posix_z(lclptr, t); - unlock(); + unlock(!err); return t; } @@ -2509,16 +3051,17 @@ posix2time_z(struct state *sp, time_t t) time_t posix2time(time_t t) { + monotime_t now = get_monotonic_time(); int err = lock(); - if (err) { + if (0 < err) { errno = err; return -1; } - if (!lcl_is_set) - tzset_unlocked(); + if (0 <= tz_change_interval || !lcl_is_set) + tzset_unlocked(!err, false, now); if (lclptr) t = posix2time_z(lclptr, t); - unlock(); + unlock(!err); return t; } diff --git a/newctime.3 b/newctime.3 index 9d09e5a55bd9..6b85ec51be68 100644 --- a/newctime.3 +++ b/newctime.3 @@ -246,17 +246,17 @@ includes the following fields: .PP .nf .ta 2n +\w'long tm_gmtoff;nn'u - int tm_sec; /\(** seconds (0\*(en60) \(**/ - int tm_min; /\(** minutes (0\*(en59) \(**/ - int tm_hour; /\(** hours (0\*(en23) \(**/ - int tm_mday; /\(** day of month (1\*(en31) \(**/ - int tm_mon; /\(** month of year (0\*(en11) \(**/ - int tm_year; /\(** year \- 1900 \(**/ - int tm_wday; /\(** day of week (Sunday = 0) \(**/ - int tm_yday; /\(** day of year (0\*(en365) \(**/ - int tm_isdst; /\(** is daylight saving time in effect? \(**/ - char \(**tm_zone; /\(** time zone abbreviation (optional) \(**/ - long tm_gmtoff; /\(** offset from UT in seconds (optional) \(**/ + int tm_sec; /* seconds (0\*(en60) */ + int tm_min; /* minutes (0\*(en59) */ + int tm_hour; /* hours (0\*(en23) */ + int tm_mday; /* day of month (1\*(en31) */ + int tm_mon; /* month of year (0\*(en11) */ + int tm_year; /* year \- 1900 */ + int tm_wday; /* day of week (Sunday = 0) */ + int tm_yday; /* day of year (0\*(en365) */ + int tm_isdst; /* is daylight saving time in effect? */ + char *tm_zone; /* time zone abbreviation (optional) */ + long tm_gmtoff; /* offset from UT in seconds (optional) */ .fi .RE .PP diff --git a/newctime.3.txt b/newctime.3.txt index 82fdf5e69a00..319640b84111 100644 --- a/newctime.3.txt +++ b/newctime.3.txt @@ -36,7 +36,7 @@ SYNOPSIS DESCRIPTION The localtime and gmtime functions convert an integer, pointed to by - clock, and return pointers to "tm" structures, described below. If the + clock, and return pointers to “tm” structures, described below. If the integer is out of range for conversion, these functions return a null pointer. The localtime function corrects for the time zone and any time zone adjustments (such as Daylight Saving Time in the United @@ -77,7 +77,7 @@ DESCRIPTION The difftime function returns the difference between two calendar times, (time1 - time0), expressed in seconds. - The asctime function converts a time value contained in a "tm" + The asctime function converts a time value contained in a “tm” structure to a pointer to a string of the form Thu Nov 24 18:22:48 1986\n\0 Years requiring fewer than four characters are padded with leading @@ -108,18 +108,18 @@ DESCRIPTION should not be freed until after all uses (e.g., by calls to strftime) of the filled-in tm_zone fields. - Declarations of all the functions and externals, and the "tm" + Declarations of all the functions and externals, and the “tm” structure, are in the <time.h> header file. The structure (of type) struct tm includes the following fields: - int tm_sec; /* seconds (0-60) */ - int tm_min; /* minutes (0-59) */ - int tm_hour; /* hours (0-23) */ - int tm_mday; /* day of month (1-31) */ - int tm_mon; /* month of year (0-11) */ + int tm_sec; /* seconds (0–60) */ + int tm_min; /* minutes (0–59) */ + int tm_hour; /* hours (0–23) */ + int tm_mday; /* day of month (1–31) */ + int tm_mon; /* month of year (0–11) */ int tm_year; /* year - 1900 */ int tm_wday; /* day of week (Sunday = 0) */ - int tm_yday; /* day of year (0-365) */ + int tm_yday; /* day of year (0–365) */ int tm_isdst; /* is daylight saving time in effect? */ char *tm_zone; /* time zone abbreviation (optional) */ long tm_gmtoff; /* offset from UT in seconds (optional) */ diff --git a/newstrftime.3 b/newstrftime.3 index e9a382240ed2..182f44f738a3 100644 --- a/newstrftime.3 +++ b/newstrftime.3 @@ -74,7 +74,7 @@ string consists of zero or more conversion specifications and ordinary characters. All ordinary characters are copied directly into the array. A conversion specification consists of a percent sign -.Ql % +.q % and one other character. .PP No more than diff --git a/newstrftime.3.txt b/newstrftime.3.txt index 15f9ec2557fc..33975a25ee3b 100644 --- a/newstrftime.3.txt +++ b/newstrftime.3.txt @@ -18,16 +18,16 @@ DESCRIPTION The format string consists of zero or more conversion specifications and ordinary characters. All ordinary characters are copied directly into the array. A conversion specification consists of a percent sign - and one other character. + “%” and one other character. No more than maxsize bytes are placed into the array. Each conversion specification is replaced by the characters as follows which are then copied into the array. The characters depend on the values of zero or more members of *timeptr as specified by brackets in - the description. If a bracketed member name is followed by "+", + the description. If a bracketed member name is followed by “+”, strftime can use the named member even though POSIX.1-2024 does not - list it; if the name is followed by "-", strftime ignores the member + list it; if the name is followed by “-”, strftime ignores the member even though POSIX.1-2024 lists it which means portable code should set it. For portability, *timeptr should be initialized as if by a successful call to gmtime, localtime, mktime, timegm, or similar @@ -42,50 +42,50 @@ DESCRIPTION %b or %h is replaced by the locale's abbreviated month name. [tm_mon] - %C is replaced by the century (a year divided by 100 and truncated - to an integer) as a decimal number, with at least two digits by + %C is replaced by the century (a year divided by 100 and truncated + to an integer) as a decimal number, with at least two digits by default. [tm_year] - %c is replaced by the locale's appropriate date and time - representation. [tm_year, tm_yday, tm_mon, tm_mday, tm_wday, + %c is replaced by the locale's appropriate date and time + representation. [tm_year, tm_yday, tm_mon, tm_mday, tm_wday, tm_hour, tm_min, tm_sec, tm_gmtoff, tm_zone, tm_isdst-]. - %D is equivalent to %m/%d/%y. Although used in the United States - for current dates, this format is ambiguous elsewhere and for - dates that might involve other centuries. [tm_year, tm_mon, + %D is equivalent to %m/%d/%y. Although used in the United States + for current dates, this format is ambiguous elsewhere and for + dates that might involve other centuries. [tm_year, tm_mon, tm_mday] %d is replaced by the day of the month as a decimal number [01,31]. [tm_mday] - %e is replaced by the day of month as a decimal number [1,31]; + %e is replaced by the day of month as a decimal number [1,31]; single digits are preceded by a blank. [tm_mday] %F is equivalent to %Y-%m-%d (the ISO 8601 date format). [tm_year, tm_mon, tm_mday] - %G is replaced by the ISO 8601 year with century as a decimal - number. This is the year that includes the greater part of the - week. (Monday as the first day of a week). See also the %V + %G is replaced by the ISO 8601 year with century as a decimal + number. This is the year that includes the greater part of the + week. (Monday as the first day of a week). See also the %V conversion specification. [tm_year, tm_yday, tm_wday] - %g is replaced by the ISO 8601 year without century as a decimal + %g is replaced by the ISO 8601 year without century as a decimal number [00,99]. Since it omits the century, it is ambiguous for dates. [tm_year, tm_yday, tm_wday] - %H is replaced by the hour (24-hour clock) as a decimal number + %H is replaced by the hour (24-hour clock) as a decimal number [00,23]. [tm_hour] - %I is replaced by the hour (12-hour clock) as a decimal number + %I is replaced by the hour (12-hour clock) as a decimal number [01,12]. [tm_hour] - %j is replaced by the day of the year as a decimal number + %j is replaced by the day of the year as a decimal number [001,366]. [tm_yday] - %k is replaced by the hour (24-hour clock) as a decimal number + %k is replaced by the hour (24-hour clock) as a decimal number [0,23]; single digits are preceded by a blank. [tm_hour] - %l is replaced by the hour (12-hour clock) as a decimal number + %l is replaced by the hour (12-hour clock) as a decimal number [1,12]; single digits are preceded by a blank. [tm_hour] %M is replaced by the minute as a decimal number [00,59]. [tm_min] @@ -94,7 +94,7 @@ DESCRIPTION %n is replaced by a newline. - %p is replaced by the locale's equivalent of either "AM" or "PM". + %p is replaced by the locale's equivalent of either “AM” or “PM”. [tm_hour] %R is replaced by the time in the format %H:%M. [tm_hour, tm_min] @@ -102,99 +102,99 @@ DESCRIPTION %r is replaced by the locale's representation of 12-hour clock time using AM/PM notation. [tm_hour, tm_min, tm_sec] - %S is replaced by the second as a decimal number [00,60]. The - range of seconds is [00,60] instead of [00,59] to allow for the + %S is replaced by the second as a decimal number [00,60]. The + range of seconds is [00,60] instead of [00,59] to allow for the periodic occurrence of leap seconds. [tm_sec] - %s is replaced by the number of seconds since the Epoch (see - ctime(3)). Although %s is reliable in this implementation, it - can have glitches on other platforms (notably obsolescent - platforms lacking tm_gmtoff or where time_t is no wider than - int), and POSIX allows strftime to set errno to EINVAL or - EOVERFLOW and return 0 if the number of seconds would be - negative or out of range for time_t. Portable code should - therefore format a time_t value directly via something like + %s is replaced by the number of seconds since the Epoch (see + ctime(3)). Although %s is reliable in this implementation, it + can have glitches on other platforms (notably obsolescent + platforms lacking tm_gmtoff or where time_t is no wider than + int), and POSIX allows strftime to set errno to EINVAL or + EOVERFLOW and return 0 if the number of seconds would be + negative or out of range for time_t. Portable code should + therefore format a time_t value directly via something like sprintf instead of via localtime followed by strftime with "%s". - [tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_gmtoff+, + [tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_gmtoff+, tm_isdst-]. - %T is replaced by the time in the format %H:%M:%S. [tm_hour, + %T is replaced by the time in the format %H:%M:%S. [tm_hour, tm_min, tm_sec] %t is replaced by a tab. - %U is replaced by the week number of the year (Sunday as the first - day of the week) as a decimal number [00,53]. [tm_wday, + %U is replaced by the week number of the year (Sunday as the first + day of the week) as a decimal number [00,53]. [tm_wday, tm_yday, tm_year-] %u is replaced by the weekday (Monday as the first day of the week) as a decimal number [1,7]. [tm_wday] - %V is replaced by the week number of the year (Monday as the first - day of the week) as a decimal number [01,53]. If the week + %V is replaced by the week number of the year (Monday as the first + day of the week) as a decimal number [01,53]. If the week containing January 1 has four or more days in the new year, then - it is week 1; otherwise it is week 53 of the previous year, and + it is week 1; otherwise it is week 53 of the previous year, and the next week is week 1. The year is given by the %G conversion specification. [tm_year, tm_yday, tm_wday] - %W is replaced by the week number of the year (Monday as the first - day of the week) as a decimal number [00,53]. [tm_yday, + %W is replaced by the week number of the year (Monday as the first + day of the week) as a decimal number [00,53]. [tm_yday, tm_wday] %w is replaced by the weekday (Sunday as the first day of the week) as a decimal number [0,6]. [tm_year, tm_yday, tm_wday] - %X is replaced by the locale's appropriate time representation. - [tm_year-, tm_yday-, tm_mon-, tm_mday-, tm_wday-, tm_hour, + %X is replaced by the locale's appropriate time representation. + [tm_year-, tm_yday-, tm_mon-, tm_mday-, tm_wday-, tm_hour, tm_min, tm_sec, tm_gmtoff, tm_zone, tm_isdst-]. - %x is replaced by the locale's appropriate date representation. - This format can be ambiguous for dates, e.g., it can generate + %x is replaced by the locale's appropriate date representation. + This format can be ambiguous for dates, e.g., it can generate "01/02/03" in the C locale. [tm_year, tm_yday, tm_mon, tm_mday, - tm_wday, tm_hour-, tm_min-, tm_sec-, tm_gmtoff-, tm_zone-, + tm_wday, tm_hour-, tm_min-, tm_sec-, tm_gmtoff-, tm_zone-, tm_isdst-]. - %Y is replaced by the year with century as a decimal number. + %Y is replaced by the year with century as a decimal number. [tm_year] - %y is replaced by the year without century as a decimal number + %y is replaced by the year without century as a decimal number [00,99]. Since it omits the century, it is ambiguous for dates. [tm_year] - %Z is replaced by the time zone abbreviation, or by the empty + %Z is replaced by the time zone abbreviation, or by the empty string if this is not determinable. [tm_zone, tm_isdst-] - %z is replaced by the offset from the Prime Meridian in the format - +HHMM or -HHMM (ISO 8601) as appropriate, with positive values + %z is replaced by the offset from the Prime Meridian in the format + +HHMM or -HHMM (ISO 8601) as appropriate, with positive values representing locations east of Greenwich, or by the empty string if this is not determinable. The numeric time zone abbreviation - -0000 is used when the time is Universal Time but local time is - indeterminate; by convention this is used for locations while + -0000 is used when the time is Universal Time but local time is + indeterminate; by convention this is used for locations while uninhabited, and corresponds to a zero offset when the time zone - abbreviation begins with "-". [tm_gmtoff, tm_zone+, tm_isdst-] + abbreviation begins with “-”. [tm_gmtoff, tm_zone+, tm_isdst-] %% is replaced by a single %. - %+ is replaced by the locale's date and time in date(1) format. - [tm_year, tm_yday, tm_mon, tm_mday, tm_wday, tm_hour, tm_min, + %+ is replaced by the locale's date and time in date(1) format. + [tm_year, tm_yday, tm_mon, tm_mday, tm_wday, tm_hour, tm_min, tm_sec, tm_gmtoff, tm_zone] - As a side effect, strftime also behaves as if tzset were called. This - is for compatibility with older platforms, as required by POSIX; it is + As a side effect, strftime also behaves as if tzset were called. This + is for compatibility with older platforms, as required by POSIX; it is not needed for strftime's own use. RETURN VALUE - If the conversion is successful, strftime returns the number of bytes - placed into the array, not counting the terminating NUL; errno is - unchanged if the returned value is zero. Otherwise, errno is set to - indicate the error, zero is returned, and the array contents are + If the conversion is successful, strftime returns the number of bytes + placed into the array, not counting the terminating NUL; errno is + unchanged if the returned value is zero. Otherwise, errno is set to + indicate the error, zero is returned, and the array contents are unspecified. ERRORS This function fails if: [ERANGE] - The total number of resulting bytes, including the terminating + The total number of resulting bytes, including the terminating NUL character, is more than maxsize. SEE ALSO diff --git a/newtzset.3 b/newtzset.3 index db6bfa7fa64c..028cfd2563e3 100644 --- a/newtzset.3 +++ b/newtzset.3 @@ -13,7 +13,7 @@ tzset \- initialize time conversion information .PP .B void tzset(void); .PP -/\(** Optional and obsolescent: \(**/ +/* Optional and obsolescent: */ .br .B extern char *tzname[]; .br @@ -78,7 +78,17 @@ contents are used as a pathname, a pathname beginning with is used as-is; otherwise the pathname is relative to a system time conversion information directory. -The file must be in the format specified in +In a privileged program the pathname must be relative. +Relative pathnames must not contain +.q "..\&" +components. +For the purpose of these checks, a file name beginning with +.q "/" +is considered to be relative if it is the +.B localtime +file's name, or if it starts with the +system timezone directory's name followed by one more more slashes. +The file must be a regular file in the format specified in .BR tzfile (5). .PP When @@ -369,6 +379,10 @@ If successful, the function returns a nonnull pointer to the newly allocated object. Otherwise, it returns a null pointer and sets .IR errno . +The +.B tzfree +function does not modify +.IR errno . .SH ERRORS .TP .B EOVERFLOW diff --git a/newtzset.3.txt b/newtzset.3.txt index e86b64ee9cca..b0d929948bb8 100644 --- a/newtzset.3.txt +++ b/newtzset.3.txt @@ -41,10 +41,15 @@ DESCRIPTION information, and, if that file cannot be read, is used directly as a specification of the time conversion information. - When TZ contents are used as a pathname, a pathname beginning with "/" + When TZ contents are used as a pathname, a pathname beginning with “/” is used as-is; otherwise the pathname is relative to a system time - conversion information directory. The file must be in the format - specified in tzfile(5). + conversion information directory. In a privileged program the pathname + must be relative. Relative pathnames must not contain “..” components. + For the purpose of these checks, a file name beginning with “/” is + considered to be relative if it is the localtime file's name, or if it + starts with the system timezone directory's name followed by one more + more slashes. The file must be a regular file in the format specified + in tzfile(5). When TZ is used directly as a specification of the time conversion information, it must have the following syntax: @@ -54,157 +59,157 @@ DESCRIPTION Where: std and dst - Three or more bytes that are the designation for the - standard (std) or the alternative (dst, such as daylight - saving time) time zone. Only std is required; if dst is + Three or more bytes that are the designation for the + standard (std) or the alternative (dst, such as daylight + saving time) time zone. Only std is required; if dst is missing, then daylight saving time does not apply in this - locale. Upper- and lowercase letters are explicitly - allowed. Any characters except a leading colon (:), - digits, comma (,), ASCII minus (-), ASCII plus (+), and - NUL bytes are allowed. Alternatively, a designation can - be surrounded by angle brackets < and >; in this case, - the designation can contain any characters other than > + locale. Upper- and lowercase letters are explicitly + allowed. Any characters except a leading colon (:), + digits, comma (,), ASCII minus (-), ASCII plus (+), and + NUL bytes are allowed. Alternatively, a designation can + be surrounded by angle brackets < and >; in this case, + the designation can contain any characters other than > and NUL. - offset Indicates the value one must add to the local time to + offset Indicates the value one must add to the local time to arrive at Coordinated Universal Time. The offset has the form: hh[:mm[:ss]] The minutes (mm) and seconds (ss) are optional. The hour - (hh) is required and may be a single digit. The offset - following std is required. If no offset follows dst, - daylight saving time is assumed to be one hour ahead of + (hh) is required and may be a single digit. The offset + following std is required. If no offset follows dst, + daylight saving time is assumed to be one hour ahead of standard time. One or more digits may be used; the value is always interpreted as a decimal number. The hour must - be between zero and 24, and the minutes (and seconds) - - if present - between zero and 59. If preceded by a "-", - the time zone shall be east of the Prime Meridian; - otherwise it shall be west (which may be indicated by an - optional preceding "+". + be between zero and 24, and the minutes (and seconds) – + if present – between zero and 59. If preceded by a “-”, + the time zone shall be east of the Prime Meridian; + otherwise it shall be west (which may be indicated by an + optional preceding “+”. rule Indicates when to change to and back from daylight saving time. The rule has the form: date/time,date/time - where the first date describes when the change from - standard to daylight saving time occurs and the second - date describes when the change back happens. Each time - field describes when, in current local time, the change + where the first date describes when the change from + standard to daylight saving time occurs and the second + date describes when the change back happens. Each time + field describes when, in current local time, the change to the other time is made. 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 + ends December 31 at 24:00 plus the difference between + daylight saving and standard time, leaving no room for standard time in the calendar. The format of date is one of the following: - Jn The Julian day n (1 <= n <= 365). Leap days are - not counted; that is, in all years - including - leap years - February 28 is day 59 and March 1 is - day 60. It is impossible to explicitly refer to - the occasional February 29. + Jn The Julian day n (1 ≤ n ≤ 365). Leap days are not + counted; that is, in all years – including leap + years – February 28 is day 59 and March 1 is day + 60. It is impossible to explicitly refer to the + occasional February 29. - n The zero-based Julian day (0 <= n <= 365). Leap - days are counted, and it is possible to refer to + n The zero-based Julian day (0 ≤ n ≤ 365). Leap + days are counted, and it is possible to refer to February 29. - Mm.n.d The d'th day (0 <= d <= 6) of week n of month m of - the year (1 <= n <= 5, 1 <= m <= 12, where week 5 - means "the last d day in month m" which may occur - in either the fourth or the fifth week). Week 1 - is the first week in which the d'th day occurs. + Mm.n.d The d'th day (0 ≤ d ≤ 6) of week n of month m of + the year (1 ≤ n ≤ 5, 1 ≤ m ≤ 12, where week 5 + means “the last d day in month m” which may occur + in either the fourth or the fifth week). Week 1 + is the first week in which the d'th day occurs. Day zero is Sunday. - The time has the same format as offset except that the - hours part of time can range from -167 through 167; this - allows for unusual rules such as "the Saturday before the - first Sunday of March". The default, if time is not + The time has the same format as offset except that the + hours part of time can range from -167 through 167; this + allows for unusual rules such as “the Saturday before the + first Sunday of March”. The default, if time is not given, is 02:00:00. Here are some examples of TZ values that directly specify the timezone. - EST5 stands for US Eastern Standard Time (EST), 5 hours behind UT, + EST5 stands for US Eastern Standard Time (EST), 5 hours behind UT, without daylight saving. <+12>-12<+13>,M11.1.0,M1.2.1/147 stands for Fiji time, 12 hours ahead of UT, springing forward on - November's first Sunday at 02:00, and falling back on January's - second Monday at 147:00 (i.e., 03:00 on the first Sunday on or - after January 14). The abbreviations for standard and daylight - saving time are "+12" and "+13". + November's first Sunday at 02:00, and falling back on January's + second Monday at 147:00 (i.e., 03:00 on the first Sunday on or + after January 14). The abbreviations for standard and daylight + saving time are “+12” and “+13”. IST-2IDT,M3.4.4/26,M10.5.0 - stands for Israel Standard Time (IST) and Israel Daylight Time - (IDT), 2 hours ahead of UT, springing forward on March's fourth - Thursday at 26:00 (i.e., 02:00 on the first Friday on or after + stands for Israel Standard Time (IST) and Israel Daylight Time + (IDT), 2 hours ahead of UT, springing forward on March's fourth + Thursday at 26:00 (i.e., 02:00 on the first Friday on or after March 23), and falling back on October's last Sunday at 02:00. <-04>4<-03>,J1/0,J365/25 - stands for permanent daylight saving time, 3 hours behind UT - with abbreviation "-03". There is a dummy fall-back transition - on December 31 at 25:00 daylight saving time (i.e., 24:00 - standard time, equivalent to January 1 at 00:00 standard time), - and a simultaneous spring-forward transition on January 1 at - 00:00 standard time, so daylight saving time is in effect all + stands for permanent daylight saving time, 3 hours behind UT + with abbreviation “-03”. There is a dummy fall-back transition + on December 31 at 25:00 daylight saving time (i.e., 24:00 + standard time, equivalent to January 1 at 00:00 standard time), + and a simultaneous spring-forward transition on January 1 at + 00:00 standard time, so daylight saving time is in effect all year and the initial <-04> is a placeholder. <-03>3<-02>,M3.5.0/-2,M10.5.0/-1 - stands for time in western Greenland, 3 hours behind UT, where - clocks follow the EU rules of springing forward on March's last - Sunday at 01:00 UT (-02:00 local time, i.e., 22:00 the previous - day) and falling back on October's last Sunday at 01:00 UT - (-01:00 local time, i.e., 23:00 the previous day). The - abbreviations for standard and daylight saving time are "-03" - and "-02". - - If TZ specifies daylight saving time but does not specify a rule, and - the optional tzfile(5)-format file posixrules is present in the system - time conversion information directory, the rules in posixrules are - used, with the posixrules standard and daylight saving time offsets - from UT replaced by those specified by the offset values in TZ. - However, the posixrules file is obsolete: if it is present it is only - for backward compatibility, and it does not work reliably. Therefore, + stands for time in western Greenland, 3 hours behind UT, where + clocks follow the EU rules of springing forward on March's last + Sunday at 01:00 UT (-02:00 local time, i.e., 22:00 the previous + day) and falling back on October's last Sunday at 01:00 UT + (-01:00 local time, i.e., 23:00 the previous day). The + abbreviations for standard and daylight saving time are “-03” + and “-02”. + + If TZ specifies daylight saving time but does not specify a rule, and + the optional tzfile(5)-format file posixrules is present in the system + time conversion information directory, the rules in posixrules are + used, with the posixrules standard and daylight saving time offsets + from UT replaced by those specified by the offset values in TZ. + However, the posixrules file is obsolete: if it is present it is only + for backward compatibility, and it does not work reliably. Therefore, if a TZ string directly specifies a timezone with daylight saving time, it should specify the daylight saving rules explicitly. - For compatibility with System V Release 3.1, a semicolon (;) may be - used to separate the rule from the rest of the specification; this is + For compatibility with System V Release 3.1, a semicolon (;) may be + used to separate the rule from the rest of the specification; this is an extension to POSIX. - The tzfree function frees a timezone object tz, which should have been - successfully allocated by tzalloc. This invalidates any tm_zone + The tzfree function frees a timezone object tz, which should have been + successfully allocated by tzalloc. This invalidates any tm_zone pointers that tz was used to set. The tzset function acts like tzalloc(getenv("TZ")), except it saves any - resulting timezone object into internal storage that is accessed by - localtime, localtime_r, and mktime. The anonymous shared timezone - object is freed by the next call to tzset. If the implied call to - getenv fails, tzset acts like tzalloc(nullptr); if the implied call to + resulting timezone object into internal storage that is accessed by + localtime, localtime_r, and mktime. The anonymous shared timezone + object is freed by the next call to tzset. If the implied call to + getenv fails, tzset acts like tzalloc(nullptr); if the implied call to tzalloc fails, tzset falls back on UT. - As a side effect, the tzset function sets some external variables if + As a side effect, the tzset function sets some external variables if the platform defines them. It sets tzname[0] and tzname[1] to pointers - to strings that are time zone abbreviations to be used with standard - and daylight saving time, respectively. It also sets timezone to be + to strings that are time zone abbreviations to be used with standard + and daylight saving time, respectively. It also sets timezone to be the number of seconds that standard time is west of the Prime Meridian, - and daylight to be zero if daylight saving time is never in effect, + and daylight to be zero if daylight saving time is never in effect, non-zero otherwise. RETURN VALUE - If successful, the tzalloc function returns a nonnull pointer to the - newly allocated object. Otherwise, it returns a null pointer and sets - errno. + If successful, the tzalloc function returns a nonnull pointer to the + newly allocated object. Otherwise, it returns a null pointer and sets + errno. The tzfree function does not modify errno. ERRORS EOVERFLOW - TZ directly specifies time conversion information, and contains + TZ directly specifies time conversion information, and contains an integer out of machine range or a time zone abbreviation that is too long for this platform. - The tzalloc function may also fail and set errno for any of the errors + The tzalloc function may also fail and set errno for any of the errors specified for the routines access(2), close(2), malloc(3), open(2), and read(2). @@ -214,7 +219,7 @@ FILES /usr/share/zoneinfo/posixrules default DST rules (obsolete) /usr/share/zoneinfo/GMT for UTC leap seconds - If /usr/share/zoneinfo/GMT is absent, UTC leap seconds are loaded from + If /usr/share/zoneinfo/GMT is absent, UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present. SEE ALSO @@ -223,11 +228,11 @@ SEE ALSO NOTES Portable code should not rely on the contents of the external variables tzname, timezone and daylight as their contents are unspecified (and do - not make sense in general) when a geographical TZ is used. In + not make sense in general) when a geographical TZ is used. In multithreaded applications behavior is undefined if one thread accesses - one of these variables while another thread invokes tzset. A future - version of POSIX is planned to remove these variables; callers can - instead use the tm_gmtoff and tm_zone members of struct tm, or use + one of these variables while another thread invokes tzset. A future + version of POSIX is planned to remove these variables; callers can + instead use the tm_gmtoff and tm_zone members of struct tm, or use strftime with "%z" or "%Z". Time Zone Database newtzset(3) diff --git a/private.h b/private.h index 0a546e02e8eb..074da284b7db 100644 --- a/private.h +++ b/private.h @@ -82,8 +82,9 @@ # include <stdbool.h> #endif -#if __STDC_VERSION__ < 202311 -# undef static_assert +/* For pre-C23 compilers, a substitute for static_assert. + Some of these compilers may warn if it is used outside the top level. */ +#if __STDC_VERSION__ < 202311 && !defined static_assert # define static_assert(cond) extern int static_assert_check[(cond) ? 1 : -1] #endif @@ -98,7 +99,9 @@ #endif /* This string was in the Factory zone through version 2016f. */ -#define GRANDPARENTED "Local time zone must be set--see zic manual page" +#ifndef GRANDPARENTED +# define GRANDPARENTED "Local time zone must be set--see zic manual page" +#endif /* ** Defaults for preprocessor symbols. @@ -118,6 +121,14 @@ # define HAVE__GENERIC (201112 <= __STDC_VERSION__) #endif +#ifndef HAVE_GETEUID +# define HAVE_GETEUID 1 +#endif + +#ifndef HAVE_GETRESUID +# define HAVE_GETRESUID 1 +#endif + #if !defined HAVE_GETTEXT && defined __has_include # if __has_include(<libintl.h>) # define HAVE_GETTEXT 1 @@ -186,33 +197,36 @@ ** Nested includes */ -/* Avoid clashes with NetBSD by renaming NetBSD's declarations. - If defining the 'timezone' variable, avoid a clash with FreeBSD's - 'timezone' function by renaming its declaration. */ -#define localtime_rz sys_localtime_rz -#define mktime_z sys_mktime_z -#define posix2time_z sys_posix2time_z -#define time2posix_z sys_time2posix_z -#if defined USG_COMPAT && USG_COMPAT == 2 +#include <stddef.h> + +/* If defining the 'timezone' variable a la POSIX, avoid clashing with the old + 'timezone' function of FreeBSD <= 14, by renaming the latter's declaration. + This hack can be removed after 2028-11-30, FreeBSD 14's expected EOL. */ +#if (defined __FreeBSD__ && __FreeBSD__ < 15 && defined __BSD_VISIBLE \ + && defined USG_COMPAT && USG_COMPAT == 2) # define timezone sys_timezone +# define timezone_defined #endif -#define timezone_t sys_timezone_t -#define tzalloc sys_tzalloc -#define tzfree sys_tzfree + #include <time.h> -#undef localtime_rz -#undef mktime_z -#undef posix2time_z -#undef time2posix_z -#if defined USG_COMPAT && USG_COMPAT == 2 + +#ifdef timezone_defined # undef timezone +# undef timezone_defined #endif -#undef timezone_t -#undef tzalloc -#undef tzfree -#include <stddef.h> #include <string.h> +#if defined HAVE_STRNLEN && !HAVE_STRNLEN +static size_t +strnlen (char const *s, size_t maxlen) +{ + size_t i; + for (i = 0; i < maxlen && s[i]; i++) + continue; + return i; +} +#endif + #if !PORT_TO_C89 # include <inttypes.h> #endif @@ -234,6 +248,9 @@ #ifndef ENOMEM # define ENOMEM EINVAL #endif +#ifndef ENOTCAPABLE +# define ENOTCAPABLE EINVAL +#endif #ifndef ENOTSUP # define ENOTSUP EINVAL #endif @@ -246,7 +263,12 @@ #endif /* HAVE_GETTEXT */ #if HAVE_UNISTD_H -# include <unistd.h> /* for R_OK, and other POSIX goodness */ +# include <unistd.h> +#else +/* Assume getopt.o or equivalent is linked via Makefile configuration. */ +int getopt(int, char *const[], char const *); +extern char *optarg; +extern int optind; #endif /* HAVE_UNISTD_H */ /* SUPPORT_POSIX2008 means the tzcode library should support @@ -274,6 +296,16 @@ # endif #endif +#ifndef HAVE_ISSETUGID +# if (defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ + || (defined __linux__ && !defined __GLIBC__) /* Android, musl, etc. */ \ + || (defined __APPLE__ && defined __MACH__) || defined __sun) +# define HAVE_ISSETUGID 1 +# else +# define HAVE_ISSETUGID 0 +# endif +#endif + #ifndef HAVE_SNPRINTF # define HAVE_SNPRINTF (!PORT_TO_C89 || 199901 <= __STDC_VERSION__) #endif @@ -310,10 +342,6 @@ # endif #endif -#ifndef R_OK -# define R_OK 4 -#endif /* !defined R_OK */ - #if PORT_TO_C89 /* @@ -322,150 +350,150 @@ ** previously included files. glibc 2.1 and Solaris 10 and later have ** stdint.h, even with pre-C99 compilers. */ -#if !defined HAVE_STDINT_H && defined __has_include -# define HAVE_STDINT_H 1 /* C23 __has_include implies C99 stdint.h. */ -#endif -#ifndef HAVE_STDINT_H -# define HAVE_STDINT_H \ - (199901 <= __STDC_VERSION__ \ - || 2 < __GLIBC__ + (1 <= __GLIBC_MINOR__) \ - || __CYGWIN__ || INTMAX_MAX) -#endif /* !defined HAVE_STDINT_H */ - -#if HAVE_STDINT_H -# include <stdint.h> -#endif /* !HAVE_STDINT_H */ - -#ifndef HAVE_INTTYPES_H -# define HAVE_INTTYPES_H HAVE_STDINT_H -#endif -#if HAVE_INTTYPES_H -# include <inttypes.h> -#endif - -/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */ -#if defined __LONG_LONG_MAX__ && !defined __STRICT_ANSI__ -# ifndef LLONG_MAX -# define LLONG_MAX __LONG_LONG_MAX__ +# if !defined HAVE_STDINT_H && defined __has_include +# define HAVE_STDINT_H 1 /* C23 __has_include implies C99 stdint.h. */ # endif -# ifndef LLONG_MIN -# define LLONG_MIN (-1 - LLONG_MAX) +# ifndef HAVE_STDINT_H +# define HAVE_STDINT_H \ + (199901 <= __STDC_VERSION__ \ + || 2 < __GLIBC__ + (1 <= __GLIBC_MINOR__) \ + || __CYGWIN__ || INTMAX_MAX) +# endif /* !defined HAVE_STDINT_H */ + +# if HAVE_STDINT_H +# include <stdint.h> +# endif /* !HAVE_STDINT_H */ + +# ifndef HAVE_INTTYPES_H +# define HAVE_INTTYPES_H HAVE_STDINT_H # endif -# ifndef ULLONG_MAX -# define ULLONG_MAX (LLONG_MAX * 2ull + 1) +# if HAVE_INTTYPES_H +# include <inttypes.h> # endif -#endif -#ifndef INT_FAST64_MAX -# if 1 <= LONG_MAX >> 31 >> 31 +/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */ +# if defined __LONG_LONG_MAX__ && !defined __STRICT_ANSI__ +# ifndef LLONG_MAX +# define LLONG_MAX __LONG_LONG_MAX__ +# endif +# ifndef LLONG_MIN +# define LLONG_MIN (-1 - LLONG_MAX) +# endif +# ifndef ULLONG_MAX +# define ULLONG_MAX (LLONG_MAX * 2ull + 1) +# endif +# endif + +# ifndef INT_FAST64_MAX +# if 1 <= LONG_MAX >> 31 >> 31 typedef long int_fast64_t; -# define INT_FAST64_MIN LONG_MIN -# define INT_FAST64_MAX LONG_MAX -# else +# define INT_FAST64_MIN LONG_MIN +# define INT_FAST64_MAX LONG_MAX +# else /* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */ typedef long long int_fast64_t; -# define INT_FAST64_MIN LLONG_MIN -# define INT_FAST64_MAX LLONG_MAX +# define INT_FAST64_MIN LLONG_MIN +# define INT_FAST64_MAX LLONG_MAX +# endif # endif -#endif -#ifndef PRIdFAST64 -# if INT_FAST64_MAX == LONG_MAX -# define PRIdFAST64 "ld" -# else -# define PRIdFAST64 "lld" +# ifndef PRIdFAST64 +# if INT_FAST64_MAX == LONG_MAX +# define PRIdFAST64 "ld" +# else +# define PRIdFAST64 "lld" +# endif # endif -#endif -#ifndef SCNdFAST64 -# define SCNdFAST64 PRIdFAST64 -#endif +# ifndef SCNdFAST64 +# define SCNdFAST64 PRIdFAST64 +# endif -#ifndef INT_FAST32_MAX -# if INT_MAX >> 31 == 0 +# ifndef INT_FAST32_MAX +# if INT_MAX >> 31 == 0 typedef long int_fast32_t; -# define INT_FAST32_MAX LONG_MAX -# define INT_FAST32_MIN LONG_MIN -# else +# define INT_FAST32_MAX LONG_MAX +# define INT_FAST32_MIN LONG_MIN +# else typedef int int_fast32_t; -# define INT_FAST32_MAX INT_MAX -# define INT_FAST32_MIN INT_MIN +# define INT_FAST32_MAX INT_MAX +# define INT_FAST32_MIN INT_MIN +# endif # endif -#endif -#ifndef INT_LEAST32_MAX +# ifndef INT_LEAST32_MAX typedef int_fast32_t int_least32_t; -#endif +# endif -#ifndef INTMAX_MAX -# ifdef LLONG_MAX +# ifndef INTMAX_MAX +# ifdef LLONG_MAX typedef long long intmax_t; -# ifndef HAVE_STRTOLL -# define HAVE_STRTOLL 1 +# ifndef HAVE_STRTOLL +# define HAVE_STRTOLL 1 +# endif +# if HAVE_STRTOLL +# define strtoimax strtoll +# endif +# define INTMAX_MAX LLONG_MAX +# define INTMAX_MIN LLONG_MIN +# else +typedef long intmax_t; +# define INTMAX_MAX LONG_MAX +# define INTMAX_MIN LONG_MIN # endif -# if HAVE_STRTOLL -# define strtoimax strtoll +# ifndef strtoimax +# define strtoimax strtol # endif -# define INTMAX_MAX LLONG_MAX -# define INTMAX_MIN LLONG_MIN -# else -typedef long intmax_t; -# define INTMAX_MAX LONG_MAX -# define INTMAX_MIN LONG_MIN -# endif -# ifndef strtoimax -# define strtoimax strtol # endif -#endif -#ifndef PRIdMAX -# if INTMAX_MAX == LLONG_MAX -# define PRIdMAX "lld" -# else -# define PRIdMAX "ld" +# ifndef PRIdMAX +# if INTMAX_MAX == LLONG_MAX +# define PRIdMAX "lld" +# else +# define PRIdMAX "ld" +# endif # endif -#endif -#ifndef PTRDIFF_MAX -# define PTRDIFF_MAX MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t)) -#endif +# ifndef PTRDIFF_MAX +# define PTRDIFF_MAX MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t)) +# endif -#ifndef UINT_FAST32_MAX +# ifndef UINT_FAST32_MAX typedef unsigned long uint_fast32_t; -#endif +# endif -#ifndef UINT_FAST64_MAX -# if 3 <= ULONG_MAX >> 31 >> 31 +# ifndef UINT_FAST64_MAX +# if 3 <= ULONG_MAX >> 31 >> 31 typedef unsigned long uint_fast64_t; -# define UINT_FAST64_MAX ULONG_MAX -# else +# define UINT_FAST64_MAX ULONG_MAX +# else /* If this fails, compile with -DHAVE_STDINT_H or with a better compiler. */ typedef unsigned long long uint_fast64_t; -# define UINT_FAST64_MAX ULLONG_MAX +# define UINT_FAST64_MAX ULLONG_MAX +# endif # endif -#endif -#ifndef UINTMAX_MAX -# ifdef ULLONG_MAX +# ifndef UINTMAX_MAX +# ifdef ULLONG_MAX typedef unsigned long long uintmax_t; -# define UINTMAX_MAX ULLONG_MAX -# else +# define UINTMAX_MAX ULLONG_MAX +# else typedef unsigned long uintmax_t; -# define UINTMAX_MAX ULONG_MAX +# define UINTMAX_MAX ULONG_MAX +# endif # endif -#endif -#ifndef PRIuMAX -# ifdef ULLONG_MAX -# define PRIuMAX "llu" -# else -# define PRIuMAX "lu" +# ifndef PRIuMAX +# ifdef ULLONG_MAX +# define PRIuMAX "llu" +# else +# define PRIuMAX "lu" +# endif # endif -#endif -#ifndef SIZE_MAX -# define SIZE_MAX ((size_t) -1) -#endif +# ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +# endif #endif /* PORT_TO_C89 */ @@ -513,6 +541,12 @@ typedef unsigned long uintmax_t; # define HAVE___HAS_C_ATTRIBUTE false #endif +#if 8 <= __GNUC__ +# define ATTRIBUTE_NONSTRING __attribute__((__nonstring__)) +#else +# define ATTRIBUTE_NONSTRING +#endif + #if HAVE___HAS_C_ATTRIBUTE # if __has_c_attribute(deprecated) # define ATTRIBUTE_DEPRECATED [[deprecated]] @@ -684,6 +718,8 @@ typedef time_tz tz_time_t; # define mktime_z tz_mktime_z # undef offtime # define offtime tz_offtime +# undef offtime_r +# define offtime_r tz_offtime_r # undef posix2time # define posix2time tz_posix2time # undef posix2time_z @@ -742,10 +778,10 @@ typedef time_tz tz_time_t; # endif DEPRECATED_IN_C23 char *asctime(struct tm const *); DEPRECATED_IN_C23 char *ctime(time_t const *); -#if SUPPORT_POSIX2008 +# if SUPPORT_POSIX2008 char *asctime_r(struct tm const *restrict, char *restrict); char *ctime_r(time_t const *, char *); -#endif +# endif ATTRIBUTE_CONST double difftime(time_t, time_t); size_t strftime(char *restrict, size_t, char const *restrict, struct tm const *restrict); @@ -793,6 +829,23 @@ extern char *asctime_r(struct tm const *restrict, char *restrict); extern char **environ; #endif +#ifndef HAVE_MEMPCPY +# if (defined mempcpy \ + || defined __FreeBSD__ || defined __NetBSD__ || defined __linux__) +# define HAVE_MEMPCPY 1 +# else +# define HAVE_MEMPCPY 0 +# endif +#endif +#if !HAVE_MEMPCPY +static void * +mempcpy(void *restrict s1, void const *restrict s2, size_t n) +{ + char *p = memcpy(s1, s2, n); + return p + n; +} +#endif + #if 2 <= HAVE_TZNAME + (TZ_TIME_T || !HAVE_POSIX_DECLS) extern char *tzname[]; #endif @@ -820,6 +873,9 @@ extern long altzone; # if TZ_TIME_T || !defined offtime struct tm *offtime(time_t const *, long); # endif +# if TZ_TIME_T || !defined offtime_r +struct tm *offtime_r(time_t const *restrict, long, struct tm *restrict); +# endif # if TZ_TIME_T || !defined timelocal time_t timelocal(struct tm *); # endif @@ -850,15 +906,16 @@ time_t posix2time(time_t); #endif /* -** Define functions that are ABI compatible with NetBSD but have -** better prototypes. NetBSD 6.1.4 defines a pointer type timezone_t -** and labors under the misconception that 'const timezone_t' is a -** pointer to a constant. This use of 'const' is ineffective, so it -** is not done here. What we call 'struct state' NetBSD calls +** Define functions that are ABI compatible with NetBSD. +** What we call 'struct state' NetBSD calls ** 'struct __state', but this is a private name so it doesn't matter. */ #if NETBSD_INSPIRED +# ifdef _NETBSD_SOURCE +# define state __state +# else typedef struct state *timezone_t; +# endif struct tm *localtime_rz(timezone_t restrict, time_t const *restrict, struct tm *restrict); time_t mktime_z(timezone_t restrict, struct tm *restrict); @@ -1003,18 +1060,19 @@ time_t timeoff(struct tm *, long); */ #if HAVE_GETTEXT -#define _(msgid) gettext(msgid) +# define _(msgid) gettext(msgid) #else /* !HAVE_GETTEXT */ -#define _(msgid) msgid +# define _(msgid) (msgid) #endif /* !HAVE_GETTEXT */ +#define N_(msgid) (msgid) #if !defined TZ_DOMAIN && defined HAVE_GETTEXT # define TZ_DOMAIN "tz" #endif #if HAVE_INCOMPATIBLE_CTIME_R -#undef asctime_r -#undef ctime_r +# undef asctime_r +# undef ctime_r char *asctime_r(struct tm const *restrict, char *restrict); char *ctime_r(time_t const *, char *); #endif /* HAVE_INCOMPATIBLE_CTIME_R */ diff --git a/theory.html b/theory.html index 352a3d87078f..6e52a929d335 100644 --- a/theory.html +++ b/theory.html @@ -89,24 +89,25 @@ The <code><abbr>tz</abbr></code> code is upwards compatible with <a href="https://en.wikipedia.org/wiki/POSIX">POSIX</a>, an international standard for <a href="https://en.wikipedia.org/wiki/Unix">UNIX</a>-like systems. -As of this writing, the current edition of POSIX is POSIX.1-2024, -which has been published but not yet in HTML form. -Unlike its predecessor POSIX.1-2017 (<a -href="https://pubs.opengroup.org/onlinepubs/9699919799/"> The Open -Group Base Specifications Issue 7</a>, IEEE Std 1003.1-2017, 2018 -Edition), POSIX.1-2024 requires support for the +As of this writing, the current edition of POSIX is +<a href="https://pubs.opengroup.org/onlinepubs/9799919799/">POSIX.1-2024</a> +(The Open Group Base Specifications Issue 8, IEEE Std 1003.1-2024). +Unlike its predecessors +<a href="https://archive.org/details/POSIX.1-1988">POSIX.1-1988</a> through +<a href="https://pubs.opengroup.org/onlinepubs/9699919799/">POSIX.1-2017</a>, +POSIX.1-2024 requires support for the <code><abbr>tz</abbr></code> database, which has a model for describing civil time that is more complex than the -standard and daylight saving times required by POSIX.1-2017. +standard and daylight saving times required by earlier POSIX editions. A <code><abbr>tz</abbr></code> timezone corresponds to a ruleset that can have more than two changes per year, these changes need not merely flip back and forth between two alternatives, and the rules themselves can change at times. Whether and when a timezone changes its clock, -and even the timezone's notional base offset from <abbr>UTC</abbr>, +and even the timezone’s notional base offset from <abbr>UTC</abbr>, are variable. -It does not always make sense to talk about a timezone's -"base offset", which is not necessarily a single number. +It does not always make sense to talk about a timezone’s +“base offset”, which is not necessarily a single number. </p> </section> @@ -118,16 +119,16 @@ Each timezone has a name that uniquely identifies the timezone. Inexperienced users are not expected to select these names unaided. Distributors should provide documentation and/or a simple selection interface that explains each name via a map or via descriptive text like -"Czech Republic" instead of the timezone name "<code>Europe/Prague</code>". +“Czech Republic” instead of the timezone name “<code>Europe/Prague</code>”. If geolocation information is available, a selection interface can locate the user on a timezone map or prioritize names that are geographically close. For an example selection interface, see the <code>tzselect</code> program in the <code><abbr>tz</abbr></code> code. -Unicode's <a href="https://cldr.unicode.org">Common Locale Data +Unicode’s <a href="https://cldr.unicode.org">Common Locale Data Repository (<abbr>CLDR</abbr>)</a> contains data that may be useful for other selection interfaces; it maps timezone names like <code>Europe/Prague</code> to -locale-dependent strings like "Prague", "Praha", "Прага", and "布拉格". +locale-dependent strings like “Prague”, “Praha”, “Прага”, and “布拉格”. </p> <p> @@ -142,13 +143,13 @@ among the following goals: civil time. </li> <li> - Indicate to experts where the timezone's clocks typically are. + Indicate to experts where the timezone’s clocks typically are. </li> <li> Be robust in the presence of political changes. For example, names are typically not tied to countries, to avoid incompatibilities when countries change their name (e.g., - Swaziland→Eswatini) or when locations change countries (e.g., Hong + Swaziland→Eswatini) or when locations change countries (e.g., Hong Kong from UK colony to China). There is no requirement that every country or national capital must have a timezone name. @@ -166,11 +167,11 @@ Names normally have the format <var>AREA</var><code>/</code><var>LOCATION</var>, where <var>AREA</var> is a continent or ocean, and <var>LOCATION</var> is a specific location within the area. -North and South America share the same area, '<code>America</code>'. -Typical names are '<code>Africa/Cairo</code>', -'<code>America/New_York</code>', and '<code>Pacific/Honolulu</code>'. +North and South America share the same area, <code>America</code>. +Typical names are <code>Africa/Cairo</code>, +<code>America/New_York</code>, and <code>Pacific/Honolulu</code>. Some names are further qualified to help avoid confusion; for example, -'<code>America/Indiana/Petersburg</code>' distinguishes Petersburg, +<code>America/Indiana/Petersburg</code> distinguishes Petersburg, Indiana from other Petersburgs in America. </p> @@ -183,25 +184,25 @@ in decreasing order of importance: <ul> <li> Use only valid POSIX file name components (i.e., the parts of - names other than '<code>/</code>'). - Do not use the file name components '<code>.</code>' and - '<code>..</code>'. + names other than "<code>/</code>"). + Do not use the file name components "<code>.</code>" and + "<code>..</code>". Within a file name component, use only <a href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> letters, - '<code>.</code>', '<code>-</code>' and '<code>_</code>'. + "<code>.</code>", "<code>-</code>" and "<code>_</code>". Do not use digits, as that might create an ambiguity with <a - href="https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03">POSIX's proleptic - <code>TZ</code> strings</a>. + href="https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap08.html#tag_08_03">POSIX’s + proleptic <code>TZ</code> strings</a>. A file name component must not exceed 14 characters or start with - '<code>-</code>'. + "<code>-</code>". E.g., prefer <code>America/Noronha</code> to <code>America/Fernando_de_Noronha</code>. Exceptions: see the discussion of legacy names below. </li> <li> - A name must not be empty, or contain '<code>//</code>', or - start or end with '<code>/</code>'. - Also, a name must not be '<code>Etc/Unknown</code>', as + A name must not be empty, or contain "<code>//</code>", or + start or end with "<code>/</code>". + Also, a name must not be "<code>Etc/Unknown</code>", as <abbr>CLDR</abbr> uses that string for an unknown or invalid timezone. </li> <li> @@ -213,7 +214,7 @@ in decreasing order of importance: <li> If one name <var>A</var> is an initial prefix of another name <var>AB</var> (ignoring case), then <var>B</var> must not - start with '<code>/</code>', as a regular file cannot have the + start with "<code>/</code>", as a regular file cannot have the same name as a directory in POSIX. For example, <code>America/New_York</code> precludes <code>America/New_York/Bronx</code>. @@ -280,8 +281,8 @@ in decreasing order of importance: <code>Atlantic/Canaries</code>. </li> <li> - Omit common suffixes like '<code>_Islands</code>' and - '<code>_City</code>', unless that would lead to ambiguity. + Omit common suffixes like "<code>_Islands</code>" and + "<code>_City</code>", unless that would lead to ambiguity. E.g., prefer <code>America/Cayman</code> to <code>America/Cayman_Islands</code> and <code>America/Guatemala</code> to @@ -292,10 +293,10 @@ in decreasing order of importance: country of Mexico has several time zones</a>. </li> <li> - Use '<code>_</code>' to represent a space. + Use "<code>_</code>" to represent a space. </li> <li> - Omit '<code>.</code>' from abbreviations in names. + Omit "<code>.</code>" from abbreviations in names. E.g., prefer <code>Atlantic/St_Helena</code> to <code>Atlantic/St._Helena</code>. </li> @@ -303,15 +304,15 @@ in decreasing order of importance: Do not change established names if they only marginally violate the above guidelines. For example, do not change the existing name <code>Europe/Rome</code> to - <code>Europe/Milan</code> merely because Milan's population has grown - to be somewhat greater than Rome's. + <code>Europe/Milan</code> merely because Milan’s population has grown + to be somewhat greater than Rome’s. </li> <li> If a name is changed, put its old spelling in the - '<code>backward</code>' file as a link to the new spelling. + "<code>backward</code>" file as a link to the new spelling. This means old spellings will continue to work. Ordinarily a name change should occur only in the rare case when - a location's consensus English-language spelling changes; for example, + a location’s consensus English-language spelling changes; for example, in 2008 <code>Asia/Calcutta</code> was renamed to <code>Asia/Kolkata</code> due to long-time widespread use of the new city name instead of the old. </li> @@ -327,11 +328,11 @@ have included the following: <ul> <li> Older versions of this package used a different naming scheme. -See the file '<code>backward</code>' for most of these older names -(e.g., '<code>US/Eastern</code>' instead of '<code>America/New_York</code>'). +See the file "<code>backward</code>" for most of these older names +(e.g., <code>US/Eastern</code> instead of <code>America/New_York</code>). The other old-fashioned names still supported are -'<code>WET</code>', '<code>CET</code>', '<code>MET</code>', and -'<code>EET</code>' (see the file '<code>europe</code>'). +<code>WET</code>, <code>CET</code>, <code>MET</code>, and +<code>EET</code> (see the file "<code>europe</code>"). </li> <li> @@ -339,13 +340,13 @@ Older versions of this package defined legacy names that are incompatible with the first guideline of location names, but which are still supported. These legacy names are mostly defined in the file -'<code>etcetera</code>'. -Also, the file '<code>backward</code>' defines the legacy names -'<code>Etc/GMT0</code>', '<code>Etc/GMT-0</code>', '<code>Etc/GMT+0</code>', -'<code>GMT0</code>', '<code>GMT-0</code>' and '<code>GMT+0</code>', -and the file '<code>northamerica</code>' defines the legacy names -'<code>EST5EDT</code>', '<code>CST6CDT</code>', -'<code>MST7MDT</code>', and '<code>PST8PDT</code>'. +"<code>etcetera</code>". +Also, the file "<code>backward</code>" defines the legacy names +<code>Etc/GMT0</code>, <code>Etc/GMT-0</code>, <code>Etc/GMT+0</code>, +<code>GMT0</code>, <code>GMT-0</code> and <code>GMT+0</code>, +and the file "<code>northamerica</code>" defines the legacy names +<code>EST5EDT</code>, <code>CST6CDT</code>, +<code>MST7MDT</code>, and <code>PST8PDT</code>. </li> <li> @@ -365,11 +366,11 @@ The file <code>zone1970.tab</code> lists geographical locations used to name timezones. It is intended to be an exhaustive list of names for geographic regions as described above; this is a subset of the timezones in the data. -Although a <code>zone1970.tab</code> location's +Although a <code>zone1970.tab</code> location’s <a href="https://en.wikipedia.org/wiki/Longitude">longitude</a> corresponds to its <a href="https://en.wikipedia.org/wiki/Local_mean_time">local mean -time (<abbr>LMT</abbr>)</a> offset with one hour for every 15° +time (<abbr>LMT</abbr>)</a> offset with one hour for every 15° east longitude, this relationship is not exact. The backward-compatibility file <code>zone.tab</code> is similar but conforms to the older-version guidelines related to <abbr>ISO</abbr> 3166-1; @@ -395,7 +396,7 @@ on platforms that do not support proleptic <code>TZ</code> strings like <code><+08>-8</code>; no other source file other than <code>backward</code> contains links to its zones. -One of <code>etcetera</code>'s names is <code>Etc/UTC</code>, +One of <code>etcetera</code>’s names is <code>Etc/UTC</code>, used by functions like <code>gmtime</code> to obtain leap second information on platforms that support leap seconds. Another <code>etcetera</code> name, <code>GMT</code>, @@ -407,7 +408,7 @@ is used by older code releases. <h2 id="abbreviations">Time zone abbreviations</h2> <p> When this package is installed, it generates time zone abbreviations -like '<code>EST</code>' to be compatible with human tradition and POSIX. +like <code>EST</code> to be compatible with human tradition and POSIX. Here are the general guidelines used for choosing time zone abbreviations, in decreasing order of importance: </p> @@ -415,25 +416,24 @@ in decreasing order of importance: <ul> <li> Use three to six characters that are ASCII alphanumerics or - '<code>+</code>' or '<code>-</code>'. + "<code>+</code>" or "<code>-</code>". Previous editions of this database also used characters like - space and '<code>?</code>', but these characters have a + space and "<code>?</code>", but these characters have a special meaning to the <a href="https://en.wikipedia.org/wiki/Unix_shell">UNIX shell</a> and cause commands like - '<code><a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set">set</a> - `<a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/date.html">date</a>`</code>' + "<code><a href="https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#set">set</a> + `<a href="https://pubs.opengroup.org/onlinepubs/9799919799/utilities/date.html">date</a>`</code>" to have unexpected effects. Previous editions of this guideline required upper-case letters, but the Congressman who introduced <a href="https://en.wikipedia.org/wiki/Chamorro_Time_Zone">Chamorro - Standard Time</a> preferred "ChST", so lower-case letters are now - allowed. - Also, POSIX from 2001 on relaxed the rule to allow '<code>-</code>', - '<code>+</code>', and alphanumeric characters from the portable + Standard Time</a> preferred “ChST”, so lower-case letters are now allowed. + Also, POSIX from 2001 on relaxed the rule to allow "<code>-</code>", + "<code>+</code>", and alphanumeric characters from the portable character set in the current locale. - In practice ASCII alphanumerics and '<code>+</code>' and - '<code>-</code>' are safe in all locales. + In practice ASCII alphanumerics and "<code>+</code>" and + "<code>-</code>" are safe in all locales. <p> In other words, in the C locale the POSIX extended regular @@ -445,10 +445,10 @@ in decreasing order of importance: </li> <li> Use abbreviations that are in common use among English-speakers, - e.g., 'EST' for Eastern Standard Time in North America. + e.g., “EST” for Eastern Standard Time in North America. We assume that applications translate them to other languages as part of the normal localization process; for example, - a French application might translate 'EST' to 'HNE'. + a French application might translate “EST” to “HNE”. <p> <small>These abbreviations (for standard/daylight/etc. time) are: @@ -483,7 +483,7 @@ in decreasing order of importance: NST/NDT/NWT/NPT/NDDT Newfoundland, NST/NDT/NWT/NPT Nome, NZMT/NZST New Zealand through 1945, - NZST/NZDT New Zealand 1946–present, + NZST/NZDT New Zealand 1946–present, PKT/PKST Pakistan, PST/PDT/PWT/PPT Pacific, PST/PDT Philippine, @@ -500,12 +500,12 @@ in decreasing order of importance: </li> <li> <p> - For times taken from a city's longitude, use the + For times taken from a city’s longitude, use the traditional <var>x</var>MT notation. - The only abbreviation like this in current use is '<abbr>GMT</abbr>'. + The only abbreviation like this in current use is <abbr>GMT</abbr>. The others are for timestamps before 1960, except that Monrovia Mean Time persisted until 1972. - Typically, numeric abbreviations (e.g., '<code>-</code>004430' for + Typically, numeric abbreviations (e.g., <code>-</code>004430 for MMT) would cause trouble here, as the numeric strings would exceed the POSIX length limit. </p> @@ -546,39 +546,39 @@ in decreasing order of importance: <small>A few abbreviations also follow the pattern that <abbr>GMT</abbr>/<abbr>BST</abbr> established for time in the UK. They are: - BMT/BST for Bermuda 1890–1930, + BMT/BST for Bermuda 1890–1930, CMT/BST for Calamarca Mean Time and Bolivian Summer Time - 1890–1932, + 1890–1932, DMT/IST for Dublin/Dunsink Mean Time and Irish Summer Time - 1880–1916, - MMT/MST/MDST for Moscow 1880–1919, and - RMT/LST for Riga Mean Time and Latvian Summer time 1880–1926. + 1880–1916, + MMT/MST/MDST for Moscow 1880–1919, and + RMT/LST for Riga Mean Time and Latvian Summer time 1880–1926. </small> </p> </li> <li> - Use '<abbr>LMT</abbr>' for local mean time of locations before the - introduction of standard time; see "<a href="#scope">Scope of the - <code><abbr>tz</abbr></code> database</a>". + Use “<abbr>LMT</abbr>” for local mean time of locations before the + introduction of standard time; see “<a href="#scope">Scope of the + <code><abbr>tz</abbr></code> database</a>”. </li> <li> If there is no common English abbreviation, use numeric offsets like <code>-</code>05 and <code>+</code>0530 that are generated - by <code>zic</code>'s <code>%z</code> notation. + by <code>zic</code>’s <code>%z</code> notation. </li> <li> Use current abbreviations for older timestamps to avoid confusion. For example, in 1910 a common English abbreviation for time - in central Europe was 'MEZ' (short for both "Middle European - Zone" and for "Mitteleuropäische Zeit" in German). - Nowadays 'CET' ("Central European Time") is more common in - English, and the database uses 'CET' even for circa-1910 + in central Europe was “MEZ” (short for both “Middle European + Zone” and for “Mitteleuropäische Zeit” in German). + Nowadays “CET” (“Central European Time”) is more common in + English, and the database uses “CET” even for circa-1910 timestamps as this is less confusing for modern users and avoids - the need for determining when 'CET' supplanted 'MEZ' in common + the need for determining when “CET” supplanted “MEZ” in common usage. </li> <li> - Use a consistent style in a timezone's history. + Use a consistent style in a timezone’s history. For example, if a history tends to use numeric abbreviations and a particular entry could go either way, use a numeric abbreviation. @@ -586,13 +586,13 @@ in decreasing order of importance: <li> Use <a href="https://en.wikipedia.org/wiki/Universal_Time">Universal Time</a> - (<abbr>UT</abbr>) (with time zone abbreviation '<code>-</code>00') for + (<abbr>UT</abbr>) (with time zone abbreviation <code>-</code>00) for locations while uninhabited. - The leading '<code>-</code>' is a flag that the <abbr>UT</abbr> offset is in + The leading "<code>-</code>" is a flag that the <abbr>UT</abbr> offset is in some sense undefined; this notation is derived from <a href="https://www.rfc-editor.org/rfc/rfc3339">Internet <abbr title="Request For Comments">RFC</abbr> 3339</a>. - (The abbreviation 'Z' that + (The abbreviation Z that <a href="https://www.rfc-editor.org/rfc/rfc9557">Internet <abbr>RFC</abbr> 9557</a> uses for this concept would violate the POSIX requirement @@ -602,11 +602,11 @@ in decreasing order of importance: <p> Application writers should note that these abbreviations are ambiguous -in practice: e.g., 'CST' means one thing in China and something else -in North America, and 'IST' can refer to time in India, Ireland or +in practice: e.g., CST means one thing in China and something else +in North America, and IST can refer to time in India, Ireland or Israel. To avoid ambiguity, use numeric <abbr>UT</abbr> offsets like -'<code>-</code>0600' instead of time zone abbreviations like 'CST'. +<code>-</code>0600 instead of time zone abbreviations like CST. </p> </section> @@ -617,7 +617,7 @@ The <code><abbr>tz</abbr></code> database is not authoritative, and it surely has errors. Corrections are welcome and encouraged; see the file <code>CONTRIBUTING</code>. Users requiring authoritative data should consult national standards -bodies and the references cited in the database's comments. +bodies and the references cited in the database’s comments. </p> <p> @@ -639,7 +639,7 @@ Errors in the <code><abbr>tz</abbr></code> database arise from many sources: clocks actually behaved; the vast majority of the necessary information was lost or never recorded. Thousands more timezones would be needed if - the <code><abbr>tz</abbr></code> database's scope were extended to + the <code><abbr>tz</abbr></code> database’s scope were extended to cover even just the known or guessed history of standard time; for example, the current single entry for France would need to split into dozens of entries, perhaps hundreds. @@ -649,11 +649,11 @@ Errors in the <code><abbr>tz</abbr></code> database arise from many sources: In her 2015 book <cite><a href="https://www.hup.harvard.edu/catalog.php?isbn=9780674286146">The - Global Transformation of Time, 1870–1950</a></cite>, + Global Transformation of Time, 1870–1950</a></cite>, Vanessa Ogle writes - "Outside of Europe and North America there was no system of time + “Outside of Europe and North America there was no system of time zones at all, often not even a stable landscape of mean times, - prior to the middle decades of the twentieth century". + prior to the middle decades of the twentieth century”. See: Timothy Shenk, <a href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanessa-ogle">Booked: A Global History of Time</a>. <cite>Dissent</cite> 2015-12-17. @@ -671,8 +671,8 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes For the UK the <code><abbr>tz</abbr></code> database relies on years of first-class work done by Joseph Myers and others; see - "<a href="https://www.polyomino.org.uk/british-time/">History of - legal time in Britain</a>". + “<a href="https://www.polyomino.org.uk/british-time/">History of + legal time in Britain</a>”. Other countries are not done nearly as well. </li> <li> @@ -697,13 +697,13 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes entries are often accurate for only a small subset of that region. For example, <code>Europe/London</code> stands for the United Kingdom, but its pre-1847 times are valid only for locations that - have London's exact meridian, and its 1847 transition + have London’s exact meridian, and its 1847 transition to <abbr>GMT</abbr> is known to be valid only for the L&NW and the Caledonian railways. </li> <li> The <code><abbr>tz</abbr></code> database does not record the - earliest time for which a timezone's + earliest time for which a timezone’s data entries are thereafter valid for every location in the region. For example, <code>Europe/London</code> is valid for all locations in its region after <abbr>GMT</abbr> was made the standard time, @@ -714,7 +714,7 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes </li> <li> The <code><abbr>tz</abbr></code> database does not record a - region's boundaries, and in many cases the boundaries are not known. + region’s boundaries, and in many cases the boundaries are not known. For example, the timezone <code>America/Kentucky/Louisville</code> represents a region around the city of Louisville, the boundaries of which are @@ -747,7 +747,7 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes than what the <code><abbr>tz</abbr></code> code can handle. For example, from 1880 to 1916 clocks in Ireland observed Dublin Mean Time (estimated to be <abbr>UT</abbr> - −00:25:21.1); although the <code><abbr>tz</abbr></code> + −00:25:21.1); although the <code><abbr>tz</abbr></code> source data can represent the .1 second, TZif files and the code cannot. In practice these old specifications were rarely if ever implemented to subsecond precision. @@ -787,7 +787,7 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes non-hour-based system at night. And even today, some local practices diverge from the Gregorian calendar with 24-hour days. These divergences range from - relatively minor, such as Japanese bars giving times like "24:30" for the + relatively minor, such as Japanese bars giving times like 24:30 for the wee hours of the morning, to more-significant differences such as <a href="https://theworld.org/stories/2015-01-30/if-you-have-meeting-ethiopia-you-better-double-check-time">the east African practice of starting the day at dawn</a>, renumbering @@ -825,16 +825,16 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes <li> Civil time was not based on atomic time before 1972, and we do not know the history of - <a href="https://en.wikipedia.org/wiki/Earth's_rotation">earth's + <a href="https://en.wikipedia.org/wiki/Earth's_rotation">earth’s rotation</a> accurately enough to map <a href="https://en.wikipedia.org/wiki/International_System_of_Units"><abbr title="International System of Units">SI</abbr></a> seconds to historical <a href="https://en.wikipedia.org/wiki/Solar_time">solar time</a> to more than about one-hour accuracy. - See: Stephenson FR, Morrison LV, Hohenkerk CY. - <a href="https://dx.doi.org/10.1098/rspa.2016.0404">Measurement of - the Earth's rotation: 720 BC to AD 2015</a>. - <cite>Proc Royal Soc A</cite>. 2016;472:20160404. + See: Morrison LV, Stephenson FR, Hohenkerk CY, Zawilski M. + <a href="https://doi.org/10.1098/rspa.2020.0776">Addendum 2020 + to ‘Measurement of the Earth’s rotation: 720 BC to AD 2015’</a>. + <cite>Proc Royal Soc A</cite>. 2021;477:20200776. Also see: Espenak F. <a href="https://eclipse.gsfc.nasa.gov/SEhelp/uncertainty2004.html">Uncertainty in Delta T (ΔT)</a>. @@ -843,7 +843,7 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes The relationship between POSIX time (that is, <abbr>UTC</abbr> but ignoring <a href="https://en.wikipedia.org/wiki/Leap_second">leap seconds</a>) and <abbr>UTC</abbr> is not agreed upon. - This affects time stamps during the leap second era (1972–2035). + This affects time stamps during the leap second era (1972–2035). Although the POSIX clock officially stops during an inserted leap second, at least one proposed standard has it jumping back a second instead; and in @@ -862,12 +862,12 @@ href="https://www.dissentmagazine.org/blog/booked-a-global-history-of-time-vanes <p> In short, many, perhaps most, of the <code><abbr>tz</abbr></code> -database's pre-1970 and future timestamps are either wrong or +database’s pre-1970 and future timestamps are either wrong or misleading. Any attempt to pass the <code><abbr>tz</abbr></code> database off as the definition of time should be unacceptable to anybody who cares about the facts. -In particular, the <code><abbr>tz</abbr></code> database's +In particular, the <code><abbr>tz</abbr></code> database’s <abbr>LMT</abbr> offsets should not be considered meaningful, and should not prompt creation of timezones merely because two locations @@ -886,7 +886,7 @@ Code compatible with this package is already primary use of this package is to update obsolete time-related files. To do this, you may need to compile the time zone compiler <code>zic</code> supplied with this package instead of using the -system <code>zic</code>, since the format of <code>zic</code>'s +system <code>zic</code>, since the format of <code>zic</code>’s input is occasionally extended, and a platform may still be shipping an older <code>zic</code>. </p> @@ -914,7 +914,8 @@ environment variable <code>TZ</code>, which can have two forms: <h3 id="POSIX.1-2017">POSIX.1-2017 properties and limitations</h3> <p> -Some platforms support only the features required by POSIX.1-2017, +Some platforms support only the features required by POSIX.1-2017 +and earlier editions, and have not yet upgraded to POSIX.1-2024. Code intended to be portable to these platforms must deal with problems that were fixed in later POSIX editions. @@ -956,14 +957,14 @@ with problems that were fixed in later POSIX editions. are 3 or more characters specifying the standard and daylight saving time (<abbr>DST</abbr>) zone abbreviations. Starting with POSIX.1-2001, <var>std</var> and <var>dst</var> - may also be in a quoted form like '<code><+09></code>'; + may also be quoted in angle brackets, like <code><+09></code>; this allows "<code>+</code>" and "<code>-</code>" in the names. </dd> <dt><var>offset</var></dt><dd> is of the form - '<code>[±]<var>hh</var>:[<var>mm</var>[:<var>ss</var>]]</code>' + <code>[±]<var>hh</var>:[<var>mm</var>[:<var>ss</var>]]</code> and specifies the offset west of <abbr>UT</abbr>. - '<var>hh</var>' may be a single digit; + <var>hh</var> may be a single digit; 0≤<var>hh</var>≤24. The default <abbr>DST</abbr> offset is one hour ahead of standard time. @@ -976,10 +977,10 @@ with problems that were fixed in later POSIX editions. </dd> <dt><var>time</var></dt><dd> takes the form - '<var>hh</var><code>:</code>[<var>mm</var>[<code>:</code><var>ss</var>]]' + <var>hh</var><code>:</code>[<var>mm</var>[<code>:</code><var>ss</var>]] and defaults to 02:00. This is the same format as the offset, except that a - leading '<code>+</code>' or '<code>-</code>' is not allowed. + leading "<code>+</code>" or "<code>-</code>" is not allowed. </dd> <dt><var>date</var></dt><dd> takes one of the following forms: @@ -996,7 +997,7 @@ with problems that were fixed in later POSIX editions. for the <var>d</var>th day of week <var>n</var> of month <var>m</var> of the year, where week 1 is the first week in which day <var>d</var> appears, and - '<code>5</code>' stands for the last week in which + "<code>5</code>" stands for the last week in which day <var>d</var> appears (which may be either the 4th or 5th week). Typically, this is the only useful form; the <var>n</var> @@ -1011,8 +1012,8 @@ with problems that were fixed in later POSIX editions. Zealand after 2007. It says that standard time (<abbr>NZST</abbr>) is 12 hours ahead of <abbr>UT</abbr>, and that daylight saving time - (<abbr>NZDT</abbr>) is observed from September's last Sunday at - 02:00 until April's first Sunday at 03:00: + (<abbr>NZDT</abbr>) is observed from September’s last Sunday at + 02:00 until April’s first Sunday at 03:00: </p> <pre><code>TZ='NZST-12NZDT,M9.5.0,M4.1.0/3'</code></pre> @@ -1048,11 +1049,11 @@ POSIX.1-2024 extends POSIX.1-2017 in the following significant ways: Earlier POSIX editions lack this requirement. </li> <li> - DST transition times can range from −167:59:59 + DST transition times can range from −167:59:59 to 167:59:59 instead of merely from 00:00:00 to 24:59:59. This allows for proleptic TZ strings like <code>"<-02>2<-01>,M3.5.0/-1,M10.5.0/0"</code> - where the transition time −1:00 means 23:00 the previous day. + where the transition time −1:00 means 23:00 the previous day. </li> </ul> <p> @@ -1065,14 +1066,14 @@ However POSIX.1-2024, like earlier POSIX editions, has some limitations: </li> <li> In POSIX, there is no tamper-proof way for a process to learn the - system's best idea of local (wall clock) time. + system’s best idea of local (wall clock) time. This is important for applications that an administrator wants - used only at certain times – without regard to whether the + used only at certain times – without regard to whether the user has fiddled the <code>TZ</code> environment variable. - While an administrator can "do everything in <abbr>UT</abbr>" to + While an administrator can “do everything in <abbr>UT</abbr>” to get around the problem, doing so is inconvenient and precludes - handling daylight saving time shifts – as might be required to + handling daylight saving time shifts – as might be required to limit phone calls to off-peak hours. </li> <li> @@ -1081,8 +1082,7 @@ However POSIX.1-2024, like earlier POSIX editions, has some limitations: </li> <li> POSIX does not define the <abbr>DST</abbr> transitions - for <code>TZ</code> values like - "<code>EST5EDT</code>". + for settings like <code>TZ='EST5EDT'</code>. Traditionally the current <abbr>US</abbr> <abbr>DST</abbr> rules were used to interpret such values, but this meant that the <abbr>US</abbr> <abbr>DST</abbr> rules were compiled into each @@ -1124,7 +1124,7 @@ However POSIX.1-2024, like earlier POSIX editions, has some limitations: If the <code>TZ</code> environment variable uses the geographical format, it is used in generating the name of a file from which time-related information is read. - The file's format is <dfn><abbr>TZif</abbr></dfn>, + The file’s format is <dfn><abbr>TZif</abbr></dfn>, a timezone information format that contains binary data; see <a href="https://www.rfc-editor.org/rfc/9636">Internet <abbr>RFC</abbr> 9636</a>. @@ -1138,18 +1138,18 @@ However POSIX.1-2024, like earlier POSIX editions, has some limitations: <p> When the <code><abbr>tz</abbr></code> code was developed in the 1980s, it was recognized that allowing the <code>TZ</code> environment - variable to take on values such as '<code>America/New_York</code>' - might cause "old" programs (that expect <code>TZ</code> to have a + variable to take on values such as <code>America/New_York</code> + might cause old programs (that expect <code>TZ</code> to have a certain format) to operate incorrectly; consideration was given to using some other environment variable (for example, <code>TIMEZONE</code>) - to hold the string used to generate the <abbr>TZif</abbr> file's name. + to hold the string used to generate the <abbr>TZif</abbr> file’s name. In the end, however, it was decided to continue using <code>TZ</code>: it is widely used for time zone purposes; separately maintaining both <code>TZ</code> and <code>TIMEZONE</code> seemed a nuisance; and systems where - "new" forms of <code>TZ</code> might cause problems can simply - use legacy <code>TZ</code> values such as "<code>EST5EDT</code>" which - can be used by "new" programs as well as by "old" programs that + new forms of <code>TZ</code> might cause problems can simply + use legacy settings such as <code>TZ='EST5EDT'</code> which + can be used by new programs as well as by old programs that assume pre-POSIX <code>TZ</code> values. </p> </li> @@ -1192,20 +1192,20 @@ The vestigial <abbr>API</abbr>s are: The POSIX <code>tzname</code> variable does not suffice and is no longer needed. It is planned to be removed in a future edition of POSIX. - To get a timestamp's time zone abbreviation, consult + To get a timestamp’s time zone abbreviation, consult the <code>tm_zone</code> member if available; otherwise, - use <code>strftime</code>'s <code>"%Z"</code> conversion + use <code>strftime</code>’s <code>"%Z"</code> conversion specification. </li> <li> The POSIX <code>daylight</code> and <code>timezone</code> variables do not suffice and are no longer needed. They are planned to be removed in a future edition of POSIX. - To get a timestamp's <abbr>UT</abbr> offset, consult + To get a timestamp’s <abbr>UT</abbr> offset, consult the <code>tm_gmtoff</code> member if available; otherwise, subtract values returned by <code>localtime</code> and <code>gmtime</code> using the rules of the Gregorian calendar, - or use <code>strftime</code>'s <code>"%z"</code> conversion + or use <code>strftime</code>’s <code>"%z"</code> conversion specification if a string like <code>"+0900"</code> suffices. </li> <li> @@ -1230,9 +1230,9 @@ The vestigial <abbr>API</abbr>s are: <li> The <a href="https://en.wikipedia.org/wiki/Version_7_Unix">7th Edition UNIX</a> <code>timezone</code> function is not present in this - package; it is impossible to reliably map <code>timezone</code>'s - arguments (a "minutes west of <abbr>GMT</abbr>" value and a - "daylight saving time in effect" flag) to a time zone + package; it is impossible to reliably map <code>timezone</code>’s + arguments (a “minutes west of <abbr>GMT</abbr>” value and a + “daylight saving time in effect” flag) to a time zone abbreviation, and we refuse to guess. Programs that in the past used the <code>timezone</code> function may now examine <code>localtime(&clock)->tm_zone</code> @@ -1262,7 +1262,7 @@ The vestigial <abbr>API</abbr>s are: The functions that are conditionally compiled if <code>STD_INSPIRED</code> is nonzero should, at this point, be looked on primarily as food for thought. - They are not in any sense "standard compatible" – some are + They are not in any sense “standard compatible” – some are not, in fact, specified in <em>any</em> standard. They do, however, represent responses of various authors to standardization proposals. @@ -1293,11 +1293,11 @@ The <code><abbr>tz</abbr></code> code and data supply the following interfaces: <ul> <li> A set of timezone names as per - "<a href="#naming">Timezone identifiers</a>" above. + “<a href="#naming">Timezone identifiers</a>” above. </li> <li> - Library functions described in "<a href="#functions">Time and date - functions</a>" above. + Library functions described in “<a href="#functions">Time and date + functions</a>” above. </li> <li> The programs <code>tzselect</code>, <code>zdump</code>, @@ -1319,7 +1319,7 @@ The <code><abbr>tz</abbr></code> code and data supply the following interfaces: </li> <li> The version number of the code and data, as the first line of - the text file '<code>version</code>' in each release. + the text file "<code>version</code>" in each release. </li> </ul> @@ -1347,7 +1347,7 @@ For example, even though the <samp>Asia/Bangkok</samp> timezone currently includes Chang Mai, Hanoi, and Phnom Penh, this is not part of the stable interface and the timezone can split at any time. If a calendar application records a future event in some location other -than Bangkok by putting "<samp>Asia/Bangkok</samp>" in the event's record, +than Bangkok by putting <samp>Asia/Bangkok</samp> in the event’s record, the application should be robust in the presence of timezone splits between now and the future time. </p> @@ -1381,7 +1381,7 @@ commonly used by <a href="https://www.ntp.org"><abbr title="Network Time Protocol">NTP</abbr></a> software that adjusts the kernel clock. However, kernel-clock twiddling approximates UTC only roughly, -and systems needing more precise UTC can use this package's leap +and systems needing more precise UTC can use this package’s leap second support directly. </p> @@ -1391,8 +1391,8 @@ counts of seconds since the POSIX epoch normally include leap seconds, as opposed to POSIX <code>time_t</code> counts which exclude leap seconds. This modified timescale is converted to <abbr>UTC</abbr> at the same point that time zone and <abbr>DST</abbr> -adjustments are applied – -namely, at calls to <code>localtime</code> and analogous functions – +adjustments are applied – +namely, at calls to <code>localtime</code> and analogous functions – and the process is driven by leap second information stored in alternate versions of the <abbr>TZif</abbr> files. Because a leap second adjustment may be needed even @@ -1402,7 +1402,7 @@ also need to consult a <abbr>TZif</abbr> file, conventionally named <samp><abbr>Etc/UTC</abbr></samp> (<samp><abbr>GMT</abbr></samp> in previous versions), to see whether leap second corrections are needed. -To convert an application's <code>time_t</code> timestamps to or from +To convert an application’s <code>time_t</code> timestamps to or from POSIX <code>time_t</code> timestamps (for use when, say, embedding or interpreting timestamps in portable <a href="https://en.wikipedia.org/wiki/Tar_(computing)"><code>tar</code></a> @@ -1425,7 +1425,7 @@ So if you configure your kernel to count leap seconds, you should also discard <samp>zoneinfo</samp> and rename <samp>zoneinfo-leaps</samp> to <samp>zoneinfo</samp>. Alternatively, you can install just one set of <abbr>TZif</abbr> files -in the first place; see the <code>REDO</code> variable in this package's +in the first place; see the <code>REDO</code> variable in this package’s <a href="https://en.wikipedia.org/wiki/Makefile">makefile</a>. </p> </section> @@ -1440,7 +1440,7 @@ An excellent resource in this area is Edward M. Reingold and Nachum Dershowitz, <cite><a href="https://www.cambridge.org/fr/academic/subjects/computer-science/computing-general-interest/calendrical-calculations-ultimate-edition-4th-edition">Calendrical Calculations: The Ultimate Edition</a></cite>, Cambridge University Press (2018). -Other information and sources are given in the file '<code>calendars</code>' +Other information and sources are given in the file "<code>calendars</code>" in the <code><abbr>tz</abbr></code> distribution. They sometimes disagree. </p> @@ -1450,20 +1450,20 @@ They sometimes disagree. <h2 id="planets">Time and time zones off Earth</h2> <p> The European Space Agency is <a -href='https://www.esa.int/Applications/Navigation/Telling_time_on_the_Moon'>considering</a> +href="https://www.esa.int/Applications/Navigation/Telling_time_on_the_Moon">considering</a> the establishment of a reference timescale for the Moon, which has days roughly equivalent to 29.5 Earth days, and where relativistic effects cause clocks to tick slightly faster than on Earth. Also, <abbr title="National Aeronautics and Space Administration">NASA</abbr> has been <a -href='https://www.whitehouse.gov/wp-content/uploads/2024/04/Celestial-Time-Standardization-Policy.pdf'>ordered</a> +href="https://www.whitehouse.gov/wp-content/uploads/2024/04/Celestial-Time-Standardization-Policy.pdf">ordered</a> to consider the establishment of Coordinated Lunar Time (<abbr>LTC</abbr>). It is not yet known whether the US and European efforts will result in multiple timescales on the Moon. </p> <p> -Some people's work schedules have used +Some people’s work schedules have used <a href="https://en.wikipedia.org/wiki/Timekeeping_on_Mars">Mars time</a>. Jet Propulsion Laboratory (JPL) coordinators kept Mars time on and off during the @@ -1473,7 +1473,7 @@ Some of their family members also adapted to Mars time. Dozens of special Mars watches were built for JPL workers who kept Mars time during the <a href="https://en.wikipedia.org/wiki/Mars_Exploration_Rover">Mars -Exploration Rovers (MER)</a> mission (2004–2018). +Exploration Rovers (MER)</a> mission (2004–2018). These timepieces looked like normal Seikos and Citizens but were adjusted to use Mars seconds rather than terrestrial seconds, although unfortunately the adjusted watches were unreliable and appear to have @@ -1481,12 +1481,12 @@ had only limited use. </p> <p> -A Mars solar day is called a "sol" and has a mean period equal to +A Mars solar day is called a “sol” and has a mean period equal to about 24 hours 39 minutes 35.244 seconds in terrestrial time. It is divided into a conventional 24-hour clock, so each Mars second equals about 1.02749125 terrestrial seconds. -(One MER worker noted, "If I am working Mars hours, and Mars hours are -2.5% more than Earth hours, shouldn't I get an extra 2.5% pay raise?") +(One MER worker noted, “If I am working Mars hours, and Mars hours are +2.5% more than Earth hours, shouldn’t I get an extra 2.5% pay raise?”) </p> <p> @@ -1494,7 +1494,7 @@ The <a href="https://en.wikipedia.org/wiki/Prime_meridian">prime meridian</a> of Mars goes through the center of the crater <a href="https://en.wikipedia.org/wiki/Airy-0">Airy-0</a>, named in honor of the British astronomer who built the Greenwich telescope that -defines Earth's prime meridian. +defines Earth’s prime meridian. Mean solar time on the Mars prime meridian is called Mars Coordinated Time (<abbr>MTC</abbr>). </p> @@ -1502,13 +1502,13 @@ called Mars Coordinated Time (<abbr>MTC</abbr>). <p> Each landed mission on Mars has adopted a different reference for solar timekeeping, so there is no real standard for Mars time zones. -For example, the MER mission defined two time zones "Local -Solar Time A" and "Local Solar Time B" for its two missions, each zone +For example, the MER mission defined two time zones “Local +Solar Time A” and “Local Solar Time B” for its two missions, each zone designed so that its time equals local true solar time at approximately the middle of the nominal mission. The A and B zones differ enough so that an MER worker assigned to -the A zone might suffer "Mars lag" when switching to work in the B zone. -Such a "time zone" is not particularly suited for any application +the A zone might suffer “Mars lag” when switching to work in the B zone. +Such a “time zone” is not particularly suited for any application other than the mission itself. </p> @@ -1522,13 +1522,13 @@ sequential count of Mars solar days elapsed since about 1873-12-29 <p> In our solar system, Mars is the planet with time and calendar most -like Earth's. +like Earth’s. On other planets, Sun-based time and calendars would work quite differently. -For example, although Mercury's +For example, although Mercury’s <a href="https://en.wikipedia.org/wiki/Rotation_period">sidereal rotation period</a> is 58.646 Earth days, Mercury revolves around the -Sun so rapidly that an observer on Mercury's equator would see a +Sun so rapidly that an observer on Mercury’s equator would see a sunrise only every 175.97 Earth days, i.e., a Mercury year is 0.5 of a Mercury day. Venus is more complicated, partly because its rotation is slightly @@ -1554,8 +1554,8 @@ Sources for time on other planets: <ul> <li> Michael Allison and Robert Schmunk, - "<a href="https://www.giss.nasa.gov/tools/mars24/help/notes.html">Technical - Notes on Mars Solar Time as Adopted by the Mars24 Sunclock</a>" + “<a href="https://www.giss.nasa.gov/tools/mars24/help/notes.html">Technical + Notes on Mars Solar Time as Adopted by the Mars24 Sunclock</a>” (2020-03-08). </li> <li> @@ -1565,28 +1565,33 @@ Sources for time on other planets: </li> <li> Jia-Rui Chong, - "<a href="https://www.latimes.com/archives/la-xpm-2004-jan-14-sci-marstime14-story.html">Workdays - Fit for a Martian</a>", <cite>Los Angeles Times</cite> - (2004-01-14), pp A1, A20–A21. + “<a href="https://www.latimes.com/archives/la-xpm-2004-jan-14-sci-marstime14-story.html">Workdays + Fit for a Martian</a>”, <cite>Los Angeles Times</cite> + (2004-01-14), pp A1, A20–A21. </li> <li> Tom Chmielewski, - "<a href="https://www.theatlantic.com/technology/archive/2015/02/jet-lag-is-worse-on-mars/386033/">Jet - Lag Is Worse on Mars</a>", <cite>The Atlantic</cite> (2015-02-26) + “<a href="https://www.theatlantic.com/technology/archive/2015/02/jet-lag-is-worse-on-mars/386033/">Jet + Lag Is Worse on Mars</a>”, <cite>The Atlantic</cite> (2015-02-26) </li> <li> Matt Williams, - "<a href="https://www.universetoday.com/37481/days-of-the-planets/">How - long is a day on the other planets of the solar system?</a>" + “<a href="https://www.universetoday.com/37481/days-of-the-planets/">How + long is a day on the other planets of the solar system?</a>” (2016-01-20). </li> </ul> </section> <footer> - <hr> - This file is in the public domain, so clarified as of 2009-05-17 by - Arthur David Olson. +<hr> +This web page is in the public domain, so clarified as of +2009-05-17 by Arthur David Olson. +<br> +Please send corrections to this web page to the +<a href="mailto:tz@iana.org">time zone mailing list</a>. +The mailing list and its archives are public, +so please do not send confidential information. </footer> </body> </html> diff --git a/time2posix.3.txt b/time2posix.3.txt index 87789b366978..6b0e0449b816 100644 --- a/time2posix.3.txt +++ b/time2posix.3.txt @@ -20,12 +20,12 @@ DESCRIPTION If the time package is configured with leap-second support enabled, however, no such adjustment is needed and time_t values continue to - increase over leap events (as a true "seconds since..." value). This + increase over leap events (as a true “seconds since...” value). This means that these values will differ from those required by POSIX by the net number of leap seconds inserted since the Epoch. Typically this is not a problem as the type time_t is intended to be - (mostly) opaque - time_t values should only be obtained-from and + (mostly) opaque – time_t values should only be obtained-from and passed-to functions such as time(2), localtime(3), mktime(3), and difftime(3). However, POSIX gives an arithmetic expression for directly computing a time_t value from a given date/time, and the same diff --git a/tz-art.html b/tz-art.html index 15ba7f4ec54b..3039a86fc48c 100644 --- a/tz-art.html +++ b/tz-art.html @@ -9,28 +9,40 @@ <h2>Documentaries</h2> <ul> <li> -"<a href="https://www.youtube.com/watch?v=84aWtseb2-4">Daylight -Saving Time Explained</a>" (2011; 6:39) lightly covers daylight saving -time's theory, history, pros and cons. Among other things, it explains -Arizona's daylight-saving enclaves quite well.</li> +“<a href="https://www.youtube.com/watch?v=84aWtseb2-4">Daylight +Saving Time Explained</a>” (2011; 6:39) lightly covers daylight saving +time’s theory, history, pros and cons. Among other things, it explains +Arizona’s daylight-saving enclaves quite well. +</li> <li> -"<a href="https://www.youtube.com/watch?v=-5wpm-gesOY">The Problem -with Time & Timezones – Computerphile</a>" (2013; 10:12) delves -into problems that programmers have with timekeeping.</li> +“<a href="https://www.youtube.com/watch?v=-5wpm-gesOY">The Problem +with Time & Timezones – Computerphile</a>” (2013; 10:12) delves +into problems that programmers have with timekeeping. +</li> <li> -"<a href="https://www.rferl.org/a/28375932.html">All The Time In The World: -Explaining The Mysteries Of Time Zones</a>" (2017; 2:15) +“<a href="https://www.rferl.org/a/28375932.html">All The Time +In The World: Explaining The Mysteries Of Time Zones</a>” (2017; 2:15) briefly says why France has more time zones than Russia. +</li> <li> -"<a href="https://www.youtube.com/watch?v=yRz-Dl60Lfc">Why Denmark used to be -.04 seconds behind the world</a>" (2019; 6:29) explains why the United Kingdom -— and, once, Denmark — haven't always exactly followed their own +“<a href="https://www.youtube.com/watch?v=yRz-Dl60Lfc">Why Denmark used to be +.04 seconds behind the world</a>” (2019; 6:29) explains why the United Kingdom +– and, once, Denmark – haven’t always exactly followed their own laws about civil time. +</li> <li> -"About Time" (1962; 59 minutes) is part of the +“<a href="https://www.youtube.com/watch?v=mfzsBMUiGGQ">How Daylight Savings +Broke this $24 Million Building</a>” (2025; 5:01) describes the system of +mirrors used at Melbourne’s Shrine of Remembrance to ensure the sun’s light +still hits at the “correct” ceremonial hour to commemorate the Armistice which +ended World War I. +</li> +<li> +“About Time” (1962; 59 minutes) is part of the Bell Science extravaganza, with Frank Baxter, Richard Deacon, and Les Tremayne. Its advisor was Richard Feynman, and it was voiced by Mel Blanc. -(<a href="https://www.imdb.com/title/tt0154110/">IMDb entry</a>.)</li> +(<a href="https://www.imdb.com/title/tt0154110/">IMDb entry</a>.) +</li> </ul> <h2>Movies</h2> <ul> @@ -39,15 +51,16 @@ In the 1946 movie <em>A Matter of Life and Death</em> (U.S. title <em>Stairway to Heaven</em>) there is a reference to British Double Summer Time. The time does not play a large part in the plot; -it's just a passing reference to the time when one of the -characters was supposed to have died (but didn't). +it’s just a passing reference to the time when one of the +characters was supposed to have died (but didn’t). (<a href="https://www.imdb.com/title/tt0038733/">IMDb entry.</a>) (Dave Cantor) +</li> <li> The 1953 railway comedy movie <em>The Titfield Thunderbolt</em> includes a -play on words on British Double Summer Time. Valentine's wife wants -him to leave the pub and asks him, "Do you know what time it is?" -And he, happy where he is, replies: "Yes, my love. Summer double time." +play on words on British Double Summer Time. Valentine’s wife wants +him to leave the pub and asks him, “Do you know what time it is?” +And he, happy where he is, replies: “Yes, my love. Summer double time.” (<a href="https://www.imdb.com/title/tt0046436/">IMDb entry.</a>) (Mark Brader, 2009-10-02) </li> @@ -60,12 +73,12 @@ is extended by 10 seconds, it will create a one-time opportunity for a gigantic computerized theft. To achieve this, at one location the crooks interfere with the microwave system supplying time signals to the computer, advancing the time by 0.1 second each minute over the -last hour of 1999. (So this movie teaches us that 0.1 × 60 = 10.) +last hour of 1999. (So this movie teaches us that 0.1 × 60 = 10.) (<a href="https://www.imdb.com/title/tt0137494/">IMDb entry.</a>) (Mark Brader, 2009-10-02) </li> <li> -One mustn't forget the +One mustn’t forget the <a href="https://www.youtube.com/watch?v=k4EUTMPuvHo">trailer</a> (2014; 2:23) for the movie <em>Daylight Saving</em>. </li> @@ -73,74 +86,74 @@ One mustn't forget the <h2>TV episodes</h2> <ul> <li> -An episode of <em>The Adventures of Superman</em> entitled "The Mysterious -Cube," first aired 1958-02-24, had Superman convincing the controllers +An episode of <em>The Adventures of Superman</em> entitled “The Mysterious +Cube”, first aired 1958-02-24, had Superman convincing the controllers of the Arlington Time Signal to broadcast ahead of actual time; doing so got a crook trying to be declared dead to emerge a bit too early from the titular enclosure. (<a href="https://www.imdb.com/title/tt0506628/">IMDb entry</a>.) </li> <li> -"<a href="https://en.wikipedia.org/wiki/The_Chimes_of_Big_Ben">The Chimes -of Big Ben</a>", <em>The Prisoner</em>, episode 2, ITC, 1967-10-06. +“<a href="https://en.wikipedia.org/wiki/The_Chimes_of_Big_Ben">The Chimes +of Big Ben</a>”, <em>The Prisoner</em>, episode 2, ITC, 1967-10-06. Our protagonist tumbles to -the fraudulent nature of a Poland-to-England escape upon hearing "Big -Ben" chiming on Polish local time. +the fraudulent nature of a Poland-to-England escape upon hearing Big +Ben chiming on Polish local time. (<a href="https://www.imdb.com/title/tt0679185/">IMDb entry.</a>) </li> <li> -"The Susie", <em>Seinfeld</em>, season 8, episode 15, NBC, 1997-02-13. +“The Susie”, <em>Seinfeld</em>, season 8, episode 15, NBC, 1997-02-13. Kramer decides that daylight saving time -isn't coming fast enough, so he sets his watch ahead an hour. +isn’t coming fast enough, so he sets his watch ahead an hour. </li> <li> -"20 Hours in America", <em>The West Wing</em>, season 4, episodes 1–2, +“20 Hours in America”, <em>The West Wing</em>, season 4, episodes 1–2, 2002-09-25, contained a <a href="https://www.youtube.com/watch?v=-J1NHzQ1sgc">scene</a> that saw White House staffers stranded in Indiana; they thought they had time to catch Air Force One but were done in by intra-Indiana local time changes. </li> <li> -"In what time zone would you find New York City?" was a $200 question on +“In what time zone would you find New York City?” was a $200 question on the 1999-11-13 United States airing of <em>Who Wants to Be a Millionaire?</em>, -and "In 1883, what industry led the movement to divide the U.S. into four time -zones?" was a $32,000 question on the 2001-05-23 United States airing of +and “In 1883, what industry led the movement to divide the U.S. into four time +zones?” was a $32,000 question on the 2001-05-23 United States airing of the same show. At this rate, the million-dollar time-zone question should have been asked 2002-06-04. </li> <li> -A private jet's mid-flight change of time zones distorts Alison Dubois' -premonition in the "We Had a Dream" episode of <em>Medium</em> +A private jet’s mid-flight change of time zones distorts Alison Dubois’ +premonition in the “We Had a Dream” episode of <em>Medium</em> (originally aired 2007-02-28). </li> <li> -A criminal's failure to account for the start of daylight saving is pivotal -in "<a href="https://monk.fandom.com/wiki/Mr._Monk_and_the_Rapper">Mr. Monk -and the Rapper</a>" (first aired 2007-07-20). +A criminal’s failure to account for the start of daylight saving is pivotal +in “<a href="https://monk.fandom.com/wiki/Mr._Monk_and_the_Rapper">Mr. Monk +and the Rapper</a>” (first aired 2007-07-20). </li> <li> -In the <em>30 Rock</em> episode "Anna Howard Shaw Day" +In the <em>30 Rock</em> episode “Anna Howard Shaw Day” (first broadcast 2010-02-11), -Jack Donaghy's date realizes that a Geneva-to-New-York business phone call +Jack Donaghy’s date realizes that a Geneva-to-New-York business phone call received in the evening must be fake given the difference in local times. </li> <li> -In the "Run by the Monkeys" episode of <em>Da Vinci's Inquest</em> +In the “Run by the Monkeys” episode of <em>Da Vinci’s Inquest</em> (first broadcast 2002-11-17), a witness in a five-year-old fire case realizes they may not have set their clock back when daylight saving ended on the day of the fire, introducing the possibility of an hour when arson might have occurred. </li> <li> -In "The Todd Couple" episode of <em>Outsourced</em> (first aired 2011-02-10), -Manmeet sets up Valentine's Day teledates for 6:00 and 9:00pm; +In “The Todd Couple” episode of <em>Outsourced</em> (first aired 2011-02-10), +Manmeet sets up Valentine’s Day teledates for 6:00 and 9:00pm; since one is with a New Yorker and the other with a San Franciscan, hilarity ensues. (Never mind that this should be 7:30am in Mumbai, yet for some reason the show -proceeds as though it's also mid-evening there.) +proceeds as though it’s also mid-evening there.) </li> <li> -In the "14 Days to Go"/"T Minus..." episode of +In the “14 Days to Go”/“T Minus...” episode of <em>You, Me and the Apocalypse</em> (first aired 2015-11-11 in the UK, 2016-03-10 in the US), the success of a mission to deal with a comet @@ -149,39 +162,39 @@ hinges on whether or not Russia observes daylight saving time. the episode first aired in the week before the switch to <abbr>DST</abbr>.) </li> <li> -"The Lost Hour", <em>Eerie, Indiana</em>, episode 10, NBC, 1991-12-01. -Despite Indiana's then-lack of <abbr>DST</abbr>, +“The Lost Hour”, <em>Eerie, Indiana</em>, episode 10, NBC, 1991-12-01. +Despite Indiana’s then-lack of <abbr>DST</abbr>, Marshall changes his clock with unusual consequences. -See "<a +See “<a href="https://www.avclub.com/eerie-indiana-was-a-few-dimensions-ahead-of-its-time-1819833380"><em>Eerie, -Indiana</em> was a few dimensions ahead of its time</a>". +Indiana</em> was a few dimensions ahead of its time</a>”. </li> <li> -"Time Tunnel", <em>The Adventures of Pete & Pete</em>, season 2, episode 5, -Nickelodeon, 1994-10-23. +“Time Tunnel”, <em>The Adventures of Pete & Pete</em>, +season 2, episode 5, Nickelodeon, 1994-10-23. The two Petes travel back in time an hour on the day that <abbr>DST</abbr> ends. </li> <li> -"King-Size Homer", <em>The Simpsons</em>, episode 135, Fox, 1995-11-05. -Homer, working from home, remarks "8:58, first -time I've ever been early for work. Except for all those daylight -savings days. Lousy farmers." +“King-Size Homer”, <em>The Simpsons</em>, episode 135, Fox, 1995-11-05. +Homer, working from home, remarks “8:58, first +time I’ve ever been early for work. Except for all those daylight +savings days. Lousy farmers.” </li> <li> <em>Last Week Tonight with John Oliver</em>, season 2, episode 5, 2015-03-08, -asked, "<a href="https://www.youtube.com/watch?v=br0NW9ufUUw">Daylight Saving -Time – How Is This Still A Thing?</a>" +asked, “<a href="https://www.youtube.com/watch?v=br0NW9ufUUw">Daylight +Saving Time – How Is This Still A Thing?</a>” </li> <li> -"Tracks", <em>The Good Wife</em>, season 7, episode 12, +“Tracks”, <em>The Good Wife</em>, season 7, episode 12, CBS, 2016-01-17. The applicability of a contract hinges on the time zone associated with a video timestamp. </li> <li> -"Justice", <em>Veep</em>, season 6, episode 4, HBO, 2017-05-07. -Jonah's inability to understand <abbr>DST</abbr> ends up impressing a wealthy +“Justice”, <em>Veep</em>, season 6, episode 4, HBO, 2017-05-07. +Jonah’s inability to understand <abbr>DST</abbr> ends up impressing a wealthy backer who sets him up for a 2020 presidential run. </li> </ul> @@ -198,7 +211,7 @@ Available versions include <a href="https://www.gutenberg.org/ebooks/103">an English translation</a>, and <a href="https://fourmilab.ch/etexts/www/tdm80j">the original French</a> -"with illustrations from the original 1873 French-language edition". +“with illustrations from the original 1873 French-language edition”. </li> <li> Nick Enright, <em>Daylight Saving</em>, 1989. @@ -208,24 +221,24 @@ A fast-paced comedy about love and loneliness as the clocks turn back. Umberto Eco, <a href="https://en.wikipedia.org/wiki/The_Island_of_the_Day_Before"><em>The Island of the Day Before</em></a> -(<em>L'isola del giorno prima</em>), 1994. -"...the story of a 17th century Italian nobleman trapped near an island +(<em>L’isola del giorno prima</em>), 1994. +“...the story of a 17th century Italian nobleman trapped near an island on the International Date Line. Time and time zones play an integral -part in the novel." (Paul Eggert, 2006-04-22) +part in the novel.” (Paul Eggert, 2006-04-22) </li> <li> John Dunning, <a href="https://www.simonandschuster.com/books/Two-OClock-Eastern-Wartime/John-Dunning/9781439171530"><em>Two -O'Clock, Eastern Wartime</em></a>, 2001. +O’Clock, Eastern Wartime</em></a>, 2001. Mystery, history, daylight saving time, and old-time radio. </li> <li> -Surrealist artist Guy Billout's work "Date Line" appeared on page 103 -of the 1999-11 <em>Atlantic Monthly</em>. +Surrealist artist Guy Billout’s work “Date Line” +appeared on page 103 of the 1999-11 <em>Atlantic Monthly</em>. </li> <li> -"Gloom, Gloom, Go Away" by Walter Kirn appeared on page 106 of <em>Time</em> -magazine's 2002-11-11 issue; among other things, it proposed +“Gloom, Gloom, Go Away” by Walter Kirn appeared on page 106 of <em>Time</em> +magazine’s 2002-11-11 issue; among other things, it proposed year-round <abbr>DST</abbr> as a way of lessening wintertime despair. </li> <li> @@ -237,20 +250,20 @@ href="https://craphound.com/est/download/"><em>Eastern Standard Tribe</em></a>, <h2>Music</h2> <ul> <li> -Recordings of "Save That Time," Russ Long, Serrob Publishing, BMI: +Recordings of “Save That Time”, Russ Long, Serrob Publishing, BMI: <ul> <li> -Karrin Allyson, <em>I Didn't Know About You</em> (1993), track 11, 3:44. +Karrin Allyson, <em>I Didn’t Know About You</em> (1993), track 11, 3:44. Concord Jazz CCD-4543. Karrin Allyson, vocal; Russ Long, piano; Gerald Spaits, bass; Todd Strait, drums. -CD notes "additional lyric by Karrin Allyson; -arranged by Russ Long and Karrin Allyson". -ADO ★, +CD notes “additional lyric by Karrin Allyson; +arranged by Russ Long and Karrin Allyson”. +ADO ★, <a href="https://www.allmusic.com/album/i-didnt-know-about-you-mw0000618657">AMG</a> -★★★★, Penguin ★★★⯪. +★★★★, Penguin ★★★⯪. </li> <li> Kevin Mahogany, <em>Double Rainbow</em> (1993), track 3, 6:27. Enja ENJ-7097 2. @@ -259,18 +272,18 @@ Kenny Barron, piano; Ray Drummond, bass; Ralph Moore, tenor saxophone; Lewis Nash, drums. -ADO ★⯪, +ADO ★⯪, <a href="https://www.allmusic.com/album/double-rainbow-mw0000620371">AMG</a> -★★★, Penguin ★★★. +★★★, Penguin ★★★. </li> <li> -Joe Williams, <em>Here's to Life</em> (1994), track 7, 3:58. +Joe Williams, <em>Here’s to Life</em> (1994), track 7, 3:58. Telarc Jazz CD-83357. Joe Williams, vocal; The Robert Farnon [39 piece] Orchestra. -Also in a 3-CD package "Triple Play", Telarc CD-83461. -ADO •, +Also in a 3-CD package “Triple Play”, Telarc CD-83461. +ADO •, <a href="https://www.allmusic.com/album/heres-to-life-mw0000623648">AMG</a> -★★, Penguin ★★★. +★★, Penguin ★★★. </li> <li> Charles Fambrough, <em>Keeper of the Spirit</em> (1995), track 7, 7:07. @@ -280,9 +293,9 @@ Joel Levine, tenor recorder; Edward Simon, piano; Lenny White, drums; Marion Simon, percussion. -ADO ★, +ADO ★, <a href="https://www.allmusic.com/album/keeper-of-the-spirit-mw0000176559">AMG</a> -unrated, Penguin ★★★. +unrated, Penguin ★★★. </ul> </li> <li> @@ -290,11 +303,11 @@ Holly Cole Trio, Blame It On My Youth (1992). Manhattan CDP 7 97349 2, 37:45. Holly Cole, voice; Aaron Davis, piano; David Piltch, string bass. -Lyrical reference to "Eastern Standard Time" in -Tom Waits's "Purple Avenue". -ADO ★★⯪, +Lyrical reference to “Eastern Standard Time” in +Tom Waits’s “Purple Avenue”. +ADO ★★⯪, <a href="https://www.allmusic.com/album/blame-it-on-my-youth-mw0000274303">AMG</a> -★★★, Penguin unrated. +★★★, Penguin unrated. </li> <li> Milt Hinton, @@ -314,15 +327,15 @@ drums; Lionel Hampton, vibraphone; Cab Calloway, Joe Williams, vocal; Buck Clayton, arrangements. -Tunes include "Old Man Time", "Time After Time", -"Sometimes I'm Happy", -"A Hot Time in the Old Town Tonight", -"Four or Five Times", "Now's the Time", -"Time on My Hands", "This Time It's Us", -and "Good Time Charlie". -ADO ★★★, +Tunes include “Old Man Time”, “Time After Time”, +“Sometimes I’m Happy”, +“A Hot Time in the Old Town Tonight”, +“Four or Five Times”, “Now’s the Time”, +“Time on My Hands”, “This Time It’s Us”, +and “Good Time Charlie”. +ADO ★★★, <a href="https://www.allmusic.com/album/old-man-time-mw0000269353">AMG</a> -★★★★⯪, Penguin ★★★. +★★★★⯪, Penguin ★★★. </li> <li> Alan Broadbent, <em>Pacific Standard Time</em> (1995). @@ -331,9 +344,9 @@ Alan Broadbent, piano; Putter Smith, Bass; Frank Gibson, Jr., drums. The CD cover features an analemma for equation-of-time fans. -ADO ★, +ADO ★, <a href="https://www.allmusic.com/album/pacific-standard-time-mw0000645433">AMG</a> -★★★★, Penguin ★★★⯪. +★★★★, Penguin ★★★⯪. </li> <li> Anthony Braxton/Richard Teitelbaum, <em>Silence/Time Zones</em> (1996). @@ -343,88 +356,89 @@ contrebasse clarinet, miscellaneous instruments; Leo Smith, trumpet and miscellaneous instruments; Leroy Jenkins, violin and miscellaneous instruments; Richard Teitelbaum, modular moog and micromoog synthesizer. -ADO •, +ADO •, <a href="https://www.allmusic.com/album/silence-time-zones-mw0000595735">AMG</a> -★★★★. +★★★★. </li> <li> Charles Gayle, <em>Time Zones</em> (2006). Tompkins Square TSQ2839, 49:06. Charles Gayle, piano. -ADO ★, +ADO ★, <a href="https://www.allmusic.com/album/time-zones-mw0000349642">AMG</a> -★★★★⯪. +★★★★⯪. </li> <li> The Get Up Kids, <em>Eudora</em> (2001). Vagrant 357, 65:12. -Includes the song "Central Standard Time." +Includes the song “Central Standard Time”. Thanks to Colin Bowern for this information. <a href="https://www.allmusic.com/album/eudora-mw0000592063">AMG</a> -★★⯪. +★★⯪. </li> <li> -Coldplay, "Clocks" (2003). +Coldplay, “Clocks” (2003). Capitol 52608, 4:13. Won the 2004 Record of the Year honor at the Grammy Awards. Co-written and performed by Chris Martin, great-great-grandson of <abbr>DST</abbr> inventor William Willett. -The song's first line is "Lights go out and I can't be saved". +The song’s first line is “Lights go out and I can’t be saved”. </li> <li> -Jaime Guevara, "<a -href="https://www.youtube.com/watch?v=ZfN4Fe_A50U">Qué -hora es</a>" (1993), 3:04. -The song protested "Sixto Hour" in Ecuador -(1992–3). Its lyrics include "Amanecía en mitad de la noche, los -guaguas iban a clase sin sol" ("It was dawning in the middle of the -night, the buses went to class without sun"). +Jaime Guevara, “<a +href="https://www.youtube.com/watch?v=ZfN4Fe_A50U">Qué +hora es</a>” (1993), 3:04. +The song protested “Sixto Hour” in Ecuador +(1992–3). Its lyrics include “Amanecía en mitad de la noche, los +guaguas iban a clase sin sol” (“It was dawning in the middle of the +night, the buses went to class without sun”). </li> <li> Irving Kahal and Harry Richman, -"There Ought to be a Moonlight Saving Time" (1931). +“There Ought to be a Moonlight Saving Time” (1931). This musical standard was a No. 1 hit for Guy Lombardo in 1931, and was also performed by Maurice Chevalier, Blossom Dearie -and many others. The phrase "Moonlight saving time" also appears in -the 1995 country song "Not Enough Hours in the Night" written by Aaron +and many others. The phrase “Moonlight saving time” also appears in +the 1995 country song “Not Enough Hours in the Night” written by Aaron Barker, Kim Williams and Rob Harbin and performed by Doug Supernaw. </li> <li> The Microscopic Septet, <em>Lobster Leaps In</em> (2008). Cuneiform 272, 73:05. -Includes the song "Twilight Time Zone." -ADO ★★, +Includes the song “Twilight Time Zone”. +ADO ★★, <a href="https://www.allmusic.com/album/lobster-leaps-in-mw0000794929">AMG</a> -★★★⯪. +★★★⯪. </li> <li> -Bob Dylan, <em>The Times They Are a-Changin'</em> (1964). +Bob Dylan, <em>The Times They Are a-Changin’</em> (1964). Columbia CK-8905, 45:36. -ADO ★⯪, +ADO ★⯪, <a href="https://www.allmusic.com/album/the-times-they-a-changin-mw0000202344">AMG</a> -★★★★⯪. -The title song is also available on "Bob Dylan's Greatest Hits" and "The Essential Bob Dylan." +★★★★⯪. +The title song is also available on “Bob Dylan’s Greatest Hits” +and “The Essential Bob Dylan”. </li> <li> Luciana Souza, <em>Tide</em> (2009). Universal Jazz France B0012688-02, 42:31. -ADO ★★⯪, +ADO ★★⯪, <a href="https://www.allmusic.com/album/tide-mw0000815692">AMG</a> -★★★⯪. -Includes the song "Fire and Wood" with the lyric -"The clocks were turned back you remember/Think it's still November." +★★★⯪. +Includes the song “Fire and Wood” with the lyric +“The clocks were turned back you remember/Think it’s still November.” </li> <li> -Ken Nordine, <em>You're Getting Better: The Word Jazz Dot Masters</em> (2005). +Ken Nordine, <em>You’re Getting Better: The Word Jazz Dot Masters</em> (2005). Geffen B0005171-02, 156:22. -ADO ★, +ADO ★, <a href="https://www.allmusic.com/album/youre-getting-better-the-word-jazz-dot-masters-mw0000736197">AMG</a> -★★★★⯪. -Includes the piece "What Time Is It" -("He knew what time it was everywhere...that counted"). +★★★★⯪. +Includes the piece “What Time Is It” +(“He knew what time it was everywhere...that counted”). </li> <li> Chicago, <em>Chicago Transit Authority</em> (1969). Columbia 64409, 1:16:20. -<a href="https://www.allmusic.com/album/chicago-transit-authority-mw0000189364">AMG</a> ★★★★. -Includes the song "Does Anybody Really Know What Time It Is?". +<a href="https://www.allmusic.com/album/chicago-transit-authority-mw0000189364">AMG</a> ★★★★. +Includes the song “Does Anybody Really Know What Time It Is?”. </li> <li> Emanuele Arciuli, @@ -440,27 +454,27 @@ Unlike minimalism, it does not assume that the listener has plenty of time. <ul> <li> The webcomic <em>xkcd</em> has the strips -"<a href="https://xkcd.com/673/">The Sun</a>" (2009-12-09), -"<a href="https://xkcd.com/1655/">Doomsday Clock</a>" (2016-03-14) and -"<a href="https://xkcd.com/2549/">Edge Cake</a>" (2021-12-01), +“<a href="https://xkcd.com/673/">The Sun</a>” (2009-12-09), +“<a href="https://xkcd.com/1655/">Doomsday Clock</a>” (2016-03-14) and +“<a href="https://xkcd.com/2549/">Edge Cake</a>” (2021-12-01), along with the panels -"<a href="https://xkcd.com/448/">Good Morning</a>" (2008-07-11), -"<a href="https://xkcd.com/1017/">Backward in Time</a>" (2012-02-14), -"<a href="https://xkcd.com/1061/">EST</a>" (2012-05-28), -"<a href="https://xkcd.com/1179/">ISO 8601</a>" (2013-02-27), -"<a href="https://xkcd.com/1335/">Now</a>" (2014-02-26), -"<a href="https://xkcd.com/1799/">Bad Map Projection: Time Zones</a>" +“<a href="https://xkcd.com/448/">Good Morning</a>” (2008-07-11), +“<a href="https://xkcd.com/1017/">Backward in Time</a>” (2012-02-14), +“<a href="https://xkcd.com/1061/">EST</a>” (2012-05-28), +“<a href="https://xkcd.com/1179/">ISO 8601</a>” (2013-02-27), +“<a href="https://xkcd.com/1335/">Now</a>” (2014-02-26), +“<a href="https://xkcd.com/1799/">Bad Map Projection: Time Zones</a>” (2017-02-15), -"<a href="https://xkcd.com/1883/">Supervillain Plan</a>" (2017-08-30), -"<a href="https://xkcd.com/2050/">6/6 Time</a>" (2018-09-24), -"<a href="https://xkcd.com/2092/">Consensus New Year</a>" (2018-12-31), -"<a href="https://xkcd.com/2266/">Leap Smearing</a>" (2020-02-10), -"<a href="https://xkcd.com/2594/">Consensus Time</a>" (2022-03-16), -"<a href="https://xkcd.com/2846/">Daylight Saving Choice</a>" (2023-10-25), -"<a href="https://xkcd.com/2854/">Date Line</a>" (2023-11-13), -and "<a href="https://xkcd.com/2867/">DateTime</a>" (2023-12-13). +“<a href="https://xkcd.com/1883/">Supervillain Plan</a>” (2017-08-30), +“<a href="https://xkcd.com/2050/">6/6 Time</a>” (2018-09-24), +“<a href="https://xkcd.com/2092/">Consensus New Year</a>” (2018-12-31), +“<a href="https://xkcd.com/2266/">Leap Smearing</a>” (2020-02-10), +“<a href="https://xkcd.com/2594/">Consensus Time</a>” (2022-03-16), +“<a href="https://xkcd.com/2846/">Daylight Saving Choice</a>” (2023-10-25), +“<a href="https://xkcd.com/2854/">Date Line</a>” (2023-11-13), +and “<a href="https://xkcd.com/2867/">DateTime</a>” (2023-12-13). The related book <em>What If?</em> has an entry -"<a href="https://what-if.xkcd.com/26/">Leap Seconds</a>" (2012-12-31). +“<a href="https://what-if.xkcd.com/26/">Leap Seconds</a>” (2012-12-31). </li> <li> Pig kills time in <a @@ -480,112 +494,116 @@ Caulfield proposes changing clocks just once a year in (the same day)</a>. </li> <li> -Peppermint Patty: "What if the world comes to an end tonight, Marcie?" +Peppermint Patty: “What if the world comes to an end tonight, Marcie?” <br> -Marcie: "I promise there'll be a tomorrow, sir ... in fact, -it's already tomorrow in Australia!" +Marcie: “I promise there’ll be a tomorrow, sir ... in fact, +it’s already tomorrow in Australia!” <br> -(Charles M. Schulz, <a href="https://www.gocomics.com/peanuts/1980/06/13"><em>Peanuts</em>, 1980-06-13</a>) +(Charles M. Schulz, +<a href="https://www.gocomics.com/peanuts/1980/06/13"><em>Peanuts</em>, +1980-06-13</a>) </li> </ul> <h2>Jokes</h2> <ul> <li> The idea behind daylight saving time was first proposed as a joke by -Benjamin Franklin. To enforce it, he suggested, "Every +Benjamin Franklin. To enforce it, he suggested, “Every morning, as soon as the sun rises, let all the bells in every church be set ringing; and if that is not sufficient, let cannon be fired in every street, to wake the sluggards effectually, and make them open their eyes to see their true interest. All the difficulty will be in the first two or three days: after which the reformation will be as -natural and easy as the present irregularity; for, <em>ce n'est que le -premier pas qui coûte</em>." -<a href="http://www.webexhibits.org/daylightsaving/franklin3.html">Franklin's +natural and easy as the present irregularity; for, <em>ce n’est que le +premier pas qui coûte</em>.” +<a href="http://www.webexhibits.org/daylightsaving/franklin3.html">Franklin’s joke</a> was first published on 1784-04-26 by the <em>Journal de Paris</em> as <a href="https://en.wikipedia.org/wiki/File:Franklin-Benjamin-Journal-de-Paris-1784.jpg">an anonymous letter translated into French</a>. </li> <li> -"We've been using the five-cent nickel in this country since 1492. -Now that's pretty near 100 years, daylight saving." +“We’ve been using the five-cent nickel in this country since 1492. +Now that’s pretty near 100 years, daylight saving.” (Groucho Marx as Captain Spaulding in <em>Animal Crackers</em>, 1930, as noted by Will Fitzgerald) </li> <li> BRADY. ...[Bishop Usher] determined that the Lord began the Creation -on the 23rd of October in the Year 4,004 B.C. at – uh, 9 A.M.! +on the 23rd of October in the Year 4,004 B.C. at – uh, 9 A.M.! <br> DRUMMOND. That Eastern Standard Time? (<em>Laughter.</em>) Or Rocky Mountain -Time? (<em>More laughter.</em>) It wasn't daylight-saving time, was it? Because -the Lord didn't make the sun until the fourth day! +Time? (<em>More laughter.</em>) It wasn’t daylight-saving time, was it? Because +the Lord didn’t make the sun until the fourth day! <br> (From the play <em>Inherit the Wind</em> by Jerome Lawrence and Robert E. Lee, filmed in 1960 with Spencer Tracy as Drummond and Fredric March as Brady, and several other times. Thanks to Mark Brader.) </li> <li> -"Good news." -"What did they do? Extend Daylight Saving Time year round?" +“Good news.” +“What did they do? Extend Daylight Saving Time year round?” (Professional tanner George Hamilton, in dialog from a May, 1999 episode of the syndicated television series <em>Baywatch</em>) </li> <li> -"A fundamental belief held by Americans is that if you are on land, you +“A fundamental belief held by Americans is that if you are on land, you cannot be killed by a fish...So most Americans remain on land, believing -they're safe. Unfortunately, this belief – like so many myths, such as that -there's a reason for 'Daylight Saving Time' – is false." +they’re safe. Unfortunately, this belief – like so many myths, such as that +there’s a reason for ‘Daylight Saving Time’ – is false.” (Dave Barry column, 2000-07-02) </li> <li> -"I once had sex for an hour and five minutes, but that was on the day -when you turn the clocks ahead." +“I once had sex for an hour and five minutes, but that was on the day +when you turn the clocks ahead.” (Garry Shandling, 52nd Annual Emmys, 2000-09-10) </li> <li> -"Would it impress you if I told you I invented Daylight Savings Time?" -("Sahjhan" to "Lilah" in dialog from the "Loyalty" episode of <em>Angel</em>, +“Would it impress you if I told you I invented Daylight Savings Time?” +(“Sahjhan” to “Lilah” in dialog from the “Loyalty” episode of <em>Angel</em>, originally aired 2002-02-25) </li> <li> -"I thought you said Tulsa was a three-hour flight." -"Well, you're forgetting about the time difference." -("Joey" and "Chandler" in dialog from the episode of <em>Friends</em> -entitled "The One With Rachel's Phone Number," originally aired 2002-12-05) +“I thought you said Tulsa was a three-hour flight.” +“Well, you’re forgetting about the time difference.” +(“Joey” and “Chandler” in dialog from the +episode of <em>Friends</em> entitled “The One With +Rachel’s Phone Number”, originally aired 2002-12-05) </li> <li> -"Is that a pertinent fact, -or are you just trying to dazzle me with your command of time zones?" -(Kelsey Grammer as "Frasier Crane" to "Roz" from the episode of <em>Frasier</em> -entitled "The Kid," originally aired 1997-11-04) +“Is that a pertinent fact, +or are you just trying to dazzle me with your command of time zones?” +(Kelsey Grammer as “Frasier Crane” to “Roz” +from the episode of <em>Frasier</em> entitled “The Kid”, +originally aired 1997-11-04) </li> <li> -"I put myself and my staff through this crazy, huge ordeal, all because +“I put myself and my staff through this crazy, huge ordeal, all because I refused to go on at midnight, okay? And so I work, you know, and then I get this job at eleven, supposed to be a big deal. Then -yesterday daylight [saving] time ended. Right now it's basically -midnight." (Conan O'Brien on the 2010-11-08 premiere of <em>Conan</em>) +yesterday daylight [saving] time ended. Right now it’s basically midnight.” +(Conan O’Brien on the 2010-11-08 premiere of <em>Conan</em>) </li> <li> -"The best method, I told folks, was to hang a large clock high on a +“The best method, I told folks, was to hang a large clock high on a barn wall where all the cows could see it. If you have Holsteins, you -will need to use an analog clock." (Jerry Nelson, <a +will need to use an analog clock.” (Jerry Nelson, “<a href="http://www.agriculture.com/family/farm-humor/how-to-adjust-dairy-cows-to-daylight-savings-time">How -to adjust dairy cows to daylight saving time</a>", <em>Successful Farming</em>, -2017-10-09) +to adjust dairy cows to daylight saving time</a>”, +<em>Successful Farming</em>, 2017-10-09) </li> <li> -"And now, driving to California, I find that I must enter a password +“And now, driving to California, I find that I must enter a password in order to change the time zone on my laptop clock. Evidently, -someone is out to mess up my schedule and my clock must be secured." +someone is out to mess up my schedule and my clock must be secured.” (Garrison Keillor, -"<a href="http://www.garrisonkeillor.com/weve-never-been-here-before/">We've -never been here before</a>", 2017-08-22) +“<a href="http://www.garrisonkeillor.com/weve-never-been-here-before/">We’ve +never been here before</a>”, 2017-08-22) </li> <li> -"Well, in my time zone that's all the time I have, -but maybe in your time zone I haven't finished yet. So stay tuned!" -(Goldie Hawn, <em>Rowan & Martin's Laugh-In</em> No. 65, 1970-03-09) +“Well, in my time zone that’s all the time I have, +but maybe in your time zone I haven’t finished yet. So stay tuned!” +(Goldie Hawn, <em>Rowan & Martin’s Laugh-In</em> No. 65, 1970-03-09) </li> </ul> <h2>See also</h2> @@ -593,13 +611,16 @@ but maybe in your time zone I haven't finished yet. So stay tuned!" <li><a href="tz-link.html">Time Zone and Daylight Saving Time Data</a></li> </ul> + +<footer> <hr> -<address> This web page is in the public domain, so clarified as of 2009-05-17 by Arthur David Olson. <br> Please send corrections to this web page to the <a href="mailto:tz@iana.org">time zone mailing list</a>. -</address> +The mailing list and its archives are public, +so please do not send confidential information. +</footer> </body> </html> diff --git a/tz-how-to.html b/tz-how-to.html index 9e438f93092a..ccfdc9eb4fdb 100644 --- a/tz-how-to.html +++ b/tz-how-to.html @@ -23,18 +23,18 @@ times of day from the <a href="tz-link.html">tz database</a> source files. It might be helpful, but not absolutely necessary, for the reader to have already downloaded the latest release of the database and become familiar with the basic layout -of the data files. The format is explained in the “man -page” for the zic compiler, <code>zic.8.txt</code>, in +of the data files. The format is explained in the “man page” +for the zic compiler, <code>zic.8.txt</code>, in the <code>code</code> subdirectory. Although this guide covers many of the common cases, it is not a complete summary of what zic accepts; the man page is the authoritative reference.</p> -<p>We’ll begin by talking about the rules for changing between standard -and daylight saving time since we’ll need that information when we talk +<p>We’ll begin by talking about the rules for changing between standard +and daylight saving time since we’ll need that information when we talk about the zones.</p> -<p>First, let’s consider the special daylight saving time rules +<p>First, let’s consider the special daylight saving time rules for Chicago (from the <code>northamerica</code> file in the <code>data</code> subdirectory):</p> @@ -107,7 +107,7 @@ first and last calendar years defining a contiguous range over which a specific Rule line is to apply. The keyword <code>only</code> can be used in the <code>TO</code> field to repeat the value of the <code>FROM</code> field in the event that a rule should only apply to a single year. Often, the keyword -<code>max</code> is used to extend a rule’s application into the +<code>max</code> is used to extend a rule’s application into the indefinite future; it is a platform-agnostic stand-in for the largest representable year. @@ -117,28 +117,28 @@ Prior to the 2020b release, it was called the <code>TYPE</code> field, though it had not been used in the main data since the 2000e release. An obsolescent supplementary file used the field as a proof-of-concept to allow <code>zic</code> to apply a given Rule -line only to certain “types” of years within the specified range as +line only to certain “types” of years within the specified range as dictated by the output of a separate script, such as: only years which would -have a US presidential election, or only years which wouldn’t. +have a US presidential election, or only years which wouldn’t. <p>The <code>SAVE</code> column contains the local (wall clock) offset from local standard time. This is usually either zero for standard time or one hour for daylight -saving time; but there’s no reason, in principle, why it can’t +saving time; but there’s no reason, in principle, why it can’t take on other values. <p>The <code>LETTER</code> (sometimes called <code>LETTER/S</code>) column can contain a variable -part of the usual abbreviation of the time zone’s name, or it can just -be a hyphen if there’s no variable part. For example, the abbreviation -used in the central time zone will be either “CST” or -“CDT”. The variable part is ‘S’ or ‘D’; -and, sure enough, that’s just what we find in +part of the usual abbreviation of the time zone’s name, or it can just +be a hyphen if there’s no variable part. For example, the abbreviation +used in the central time zone will be either “CST” or “CDT”. +The variable part is ‘S’ or ‘D’; +and, sure enough, that’s just what we find in the <code>LETTER</code> column in the <code>Chicago</code> rules. More about this when we talk about -“Zone” lines. +“Zone” lines. -<p>One important thing to notice is that “Rule” lines +<p>One important thing to notice is that “Rule” lines want at once to be both <i>transitions</i> and <i>steady states</i>: <ul> <li>On the one hand, they represent transitions between standard and @@ -158,7 +158,7 @@ years. Similarly, the rule for changing to daylight saving time was the same from 1922 to 1966; but the rule for returning to standard time changed in 1955. Got it?</p> -<p>OK, now for the somewhat more interesting “US” rules:</p> +<p>OK, now for the somewhat more interesting “US” rules:</p> <table> <tr> @@ -211,15 +211,15 @@ Rule US 2007 max - Nov Sun>=1 2:00 0 S <tr> <td colspan="2">1942 only</td> <td colspan="2">February 9<small><sup>th</sup></small></td> - <td>go to “war time”</td> + <td>go to “war time”</td> </tr> <tr> <td colspan="2" rowspan="2">1945 only</td> <td colspan="2">August 14<small><sup>th</sup></small></td> <td>23:00 <a href="https://en.wikipedia.org/wiki/Universal_Time">UT</a></td> <td> - rename “war time” to “peace<br>time;” - clocks don’t change + rename “war time” to “peace<br>time;” + clocks don’t change </td> </tr> <tr> @@ -272,33 +272,33 @@ Rule US 2007 max - Nov Sun>=1 2:00 0 S <p>First, the time that something happens (in the <code>AT</code> column) is not necessarily the local (wall clock) time. The time can be -suffixed with ‘s’ (for “standard”) to mean +suffixed with ‘s’ (for “standard”) to mean local standard time, different from local (wall clock) time when observing -daylight saving time; or it can be suffixed with ‘g’, -‘u’, or ‘z’, all three of which mean the +daylight saving time; or it can be suffixed with ‘g’, +‘u’, or ‘z’, all three of which mean the standard time at the <a href="https://en.wikipedia.org/wiki/Prime_Meridian">prime meridian</a>. -‘g’ stands for “<a -href="https://en.wikipedia.org/wiki/Greenwich_Mean_Time">GMT</a>”; -‘u’ stands for “<a -href="https://en.wikipedia.org/wiki/Universal_Time">UT</a>” or “<a -href="https://en.wikipedia.org/wiki/Coordinated_Universal_Time">UTC</a>” -(whichever was official at the time); ‘z’ stands for the +‘g’ stands for “<a +href="https://en.wikipedia.org/wiki/Greenwich_Mean_Time">GMT</a>”; +‘u’ stands for “<a +href="https://en.wikipedia.org/wiki/Universal_Time">UT</a>” or “<a +href="https://en.wikipedia.org/wiki/Coordinated_Universal_Time">UTC</a>” +(whichever was official at the time); ‘z’ stands for the <a href="https://en.wikipedia.org/wiki/Nautical_time">nautical time zone</a> -Z (a.k.a. “Zulu” which, in turn, stands for ‘Z’). -The time can also be suffixed with ‘w’ meaning local (wall -clock) time; but it usually isn’t because that’s the +Z (a.k.a. “Zulu” which, in turn, stands for ‘Z’). +The time can also be suffixed with ‘w’ meaning local (wall +clock) time; but it usually isn’t because that’s the default.</p> <p>Second, the day in the <code>ON</code> column, in addition to -“<code>lastSun</code>” or a particular day of the month, -can have the form, “<code>Sun>=</code><i>x</i>” or -“<code>Sun<=</code><i>x</i>,” where <i>x</i> is a day -of the month. For example, “<code>Sun>=8</code>” means -“the first Sunday on or after the eighth of the month,” in +“<code>lastSun</code>” or a particular day of the month, +can have the form, “<code>Sun>=</code><i>x</i>” or +“<code>Sun<=</code><i>x</i>,” where <i>x</i> is a day +of the month. For example, “<code>Sun>=8</code>” means +“the first Sunday on or after the eighth of the month,” in other words, the second Sunday of the month. Furthermore, although -there are no examples above, the weekday needn’t be -“<code>Sun</code>” in either form, but can be the usual +there are no examples above, the weekday needn’t be +“<code>Sun</code>” in either form, but can be the usual three-character English abbreviation for any day of the week.</p> <p>And the US rules give us more examples of a couple of things @@ -317,8 +317,8 @@ state or other more local rule).</li> <li>The <code>SAVE</code> and <code>LETTER</code> columns contain <i>steady state</i>, not transitions. Consider, for example, -the transition from “war time” to “peace time” -that happened on August 14, 1945. The “1:00” in +the transition from “war time” to “peace time” +that happened on August 14, 1945. The “1:00” in the <code>SAVE</code> column is <i>not</i> an instruction to advance the clock an hour. It means that clocks should <i>be</i> one hour ahead of standard time, which they already are because of the previous @@ -326,7 +326,7 @@ rule, so there should be no change.</li> </ul> -<p>OK, now let’s look at a Zone record:</p> +<p>OK, now let’s look at a Zone record:</p> <table> <tr> @@ -365,14 +365,14 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24 <th>Time</th> </tr> <tr> - <td>−5:50:36</td> + <td>−5:50:36</td> <td>not observed</td> <td>LMT</td> <td>1883-11-18</td> <td>12:09:24</td> </tr> <tr> - <td rowspan="2">−6:00:00</td> + <td rowspan="2">−6:00:00</td> <td>US rules</td> <td rowspan="2">CST or CDT</td> <td>1920-01-01</td> @@ -384,13 +384,13 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24 <td rowspan="2">02:00:00</td> </tr> <tr> - <td>−5:00:00</td> + <td>−5:00:00</td> <td>not observed</td> <td>EST</td> <td>1936-11-15</td> </tr> <tr> - <td rowspan="4">−6:00:00</td> + <td rowspan="4">−6:00:00</td> <td>Chicago rules</td> <td>CST or CDT</td> <td>1942-01-01</td> @@ -408,7 +408,7 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24 </tr> <tr> <td>US rules</td> - <td colspan="2">—</td> + <td colspan="2">–</td> </tr> </table> @@ -417,24 +417,24 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24 <p>First, and somewhat trivially, whereas Rules are considered to contain one or more records, a Zone is considered to be a single record with zero or more <i>continuation lines</i>. Thus, the keyword, -“<code>Zone</code>,” and the zone name are not +“<code>Zone</code>,” and the zone name are not repeated. The last line is the one without anything in the <code>[UNTIL]</code> column.</p> <p>Second, and more fundamentally, each line of a Zone represents a steady state, not a transition between states. The state exists from -the date and time in the previous line’s <code>[UNTIL]</code> +the date and time in the previous line’s <code>[UNTIL]</code> column up to the date and time in the current -line’s <code>[UNTIL]</code> column. In other words, the date and +line’s <code>[UNTIL]</code> column. In other words, the date and time in the <code>[UNTIL]</code> column is the instant that separates this state from the next. Where that would be ambiguous because -we’re setting our clocks back, the <code>[UNTIL]</code> column +we’re setting our clocks back, the <code>[UNTIL]</code> column specifies the first occurrence of the instant. The state specified by the last line, the one without anything in the <code>[UNTIL]</code> column, continues to the present.</p> <p>The first line typically specifies the mean solar time observed -before the introduction of standard time. Since there’s no line before +before the introduction of standard time. Since there’s no line before that, it has no beginning. <code>8-) </code> For some places near the <a href="https://en.wikipedia.org/wiki/International_Date_Line">International Date Line</a>, the first <i>two</i> lines will show solar times @@ -453,16 +453,16 @@ Alaska was then 24 hours earlier than it had been. <code><aside></code>(6 October in the Julian calendar, which Russia was still using then for religious reasons, was followed by <i>a second instance of the same day with a different name</i>, 18 -October in the Gregorian calendar. Isn’t civil time +October in the Gregorian calendar. Isn’t civil time wonderful? <code>8-)</code>)<code></aside></code></p> -<p>The abbreviation, “LMT” stands for “local mean -time”, which is an invention of +<p>The abbreviation, “LMT” stands for “local mean +time”, which is an invention of the <a href="https://en.wikipedia.org/wiki/Tz_database">tz database</a> and was probably never actually used during the period. Furthermore, the value is almost certainly wrong except in the archetypal place after which the zone is named. (The tz database -usually doesn’t provide a separate Zone record for places where +usually doesn’t provide a separate Zone record for places where nothing significant happened after 1970.)</p> <p>The <code>RULES</code> column tells us whether daylight saving time is being observed: @@ -470,7 +470,7 @@ nothing significant happened after 1970.)</p> <li>A hyphen, a kind of null value, means that we have not set our clocks ahead of standard time.</li> -<li>An amount of time (usually but not necessarily “1:00” +<li>An amount of time (usually but not necessarily “1:00” meaning one hour) means that we have set our clocks ahead by that amount.</li> @@ -488,10 +488,10 @@ Zone Pacific/Honolulu ... 1933 Apr 30 2:00 </pre> <p>Hawaii tried daylight saving time for three weeks in 1933 and -decided they didn’t like it. <code>8-) </code>Note that +decided they didn’t like it. <code>8-) </code>Note that the <code>STDOFF</code> column always contains the standard time -offset, so the local (wall clock) time during this period was GMT − -10:30 + 1:00 = GMT − 9:30.</p> +offset, so the local (wall clock) time during this period was GMT − +10:30 + 1:00 = GMT − 9:30.</p> <p>The <code>FORMAT</code> column specifies the usual abbreviation of the time zone name. It should have one of four forms:</p> @@ -499,24 +499,24 @@ the time zone name. It should have one of four forms:</p> <li>a time zone abbreviation that is a string of three or more characters that are either ASCII alphanumerics, -“<code>+</code>”, or “<code>-</code>”</li> +“<code>+</code>”, or “<code>-</code>”</li> -<li>the string “%z”, in which case the -“<code>%z</code>” will be replaced by a numeric time zone +<li>the string “%z”, in which case the +“<code>%z</code>” will be replaced by a numeric time zone abbreviation</li> <li>a pair of time zone abbreviations separated by a slash -(‘<code>/</code>’), in which case the first string is the +(‘<code>/</code>’), in which case the first string is the abbreviation for the standard time name and the second string is the abbreviation for the daylight saving time name</li> -<li>a string containing “<code>%s</code>”, in which case -the “<code>%s</code>” will be replaced by the text in the -appropriate Rule’s <code>LETTER</code> column, and the resulting +<li>a string containing “<code>%s</code>”, in which case +the “<code>%s</code>” will be replaced by the text in the +appropriate Rule’s <code>LETTER</code> column, and the resulting string should be a time zone abbreviation</li> </ul> -<p>The last two make sense only if there’s a named rule in effect.</p> +<p>The last two make sense only if there’s a named rule in effect.</p> <p>An example of a slash is:</p> <pre> @@ -552,9 +552,9 @@ database</a> gives abbreviations for time zones in popular English-language usage. For example, the last line in <code>Zone</code> <code>Pacific/Honolulu</code> (shown below) gives -“HST” for “Hawaii standard time” even though the +“HST” for “Hawaii standard time” even though the <a href="https://www.law.cornell.edu/uscode/text/15/263">legal</a> -name for that time zone is “Hawaii-Aleutian standard time.” +name for that time zone is “Hawaii–Aleutian standard time”. This author has read that there are also some places in Australia where popular time zone names differ from the legal ones. @@ -562,10 +562,10 @@ popular time zone names differ from the legal ones. href="https://en.wikipedia.org/wiki/Internationalization_and_localization">localize</a> the abbreviations. They are intended to be the values returned through the <code>"%Z"</code> format specifier to -<a href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a>’s -<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/strftime.html"><code>strftime</code></a> +<a href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a>’s +<a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/strftime.html"><code>strftime</code></a> function in the -<a href="https://kirste.userpage.fu-berlin.de/chemnet/use/info/libc/libc_19.html#SEC324">“C” locale</a>. +<a href="https://kirste.userpage.fu-berlin.de/chemnet/use/info/libc/libc_19.html#SEC324">“C” locale</a>. <li>If there is no generally accepted abbreviation for a time zone, a numeric offset is used instead, e.g., <code>+07</code> for 7 hours @@ -574,7 +574,7 @@ zone while uninhabited, where the offset is zero but in some sense the true offset is undefined. </ul> -<p>As a final example, here’s the complete history for Hawaii:</p> +<p>As a final example, here’s the complete history for Hawaii:</p> <table> <tr> @@ -626,15 +626,15 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00 <th>Time</th> </tr> <tr> - <td>−10:31:26</td> - <td>—</td> + <td>−10:31:26</td> + <td>–</td> <td>LMT</td> <td>local mean time</td> <td>1896-01-13</td> <td>12:00</td> </tr> <tr> - <td>−10:30</td> + <td>−10:30</td> <td>+0:01:26</td> <td>HST</td> <td>Hawaii standard time</td> @@ -642,7 +642,7 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00 <td>02:00</td> </tr> <tr> - <td>−9:30</td> + <td>−9:30</td> <td>+1:00</td> <td>HDT</td> <td>Hawaii daylight time</td> @@ -650,15 +650,15 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00 <td>12:00</td> </tr> <tr> - <td>−10:30¹</td> - <td>−1:00¹</td> + <td>−10:30¹</td> + <td>−1:00¹</td> <td>HST¹</td> <td>Hawaii standard time</td> <td>1942-02-09</td> <td>02:00</td> </tr> <tr> - <td rowspan="2">−9:30</td> + <td rowspan="2">−9:30</td> <td>+1:00</td> <td>HWT</td> <td>Hawaii war time</td> @@ -673,34 +673,34 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00 <td rowspan="2">02:00</td> </tr> <tr> - <td>−10:30</td> - <td>−1:00</td> + <td>−10:30</td> + <td>−1:00</td> <td rowspan="2">HST</td> <td rowspan="2">Hawaii standard time</td> <td>1947-06-08</td> </tr> <tr> - <td>−10:00³</td> + <td>−10:00³</td> <td>+0:30³</td> - <td colspan="2">—</td> + <td colspan="2">–</td> </tr> <tr> <td colspan="6" class="footnote"> - ¹Switching to US rules…most recent transition (in 1919) was to standard time + ¹Switching to US rules...most recent transition (in 1919) was to standard time </td> </tr> <tr> <td colspan="6" class="footnote"> ²23:00 <a href="https://en.wikipedia.org/wiki/Universal_Time">UT</a> - + (−9:30) = 13:30 local + + (−9:30) = 13:30 local </td> </tr> <tr> <td colspan="6" class="footnote"> - ³Since <a href="https://en.wikipedia.org/wiki/ISO_8601">1947–06–08T12:30Z</a>, + ³Since <a href="https://en.wikipedia.org/wiki/ISO_8601">1947-06-08T12:30Z</a>, the civil time in Hawaii has been <a href="https://en.wikipedia.org/wiki/Universal_Time">UT</a>/<a href="https://en.wikipedia.org/wiki/Coordinated_Universal_Time">UTC</a> - − 10:00 year-round. + −10:00 year-round. </td> </tr> </table> diff --git a/tz-link.html b/tz-link.html index ad2cc972a4f9..9267fb6f822b 100644 --- a/tz-link.html +++ b/tz-link.html @@ -73,7 +73,7 @@ This database (known as <code><abbr>tz</abbr></code>, is used by several implementations, including <a href="https://www.gnu.org/software/libc/">the -<abbr title="GNU's Not Unix">GNU</abbr> +<abbr title="GNU’s Not Unix">GNU</abbr> C Library</a> (used in <a href="https://en.wikipedia.org/wiki/Linux"><abbr>GNU</abbr>/Linux</a>), <a href="https://www.android.com">Android</a>, @@ -84,7 +84,6 @@ title="Berkeley Software Distribution">BSD</abbr></a>, <a href="https://www.chromium.org/chromium-os/">ChromiumOS</a>, <a href="https://cygwin.com">Cygwin</a>, <a href="https://mariadb.org">MariaDB</a>, -<a href="https://en.wikipedia.org/wiki/MINIX">MINIX</a>, <a href="https://musl.libc.org">musl libc</a>, <a href="https://www.mysql.com">MySQL</a>, <a href="https://en.wikipedia.org/wiki/WebOS"><abbr @@ -97,8 +96,9 @@ title="iPhone OS">iOS</abbr></a>, <a href="https://www.microsoft.com/en-us/windows">Microsoft Windows</a>, <a href="https://www.vmssoftware.com">Open<abbr title="Virtual Memory System">VMS</abbr></a>, -<a href="https://www.oracle.com/database/">Oracle Database</a>, and -<a href="https://www.oracle.com/solaris">Oracle Solaris</a>.</p> +<a href="https://www.oracle.com/database/">Oracle Database</a>, +<a href="https://www.oracle.com/solaris">Oracle Solaris</a>, +and <a href="https://blackberry.qnx.com/en">QNX</a>.</p> <p> Each main entry in the database represents a <dfn>timezone</dfn> for a set of civil-time clocks that have all agreed since 1970. @@ -117,7 +117,7 @@ To use the database on a <a href="https://en.wikipedia.org/wiki/POSIX"><abbr title="Portable Operating System Interface">POSIX</abbr>.1-2024</a> implementation set the <code><abbr>TZ</abbr></code> -environment variable to the location's full name, +environment variable to the location’s full name, e.g., <code><abbr>TZ</abbr>="America/New_York"</code>.</p> <p> Associated with each timezone is a history of offsets from @@ -138,7 +138,7 @@ for Eastern Standard Time in the <abbr>US</abbr>.</p> <p> The following <a href="https://en.wikipedia.org/wiki/Unix_shell">shell</a> commands download -the latest release's two +the latest release’s two <a href="https://en.wikipedia.org/wiki/Tar_(computing)">tarballs</a> to a <abbr>GNU</abbr>/Linux or similar host.</p> <pre><code>mkdir tzdb @@ -169,17 +169,20 @@ lower-case letter (<samp>a</samp> through <samp>z</samp>, then <samp>za</samp> through <samp>zz</samp>, then <samp>zza</samp> through <samp>zzz</samp>, and so on). Since version 2022a, each release has been distributed in -<a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06">POSIX +<a href="https://pubs.opengroup.org/onlinepubs/9799919799/utilities/pax.html#tag_20_94_13_06">POSIX ustar interchange format</a>, compressed as described above; older releases use a nearly compatible format. Since version 2016h, each release has contained a text file named -"<code>version</code>" whose first (and currently only) line is the version. -Older releases are <a href="https://ftp.iana.org/tz/releases/">archived</a>, -and are also available in an -<a href="ftp://ftp.iana.org/tz/releases/"><abbr -title="File Transfer Protocol">FTP</abbr> directory</a> via a -less secure protocol.</p> -<p>Alternatively, a development repository of code and data can be +“<code>version</code>” whose first (and currently only) line is the version. +<a href="https://ftp.iana.org/tz/releases/">Older archived releases are +available</a> via +<a href="https://en.wikipedia.org/wiki/HTTPS"><abbr +title="Hypertext Transfer Protocol Secure">HTTPS</abbr></a>, +<a href="https://en.wikipedia.org/wiki/Rsync"><abbr +title="remote sync">rsync</abbr></a>, and +<a href="https://en.wikipedia.org/wiki/FTP"><abbr +title="File Transfer Protocol">FTP</abbr></a>. +<p>Alternatively, a development repository of code and data can bem retrieved from <a href="https://github.com">GitHub</a> via the shell command:</p> <pre><code><a href="https://git-scm.com">git</a> clone <a href="https://github.com/eggert/tz">https://github.com/eggert/tz</a> @@ -194,7 +197,7 @@ After obtaining the code and data files, see the The code lets you compile the <code><abbr>tz</abbr></code> source files into machine-readable binary files, one for each location. The binary files are in a special format specified by -<a href="https://www.rfc-editor.org/rfc/9636">The +<a href="https://www.rfc-editor.org/rfc/rfc9636">The Time Zone Information Format (<abbr>TZif</abbr>)</a> (Internet <abbr title="Request For Comments">RFC</abbr> 9636). The code also lets @@ -208,9 +211,12 @@ location.</p> The <code><abbr>tz</abbr></code> code and data are by no means authoritative. If you find errors, please email changes to <a href="mailto:tz@iana.org"><code>tz@iana.org</code></a>, -the time zone mailing list. See +the time zone mailing list. +The mailing list and its archives are public, +so please do not send confidential information. +See <a href="https://lists.iana.org/postorius/lists/tz.iana.org/">the mailing -list's main page</a> to subscribe or to browse its archive of old messages. +list’s main page</a> to subscribe or to browse its archive of old messages. <a href="https://tzdata-meta.timtimeonline.com">Metadata for mailing list discussions</a> and corresponding data changes can be generated <a href="https://github.com/timparenti/tzdata-meta">automatically</a>. @@ -248,7 +254,7 @@ with lines terminated by <a href="https://en.wikipedia.org/wiki/Newline"><abbr title="linefeed">LF</abbr></a>, which can be modified by common text editors such as <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>, -<a href="https://gedit-technology.github.io/apps/gedit/">gedit</a>, and +<a href="https://gedit-text-editor.org">gedit</a>, and <a href="https://www.vim.org">vim</a>. Specialized source-file editing can be done via the <a href="https://packagecontrol.io/packages/zoneinfo">Sublime @@ -274,14 +280,15 @@ displays changes between recent <code><abbr>tzdb</abbr></code> versions. <h2 id="coordinating">Coordinating with governments and distributors</h2> <p> As discussed in -"<a href="https://www.icann.org/en/blogs/details/how-time-zones-are-coordinated-13-03-2023-en">How -Time Zones Are Coordinated</a>", the time zone database relies on +“<a href="https://www.icann.org/en/blogs/details/how-time-zones-are-coordinated-13-03-2023-en">How +Time Zones Are Coordinated</a>”, the time zone database relies on collaboration among governments, the time zone database volunteer community, and data distributors downstream. <p> If your government plans to change its time zone boundaries or -daylight saving rules, please send email to <a -href="mailto:tz@iana.org"><code>tz@iana.org</code></a> well in advance, +daylight saving rules, please send email as described in +"<a href="#changes">Changes to the <code><abbr>tz</abbr></code> database</a>". +Do this well in advance, as this will lessen confusion and will coordinate updates to many cell phones, computers, and other devices around the world. In your email, please cite the legislation or regulation that specifies @@ -289,7 +296,7 @@ the change, so that it can be checked for details such as the exact times when clock transitions occur. It is OK if a rule change is planned to affect clocks far into the future, as a long-planned change can easily be reverted -or otherwise altered with a year's notice before the change would have +or otherwise altered with a year’s notice before the change would have affected clocks.</p> <p> There is no fixed schedule for <code><abbr>tzdb</abbr></code> releases. @@ -303,7 +310,7 @@ href="https://en.wikipedia.org/wiki/End_user">end users</a> see changes. These updates can be expensive, for both the <a href="https://en.wikipedia.org/wiki/Quality_assurance">quality assurance</a> process and the overall cost of shipping and installing -updates to each device's copy of <code><abbr>tzdb</abbr></code>. +updates to each device’s copy of <code><abbr>tzdb</abbr></code>. Updates may be batched with other updates and may take substantial time to reach end users after a release. Older devices may no longer be supported and thus may never be updated, @@ -313,9 +320,9 @@ For these reasons any rule change should be promulgated at least a year before it affects how clocks operate; otherwise, there is a good chance that many clocks will be wrong due to delays in propagating updates, and that residents will be confused or even actively resist the change. -The shorter the notice, the more likely clock problems will arise; see "<a +The shorter the notice, the more likely clock problems will arise; see “<a href="https://codeofmatt.com/2016/04/23/on-the-timing-of-time-zone-changes/">On -the Timing of Time Zone Changes</a>" for examples. +the Timing of Time Zone Changes</a>” for examples. </p> </section> @@ -331,7 +338,7 @@ database format.</li> <li><a href="https://blog.jonudell.net/2009/10/23/a-literary-appreciation-of-the-olsonzoneinfotz-database/">A literary appreciation of the Olson/Zoneinfo/tz database</a> comments on the -database's style.</li> +database’s style.</li> <li><a href="https://doi.org/10.1145/3340301.3341125">What time is it: managing time in the internet</a> analyzes the database longitudinally.</li> </ul> @@ -344,7 +351,7 @@ managing time in the internet</a> analyzes the database longitudinally.</li> These are listed roughly in ascending order of complexity and fanciness. </p> <ul> -<li><a href="https://time.is">Time.is</a> shows locations' +<li><a href="https://time.is">Time.is</a> shows locations’ time and zones.</li> <li><a href="https://www.timejones.com">TimeJones.com</a>, <a href="https://timezoneconverterapp.com">Time Zone Converter</a> and @@ -362,7 +369,7 @@ lets you see the <code><abbr>TZ</abbr></code> values directly.</li> <li><a href="https://www.convertit.com/Go/ConvertIt/World_Time/Current_Time.ASP">Current Time in 1000 Places</a> uses descriptions of the values.</li> -<li><a href="https://www.timeanddate.com/worldclock/">The World Clock – +<li><a href="https://www.timeanddate.com/worldclock/">The World Clock – Worldwide</a> lets you sort zone names and convert times.</li> <li><a href="https://24timezones.com">24TimeZones</a> has a world time map and a time converter.</li> @@ -376,21 +383,16 @@ calculates the current time difference between locations.</li> <section> <h2 id="protocols">Network protocols for <code><abbr>tz</abbr></code> data</h2> <ul> -<li>The <a href="https://www.ietf.org">Internet Engineering Task Force</a>'s -<a href="https://datatracker.ietf.org/wg/tzdist/charter/">Time Zone Data -Distribution Service (tzdist) working group</a> defined <a -href="https://www.rfc-editor.org/rfc/rfc7808">TZDIST</a> -(Internet <abbr>RFC</abbr> 7808), a time zone data distribution service, -along with <a href="https://www.rfc-editor.org/rfc/rfc7809">CalDAV</a> +<li><a href="https://www.rfc-editor.org/rfc/rfc7808">Time Zone +Data Distribution Service</a> (TZDIST, Internet <abbr>RFC</abbr> 7808) +is associated with +<a href="https://www.rfc-editor.org/rfc/rfc7809">CalDAV</a> (Internet <abbr>RFC</abbr> 7809), a calendar access protocol for transferring time zone data by reference. <a href="https://devguide.calconnect.org/Time-Zones/TZDS/">TZDIST -implementations</a> are available. -The <a href="https://www.ietf.org/mailman/listinfo/tzdist-bis">tzdist-bis -mailing list</a> discusses possible extensions.</li> -<li>The <a href="https://www.rfc-editor.org/rfc/rfc5545"> -Internet Calendaring and Scheduling Core Object Specification -(iCalendar)</a> (Internet <abbr>RFC</abbr> 5445) +implementations</a> are available.</li> +<li>The <a href="https://www.rfc-editor.org/rfc/rfc5545">iCalendar format</a> +(Internet <abbr>RFC</abbr> 5445) covers time zone data; see its VTIMEZONE calendar component. The iCalendar format requires specialized parsers and generators; a @@ -422,10 +424,6 @@ available under the <a href="https://www.gnu.org/copyleft/gpl.html"><abbr>GNU</abbr> General Public License (<abbr title="General Public License">GPL</abbr>)</a>.</li> -<li><a href="https://sourceforge.net/projects/tzical/">tziCal – tz -database conversion utility</a> is like Vzic, except for the <a -href="https://dotnet.microsoft.com">.NET framework</a> -and with a <abbr>BSD</abbr>-style license.</li> <li><a href="https://metacpan.org/release/DateTime-TimeZone">DateTime::TimeZone</a> contains a script <code>parse_olson</code> that compiles @@ -475,7 +473,7 @@ href="https://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.ht SE 8 Date and Time</a> <abbr>API</abbr> can be supplemented by <a href="https://www.threeten.org/threeten-extra/">ThreeTen-Extra</a>, which is freely available under a <abbr>BSD</abbr>-style license.</li> -<li><a href="https://www.joda.org/joda-time/">Joda-Time – Java date +<li><a href="https://www.joda.org/joda-time/">Joda-Time – Java date and time <abbr>API</abbr></a> contains a class <code>org.joda.time.tz.ZoneInfoCompiler</code> that compiles <code><abbr>tz</abbr></code> source into a binary format. It inspired @@ -484,7 +482,7 @@ they can assume Java 8 or later. It is available under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License</a>.</li> <li><a href="https://bell-sw.com/pages/iana-updater/">IANA Updater</a> and <a href="https://www.azul.com/products/open-source-tools/ziupdater-time-zone-tool/">ZIUpdater</a> -are alternatives to TZUpdater. IANA Updater's license is unclear; +are alternatives to TZUpdater. IANA Updater’s license is unclear; ZIUpdater is licensed under the <abbr>GPL</abbr>.</li> <li><a href="https://github.com/MenoData/Time4A">Time4A: Advanced date and time library for Android</a> and @@ -499,7 +497,7 @@ License">LGPL</abbr>)</a>.</li> <li><abbr>ICU</abbr> (mentioned <a href="#ICU">above</a>) contains compilers and Java-based libraries.</li> </ul> -<li><a href="https://nodatime.org">Noda Time – Date and +<li><a href="https://nodatime.org">Noda Time – Date and time <abbr>API</abbr> for .NET</a> is like Joda-Time and Time4J, but for the .NET framework instead of Java. It is freely available under the Apache License.</li> @@ -548,13 +546,13 @@ The proposed <a href="https://github.com/tc39/proposal-temporal"><code>Temporal</code> objects</a> let programs access an abstract view of <code><abbr>tzdb</abbr></code> data, and are designed to replace <a -href="https://codeofmatt.com/javascript-date-type-is-horribly-broken/">JavaScript's +href="https://codeofmatt.com/javascript-date-type-is-horribly-broken/">JavaScript’s problematic <code>Date</code> objects</a> when working with dates and times. <li><a href="https://github.com/JuliaTime">JuliaTime</a> contains a compiler from <code><abbr>tz</abbr></code> source into <a href="https://julialang.org">Julia</a>. It is freely available under the <abbr>MIT</abbr> license.</li> -<li><a href="https://github.com/pavkam/tzdb"><abbr>TZDB</abbr> – +<li><a href="https://github.com/pavkam/tzdb"><abbr>TZDB</abbr> – <abbr>IANA</abbr> Time Zone Database for Delphi/<abbr title="Free Pascal Compiler">FPC</abbr></a> compiles from <code><abbr>tz</abbr></code> source into @@ -563,14 +561,14 @@ as compiled by <a href="https://en.wikipedia.org/wiki/Delphi_(IDE)">Delphi</a> and <a href="https://en.wikipedia.org/wiki/Free_Pascal"><abbr>FPC</abbr></a>. It is freely available under a <abbr>BSD</abbr>-style license.</li> -<li><a href="https://pythonhosted.org/pytz/">pytz – World Timezone +<li><a href="https://pythonhosted.org/pytz/">pytz – World Timezone Definitions for Python</a> compiles <code><abbr>tz</abbr></code> source into <a href="https://www.python.org">Python</a>. It is freely available under a <abbr>BSD</abbr>-style license. In code that can assume Python 3.6 or later it is largely superseded; see <a href="https://blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html">pytz: The Fastest Footgun in the West</a>.</li> -<li><a href="https://tzinfo.github.io">TZInfo – +<li><a href="https://tzinfo.github.io">TZInfo – Ruby Timezone Library</a> compiles <code><abbr>tz</abbr></code> source into <a href="https://www.ruby-lang.org/en/">Ruby</a>. @@ -600,14 +598,14 @@ has an independent, thread-safe implementation of a <abbr>TZif</abbr> file reader. This library is freely available under the LGPL and is widely used in <abbr>GNU</abbr>/Linux systems.</li> -<li><a href="https://www.gnome.org">GNOME</a>'s +<li><a href="https://www.gnome.org">GNOME</a>’s <a href="https://developer.gnome.org/glib/">GLib</a> has a <abbr>TZif</abbr> file reader written in C that creates a <code>GTimeZone</code> object representing sets of <abbr>UT</abbr> offsets. It is freely available under the <abbr>LGPL</abbr>.</li> <li>The -<a href="https://github.com/bloomberg/bde/wiki">BDE Standard Library</a>'s +<a href="https://github.com/bloomberg/bde/wiki">BDE Standard Library</a>’s <code>baltzo::TimeZoneUtil</code> component contains a C++ implementation of a <abbr>TZif</abbr> file reader. It is freely available under the Apache License.</li> @@ -615,6 +613,9 @@ the Apache License.</li> library that translates between <abbr>UT</abbr> and civil time and can read <abbr>TZif</abbr> files. It is freely available under the Apache License.</li> +<li>The <a href="https://golang.org">Go programming language</a> +has a <abbr>TZif</abbr> file reader <a +href="https://pkg.go.dev/time#LoadLocationFromTZData"><code>LoadLocationFromTZData</code></a>.</li> <li>The <a href="https://github.com/nayarsystems/posix_tz_db"><code>posix_tz_db</code> package</a> contains Python code @@ -677,10 +678,6 @@ href="https://www.mozilla.org/en-US/thunderbird/">Thunderbird</a>. It displays multiple clocks in the application window, and has a mapping interface to <a href="https://www.google.com/earth/">Google Earth</a>. It is freely available under the <abbr>GPL</abbr>.</li> -<li><a href="https://golang.org">Go programming language</a> -implementations contain a copy of a 32-bit subset of a recent -<code><abbr>tz</abbr></code> database in a -Go-specific format.</li> <li>Microsoft Windows 8.1 and later has <code><abbr>tz</abbr></code> data and <abbr>CLDR</abbr> data (mentioned <a href="#CLDR">below</a>) used by the @@ -695,8 +692,8 @@ the older, proprietary method of Microsoft Windows 2000 and later, which stores time zone data in the <a href="https://en.wikipedia.org/wiki/Windows_Registry">Windows Registry</a>. The <a -href="https://unicode.org/cldr/charts/latest/supplemental/zone_tzid.html">Zone → -Tzid table</a> or <a +href="https://unicode.org/cldr/charts/latest/supplemental/zone_tzid.html">Zone +→ Tzid table</a> or <a href="https://github.com/unicode-org/cldr/blob/master/common/supplemental/windowsZones.xml"><abbr>XML</abbr> file</a> of the <abbr>CLDR</abbr> data maps proprietary zone IDs to <code><abbr>tz</abbr></code> names. @@ -714,7 +711,7 @@ Java-specific format.</li> <h2 id="other-dbs">Other time zone databases</h2> <ul> <li><a href="https://www.astro.com/atlas">Time-zone Atlas</a> -is Astrodienst's Web version of Shanks and Pottenger's out-of-print +is Astrodienst’s Web version of Shanks and Pottenger’s out-of-print time zone history atlases <a href="https://www.worldcat.org/oclc/468828649">for the US</a> and <a href="https://www.worldcat.org/oclc/76950459">for the world</a>. @@ -749,7 +746,7 @@ Agency (<abbr title="Central Intelligence Agency">CIA</abbr>)</a>, contains a time zone map; the <a -href="https://legacy.lib.utexas.edu/maps/world.html">Perry–Castañeda +href="https://legacy.lib.utexas.edu/maps/world.html">Perry–Castañeda Library Map Collection</a> of the University of Texas at Austin has copies of recent editions. @@ -759,14 +756,13 @@ and parts of the data are a few years out of date.</li> <li><a href="https://www.worldtimezone.com">World Time Zone Map with current time</a> has several fancy time zone maps; it covers Russia particularly well. -The maps' pictorial quality is not quite as good as the -<abbr>CIA</abbr>'s +The maps’ pictorial quality is not quite as good as the <abbr>CIA</abbr>’s but the maps are more up to date.</li> <li><a href="https://blog.poormansmath.net/how-much-is-time-wrong-around-the-world/">How much is time wrong around the world?</a> maps the difference between mean solar and standard time, highlighting areas such as western China -where the two differ greatly. It's a bit out of date, unfortunately.</li> +where the two differ greatly. It’s a bit out of date, unfortunately.</li> </ul> </section> @@ -799,25 +795,25 @@ Commercial network API access is provided by <a href="https://askgeo.com">AskGeo</a> and <a href="https://www.geogarage.com/blog/news-1/post/geogarage-time-zone-api-31">GeoGarage</a>. </li> -<li>"<a +<li>“<a href="https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates/16086964">How to get a time zone from a location using latitude and longitude -coordinates?</a>" discusses other geolocation possibilities.</li> +coordinates?</a>” discusses other geolocation possibilities.</li> <li><a href="http://statoids.com/statoids.html">Administrative -Divisions of Countries ("Statoids")</a> lists +Divisions of Countries (“Statoids”)</a> lists political subdivision data related to time zones.</li> <li><a href="https://manifold.net/info/freestuff.shtml">Manifold Software -– GIS and Database Tools</a> includes a Manifold-format map of +– GIS and Database Tools</a> includes a Manifold-format map of world time zone boundaries circa 2007, distributed under the <abbr>GPL</abbr>.</li> <li>A ship within the <a href="https://en.wikipedia.org/wiki/Territorial_waters">territorial -waters</a> of any nation uses that nation's time. In international -waters, time zone boundaries are meridians 15° apart, except that -<abbr>UT</abbr>−12 and <abbr>UT</abbr>+12 are each 7.5° +waters</a> of any nation uses that nation’s time. In international +waters, time zone boundaries are meridians 15° apart, except that +<abbr>UT</abbr>−12 and <abbr>UT</abbr>+12 are each 7.5° wide and are separated by -the 180° meridian (not by the International Date Line, which is -for land and territorial waters only). A captain can change ship's +the 180° meridian (not by the International Date Line, which is +for land and territorial waters only). A captain can change ship’s clocks any time after entering a new time zone; midnight changes are common.</li> </ul> @@ -831,12 +827,13 @@ Walk through Time</a> surveys the evolution of timekeeping.</li> <li>The history of daylight saving time is surveyed in <a href="http://www.webexhibits.org/daylightsaving/">About Daylight -Saving Time – History, rationale, laws & dates</a> and summarized in +Saving Time – History, rationale, laws & dates</a> and summarized in <a href="http://seizethedaylight.com/dst/">A Brief History of Daylight Saving Time</a>.</li> <li><a href="https://www.laphamsquarterly.org/roundtable/time-lords">Time Lords</a> discusses how authoritarians manipulate civil time.</li> -<li><a href="https://www.w3.org/TR/timezone/">Working with Time Zones</a> +<li><a href="https://www.w3.org/TR/timezone/">Working with Time +and Time Zones</a> contains guidelines and best practices for software applications that deal with civil time.</li> <li><a href="https://webspace.science.uu.nl/~gent0113/idl/idl.htm">A History of @@ -851,10 +848,7 @@ Zone Concepts</a> discusses terminological issues behind time zones.</li> <h2 id="national">National histories of legal time</h2> <dl> <dt>Australia</dt> -<dd>The Parliamentary Library commissioned a <a -href="https://parlinfo.aph.gov.au/parlInfo/download/library/prspub/359V6/upload_binary/359v60.pdf">research -paper on daylight saving time in Australia</a>. -The Bureau of Meteorology publishes a list of <a +<dd>The Bureau of Meteorology publishes a list of <a href="http://www.bom.gov.au/climate/averages/tables/dst_times.shtml">Implementation Dates of Daylight Savings Time within Australia</a>.</dd> <dt>Belgium</dt> @@ -867,7 +861,7 @@ hreflang="fr">French</a>).</dd> <dt>Brazil</dt> <dd>The Time Service Department of the National Observatory records <a href="http://pcdsh01.on.br/DecHV.html" -hreflang="pt-BR">Brazil's daylight saving time decrees (in +hreflang="pt-BR">Brazil’s daylight saving time decrees (in Portuguese)</a>.</dd> <dt>Canada</dt> <dd>National Research Council Canada publishes current @@ -877,12 +871,12 @@ zones and daylight saving time</a>.</dd> <dt>Chile</dt> <dd>The Hydrographic and Oceanographic Service of the Chilean Navy publishes a <a href="https://www.horaoficial.cl/historia_hora.php" hreflang="es">history of -Chile's official time (in Spanish)</a>.</dd> +Chile’s official time (in Spanish)</a>.</dd> <dt>China</dt> <dd>The Hong Kong Observatory maintains a <a href="https://www.hko.gov.hk/en/gts/time/Summertime.htm">history of summer time in Hong Kong</a>, -and Macau's Meteorological and Geophysical Bureau maintains a <a +and Macau’s Meteorological and Geophysical Bureau maintains a <a href="https://www.smg.gov.mo/en/subpage/224/page/174">similar history for Macau</a>. Unfortunately the latter is incomplete and has errors.</dd> @@ -915,8 +909,8 @@ covers the history of local time in the Netherlands from ancient times.</dd> href="https://www.dia.govt.nz/Daylight-Saving-History">History of Daylight Saving</a>.</dd> <dt>Palestine</dt> -<dd>The Ministry of Telecom and IT publishes a <a -href="https://mtit.pna.ps/home/TimeZone" +<dd>The Ministry of Telecom and Digital Economy publishes a <a +href="https://mtde.gov.ps/home/TimeZone" hreflang="ar">history of clock changes (in Arabic)</a>.</dd> <dt>Portugal</dt> <dd>The Lisbon Astronomical Observatory publishes a @@ -925,7 +919,7 @@ legal time (in Portuguese)</a>.</dd> <dt>Singapore</dt> <dd><a id="Singapore" href="https://web.archive.org/web/20190822231045/http://www.math.nus.edu.sg/~mathelmr/teaching/timezone.html">Why -is Singapore in the "Wrong" Time Zone?</a> details the +is Singapore in the “Wrong” Time Zone?</a> details the history of legal time in Singapore and Malaysia.</dd> <dt>United Kingdom</dt> <dd><a @@ -933,7 +927,7 @@ href="https://www.polyomino.org.uk/british-time/">History of legal time in Britain</a> discusses in detail the country with perhaps the best-documented history of clock adjustments.</dd> <dt>United States</dt> -<dd>The Department of Transportation's <a +<dd>The Department of Transportation’s <a href="https://www.transportation.gov/regulations/recent-time-zone-proceedings">Recent Time Zone Proceedings</a> lists changes to official written time zone boundaries, and its <a @@ -957,9 +951,6 @@ zone shifts, and many scientific studies have been conducted. This section summarizes reviews and position statements based on scientific literature in the area.</p> <ul> -<li>In 2022 the American Medical Association issued a -<a href="https://www.ama-assn.org/press-center/press-releases/ama-calls-permanent-standard-time">statement -supporting permanent standard time</a> on health grounds.</li> <li>Carey RN, Sarma KM. <a href="https://bmjopen.bmj.com/content/7/6/e014319.long">Impact of daylight saving time on road traffic collision risk: a systematic @@ -969,13 +960,35 @@ This reviews research literature and concludes that the evidence neither supports nor refutes road safety benefits from shifts in time zones.</li> <li>Havranek T, Herman D, Irsova D. -<a href="https://www.iaee.org/en/publications/ejarticle.aspx?id=3051">Does -daylight saving save electricity? A meta-analysis</a>. -<em>Energy J.</em> 2018;39(2):35–61. +Does daylight saving save electricity? A meta-analysis. +<em>Energy J.</em> 2018;39(2):35–61. doi:<a href="https://doi.org/10.5547/01956574.39.2.thav">10.5547/01956574.39.2.thav</a>. -This analyzes research literature and concludes, "Electricity savings +This analyzes research literature and concludes, “Electricity savings are larger for countries farther away from the equator, while -subtropical regions consume more electricity because of <abbr>DST</abbr>."</li> +subtropical regions consume more electricity because of <abbr>DST</abbr>.”</li> +<li>Neumann P, von Blanckenburg K. <a +href="https://journals.sagepub.com/doi/full/10.1177/0961463X241310562">What +time will it be? A comprehensive literature review on daylight saving time</a>. +<em>Time Soc</em>. 2025-01-21. +doi:<a href="https://doi.org/10.1177/0961463X241310562">10.1177/0961463X241310562</a>. +This reviews DST’s effects on electricity, health, crime, road safety, +and the economy, focusing on research since 2010, and concludes that +year-round standard time is preferable overall. +</ul> + +<p>The following medical societies have taken positions on the +advisability of clock shifts:</p> + +<ul> +<li>In 2022 the American Medical Association issued a +<a href="https://www.ama-assn.org/press-center/press-releases/ama-calls-permanent-standard-time">statement +supporting permanent standard time</a> on health grounds.</li> +<li>Crawford MR, Winnebeck EC, von Schantz M <em>et al</em>. +<a href="https://onlinelibrary.wiley.com/doi/10.1111/jsr.14352">The +British Sleep Society position statement on Daylight Saving Time in the UK</a>. +<em>J Sleep Res.</em> 2025;34(3):e14352. +doi:<a href="https://doi.org/10.1111/jsr.14352">10.1111/jsr.14352</a>. +This recommends that the UK abolish DST for health reasons.</li> <li>Malow BA. <a href="https://academic.oup.com/sleep/article/45/12/zsac236/6717940">It is time to abolish the clock change and adopt permanent @@ -984,20 +997,12 @@ a Sleep Research Society position statement</a>. <em>Sleep.</em> 2022;45(12):zsac236. doi:<a href="https://doi.org/10.1093/sleep/zsac236">10.1093/sleep/zsac236</a>. After reviewing the scientific literature, the Sleep Research Society -advocates permanent standard time due to its health benefits. -<li>Neumann P, von Blanckenburg K. <a -href="https://journals.sagepub.com/doi/full/10.1177/0961463X241310562">What -time will it be? A comprehensive literature review on daylight saving time</a>. -<em>Time Soc</em>. 2025-01-21. -doi:<a href="https://doi.org/10.1177/0961463X241310562">10.1177/0961463X241310562</a>. -This reviews DST's effects on electricity, health, crime, road safety, -and the economy, focusing on research since 2010, and concludes that -year-round standard time is preferable overall. +advocates permanent standard time due to its health benefits.</li> <li>Rishi MA, Cheng JY, Strang AR <em>et al</em>. <a href="https://jcsm.aasm.org/doi/10.5664/jcsm.10898">Permanent standard time is the optimal choice for health and safety: an American Academy of Sleep Medicine position statement</a>. -<em>J Clin Sleep Med.</em> 2024;20(1):121–125. +<em>J Clin Sleep Med.</em> 2024;20(1):121–125. doi:<a href="https://doi.org/10.5664/jcsm.10898">10.5664/jcsm.10898</a>. The AASM argues for permanent standard time due to health and safety risks and economic costs of both <abbr>DST</abbr> transitions and @@ -1005,12 +1010,12 @@ permanent <abbr>DST</abbr>.</li> <li>Roenneberg T, Wirz-Justice A, Skene DJ <em>et al</em>. <a href="https://journals.sagepub.com/doi/10.1177/0748730419854197">Why should we abolish Daylight Saving Time?</a> -<em>J Biol Rhythms.</em> 2019;34(3):227–230. +<em>J Biol Rhythms.</em> 2019;34(3):227–230. doi:<a href="https://doi.org/10.1177/0748730419854197">10.1177/0748730419854197</a>. The Society for Research on Biological Rhythms opposes <abbr>DST</abbr> changes and permanent <abbr>DST</abbr>, and advocates that governments adopt -"permanent Standard Time for the health and safety of their citizens".</li> +“permanent Standard Time for the health and safety of their citizens”.</li> </ul> </section> @@ -1044,14 +1049,14 @@ Options for <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr></a> specifies a <a href="https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol"><abbr>DHCP</abbr></a> option for a server to configure -a client's time zone and daylight saving settings automatically.</li> +a client’s time zone and daylight saving settings automatically.</li> <li><a href="https://www.ucolick.org/~sla/leapsecs/timescales.html">Time Scales</a> describes astronomical time scales like <abbr title="Terrestrial Dynamic Time">TDT</abbr>, <abbr title="Geocentric Coordinate Time">TCG</abbr>, and <abbr title="Barycentric Dynamic Time">TDB</abbr>. <li>The <a href="https://www.iau.org"><abbr -title="International Astronomical Union">IAU</abbr></a>'s <a +title="International Astronomical Union">IAU</abbr></a>’s <a href="https://www.iausofa.org"><abbr title="Standards Of Fundamental Astronomy">SOFA</abbr></a> collection contains C and <a @@ -1063,7 +1068,7 @@ code for converting among time scales like <a href="https://www.iausofa.org/tandc.html">SOFA license</a>.</li> <li><a href="https://www.giss.nasa.gov/tools/mars24/help/notes.html">Mars24 Sunclock -– Time on Mars</a> describes Airy Mean Time (<abbr>AMT</abbr>) and the +– Time on Mars</a> describes Airy Mean Time (<abbr>AMT</abbr>) and the diverse local time scales used by each landed mission on Mars.</li> <li><a href="http://leapsecond.com">LeapSecond.com</a> is @@ -1072,25 +1077,26 @@ in general. It covers the state of the art in amateur timekeeping, and how the art has progressed over the past few decades.</li> <li>The rules for leap seconds are specified in Annex 1 (Time scales) of <a href="https://www.itu.int/rec/R-REC-TF.460-6-200202-I/">Standard-frequency -and time-signal emissions</a>, International Telecommunication Union – +and time-signal emissions</a>, International Telecommunication Union – Radiocommunication Sector (ITU-R) Recommendation TF.460-6 (02/2002).</li> <li><a href="https://www.iers.org/IERS/EN/Publications/Bulletins/bulletins.html"><abbr title="International Earth Rotation and Reference Systems Service">IERS</abbr> Bulletins</a> contains official publications of the International Earth Rotation and Reference Systems Service, which decides when leap -seconds occur. The <code><abbr>tz</abbr></code> code and data support leap seconds -via an optional "<code>right</code>" configuration where a computer's internal +seconds occur. +The <code><abbr>tz</abbr></code> code and data support leap seconds +via an optional <code>"right"</code> configuration where a computer’s internal <code>time_t</code> integer clock counts every <abbr>TAI</abbr> second, -as opposed to the default "<code>posix</code>" configuration +as opposed to the default <code>"posix"</code> configuration where the internal clock ignores leap seconds. The two configurations agree for timestamps starting with 1972-01-01 00:00:00 <abbr>UTC</abbr> (<code>time_t</code> 63 072 000) and diverge for timestamps starting with <code>time_t</code> 78 796 800, which corresponds to the first leap second -1972-06-30 23:59:60 <abbr>UTC</abbr> in the "<code>right</code>" configuration, +1972-06-30 23:59:60 <abbr>UTC</abbr> in the <code>"right"</code> configuration, and to -1972-07-01 00:00:00 <abbr>UTC</abbr> in the "<code>posix</code>" configuration. +1972-07-01 00:00:00 <abbr>UTC</abbr> in the <code>"posix"</code> configuration. In practice the two configurations also agree for timestamps before 1972 even though the historical situation is messy, partly because neither <abbr>UTC</abbr> nor <abbr>TAI</abbr> @@ -1105,7 +1111,7 @@ The <abbr>IERS</abbr> maintains this file, and a copy is distributed by and <a href="https://ntpsec.org">NTPsec</a>. The <code><abbr>tz</abbr></code> database also distributes leap second information in a differently-formatted <code>leapseconds</code> text file, -as well as in the "<code>right</code>" configuration in binary form; for +as well as in the <code>"right"</code> configuration in binary form; for example, <code>right/UTC</code> can be used by <a href="https://chrony-project.org"><code>chrony</code></a>, another <abbr>NTP</abbr> implementation.</li> @@ -1114,13 +1120,13 @@ discusses how to gradually adjust <abbr>POSIX</abbr> clocks near a leap second so that they disagree with <abbr>UTC</abbr> by at most a half second, even though every <abbr>POSIX</abbr> minute has exactly sixty seconds. This approach works with the default <code><abbr>tz</abbr></code> -"<code>posix</code>" configuration, is <a +<code>"posix"</code> configuration, is <a href="http://bk1.ntp.org/ntp-stable/README.leapsmear">supported</a> by the abovementioned <abbr>NTP</abbr> implementations, <a href="https://github.com/google/unsmear">supports</a> conversion between <abbr>UTC</abbr> and smeared <abbr>POSIX</abbr> timestamps, and is used by major cloud service providers. However, according to -<a href="https://www.rfc-editor.org/rfc/rfc8633#section-3.7.1">§3.7.1 of +<a href="https://www.rfc-editor.org/rfc/rfc8633#section-3.7.1">§3.7.1 of Network Time Protocol Best Current Practices</a> (Internet <abbr>RFC</abbr> 8633), leap smearing is not suitable for applications requiring accurate <abbr>UTC</abbr> or civil time, @@ -1129,7 +1135,7 @@ and is intended for use only in single, well-controlled environments.</li> href="https://pairlist6.pair.net/mailman/listinfo/leapsecs">Leap Second Discussion List</a> covers <a href="https://www2.unb.ca/gge/Resources/gpsworld.november99.pdf">McCarthy -and Klepczynski's 1999 proposal to discontinue leap seconds</a>, +and Klepczynski’s 1999 proposal to discontinue leap seconds</a>, discussed further in <a href="https://www.cl.cam.ac.uk/~mgk25/time/metrologia-leapsecond.pdf">The leap second: its history and possible future</a>. @@ -1143,12 +1149,16 @@ to discontinue the use of leap seconds by 2035, and requested that no discontinuous adjustments be made to UTC for at least a century. The World Radiocommunication Conference <a href="https://www.itu.int/dms_pub/itu-r/opb/act/R-ACT-WRC.15-2023-PDF-E.pdf">resolved -in 2023</a> to cooperate with this process. -<a href="https://www.preprints.org/manuscript/202406.0043/v1">A proposal -to change the leap-second adjustments to Coordinated Universal Time</a> -(doi:<a href="https://doi.org/10.1088/1681-7575/ad6266">10.1088/1681-7575/ad6266</a>) -would replace leap seconds with 13-second leap smears occurring once per +in 2023</a> to cooperate with this process. One proposal to implement this +would replace leap seconds with seven 13-second leap smears occurring once per decade until 2100, with leap smears after that gradually increasing in size. +See: +<ul> +<li>Levine J. <a href="https://www.preprints.org/manuscript/202406.0043/v1">A +proposal to change the leap-second adjustments to +coordinated universal time</a>. <em>Metrologia.</em> 2024;61(5):055002. doi:<a +href="https://doi.org/10.1088/1681-7575/ad6266">10.1088/1681-7575/ad6266</a>.</li> +</ul> However, there is still no consensus on whether this is the best way to replace leap seconds. </li> @@ -1161,9 +1171,8 @@ to replace leap seconds. <li>The <a id="CLDR" href="https://cldr.unicode.org">Unicode Common Locale Data Repository (<abbr>CLDR</abbr>) Project</a> has localizations for time zone names, abbreviations, identifiers, and formats. For example, it -contains French translations for "Eastern European Summer Time", -"<abbr title="Eastern European Summer Time">EEST</abbr>", and -"Bucharest". Its +contains French translations for “Eastern European Summer Time”, +“<abbr title="Eastern European Summer Time">EEST</abbr>”, and “Bucharest”. Its <a href="https://unicode.org/cldr/charts/latest/by_type/">by-type charts</a> show these values for many locales. Data values are available in both <abbr title="Locale Data Markup Language">LDML</abbr> @@ -1174,13 +1183,13 @@ the international standard date and time notation</a> covers <a href="https://www.iso.org/standard/70907.html"><em><abbr title="International Organization for Standardization">ISO</abbr> -8601-1:2019 – Date and time – Representations for information -interchange – Part 1: Basic rules</em></a>.</li> +8601-1:2019 – Date and time – Representations for information +interchange – Part 1: Basic rules</em></a>.</li> <li> <a href="https://www.w3.org/TR/xmlschema/#dateTime"><abbr>XML</abbr> -Schema: Datatypes – dateTime</a> specifies a format inspired by +Schema: Datatypes – dateTime</a> specifies a format inspired by <abbr>ISO</abbr> 8601 that is in common use in <abbr>XML</abbr> data.</li> -<li><a href="https://www.rfc-editor.org/rfc/rfc5322#section-3.3">§3.3 of +<li><a href="https://www.rfc-editor.org/rfc/rfc5322#section-3.3">§3.3 of Internet Message Format</a> (Internet <abbr>RFC</abbr> 5322) specifies the time notation used in email and <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol"><abbr>HTTP</abbr></a> @@ -1193,7 +1202,7 @@ An extension, <a href="https://www.rfc-editor.org/rfc/rfc9557">Date and Time on the Internet: Timestamps with Additional Information</a> (Internet <abbr>RFC</abbr> 9557) extends this profile to let you specify the <code><abbr>tzdb</abbr></code> timezone of a timestamp -via suffixes like "<code>[Asia/Tokyo]</code>". +via suffixes like <code>[Asia/Tokyo]</code>. <li> <a href="https://web.archive.org/web/20190130042457/https://www.hackcraft.net/web/datetime/">Date & Time Formats on the Web</a> surveys web- and Internet-oriented date and time @@ -1201,17 +1210,17 @@ formats.</li> <li>Alphabetic time zone abbreviations should not be used as unique identifiers for <abbr>UT</abbr> offsets as they are ambiguous in practice. For example, in English-speaking North America -"<abbr>CST</abbr>" denotes 6 hours behind <abbr>UT</abbr>, +“<abbr>CST</abbr>” denotes 6 hours behind <abbr>UT</abbr>, but in China it denotes 8 hours ahead of <abbr>UT</abbr>, and French-speaking North Americans prefer -"<abbr title="Heure Normale du Centre">HNC</abbr>" to -"<abbr>CST</abbr>". The <code><abbr>tz</abbr></code> +“<abbr title="Heure Normale du Centre">HNC</abbr>” to +“<abbr>CST</abbr>”. The <code><abbr>tz</abbr></code> database contains English abbreviations for many timestamps; -unfortunately some of these abbreviations were merely the database maintainers' +unfortunately some of these abbreviations were merely the database maintainers’ inventions, and these have been removed when possible.</li> <li>Numeric time zone abbreviations typically count hours east of <abbr>UT</abbr>, e.g., +09 for Japan and -−10 for Hawaii. However, <abbr>POSIX</abbr> proleptic +−10 for Hawaii. However, <abbr>POSIX</abbr> proleptic <code><abbr>TZ</abbr></code> settings use the opposite convention. For example, one might use <code><abbr>TZ</abbr>="<abbr title="Japan Standard Time">JST</abbr>-9"</code> and @@ -1225,7 +1234,7 @@ any future changes to the rules. One should never set <abbr>POSIX</abbr> <code><abbr>TZ</abbr></code> to a value like <code>"GMT-9"</code>, though, since this would incorrectly imply that local time is nine hours ahead of <abbr>UT</abbr> and the time zone -is called "<abbr>GMT</abbr>".</li> +is called “<abbr>GMT</abbr>”.</li> </ul> </section> @@ -1245,6 +1254,8 @@ This web page is in the public domain, so clarified as of <br> Please send corrections to this web page to the <a href="mailto:tz@iana.org">time zone mailing list</a>. +The mailing list and its archives are public, +so please do not send confidential information. </footer> </body> </html> @@ -138,7 +138,7 @@ already support the POSIX-required range [\-24:59:59, 25:59:59]. bytes that represent time zone designations, which are null-terminated byte strings, each indexed by the .B tt_desigidx -values mentioned above. +values mentioned above, and each corresponding to a time zone abbreviation. The byte strings can overlap if one is a suffix of the other. The encoding of these strings is not specified. .IP \(bu @@ -221,6 +221,7 @@ after the last transition time stored in the file or for all instants if the file has no transitions. The TZ string is empty (i.e., nothing between the newlines) if there is no proleptic representation for such instants. +.PP If non-empty, the TZ string must agree with the local time type after the last transition time if present in the eight-byte data; for example, given the string @@ -229,6 +230,10 @@ then if a last transition time is in July, the transition's local time type must specify a daylight-saving time abbreviated .q "WEST" that is one hour east of UT. +.PP +The TZ string can contain time zone abbreviations and UT offsets that +do not appear elsewhere in the TZif file. +.PP Also, if there is at least one transition, time type 0 is associated with the time period from the indefinite past up to but not including the earliest transition time. @@ -289,7 +294,7 @@ time, TZif readers should either refuse to process post-expiration timestamps, or process them as if the expiration time did not exist (possibly with an error indication). .PP -Time zone designations should consist of at least three (3) +Time zone abbreviations should consist of at least three (3) and no more than six (6) ASCII characters from the set of alphanumerics, .q "\-", @@ -298,6 +303,10 @@ and This is for compatibility with POSIX requirements for time zone abbreviations. .PP +A numeric time zone abbreviation should match the UT offset. +For example, "+0530" should be used only if the UT offset is 5.5 hours +ahead of UT, and "\-00" should be used only if the UT offset is zero. +.PP When reading a version 2 or higher file, readers should ignore the version 1 header and data block except for the purpose of skipping over them. @@ -359,6 +368,14 @@ As a partial workaround, a writer can output more transitions than necessary, so that only far-future timestamps are mishandled by version 2 readers. .IP \(bu +Some readers might mishandle timestamps after a file's last transition, +because they require that all abbreviations or UT offsets +in the proleptic TZ string must also occur somewhere in the file's tables +of time zone designations and local time type records. +As a workaround, a writer can output more transitions than necessary, +so that the other tables contain duplicates of the proleptic TZ string's +abbreviations and offsets. +.IP \(bu Some readers designed for version 2 do not support permanent daylight saving time with transitions after 24:00 \(en e.g., a TZ string diff --git a/tzfile.5.txt b/tzfile.5.txt index 842fc132e2a7..78f9eec81657 100644 --- a/tzfile.5.txt +++ b/tzfile.5.txt @@ -14,57 +14,57 @@ DESCRIPTION a one-byte binary integer that is either 0 (false) or 1 (true). The format begins with a 44-byte header containing the following fields: - o The magic four-byte ASCII sequence "TZif" identifies the file as a + • The magic four-byte ASCII sequence “TZif” identifies the file as a timezone information file. - o A byte identifying the version of the file's format (as of 2021, - either an ASCII NUL, "2", "3", or "4"). + • A byte identifying the version of the file's format (as of 2021, + either an ASCII NUL, “2”, “3”, or “4”). - o Fifteen bytes containing zeros reserved for future use. + • Fifteen bytes containing zeros reserved for future use. - o Six four-byte integer values, in the following order: + • Six four-byte integer values, in the following order: tzh_ttisutcnt - The number of UT/local indicators stored in the file. (UT is + The number of UT/local indicators stored in the file. (UT is Universal Time.) tzh_ttisstdcnt The number of standard/wall indicators stored in the file. tzh_leapcnt - The number of leap seconds for which data entries are stored + The number of leap seconds for which data entries are stored in the file. tzh_timecnt - The number of transition times for which data entries are + The number of transition times for which data entries are stored in the file. tzh_typecnt - The number of local time types for which data entries are + The number of local time types for which data entries are stored in the file (must not be zero). tzh_charcnt - The number of bytes of time zone abbreviation strings stored + The number of bytes of time zone abbreviation strings stored in the file. - The above header is followed by the following fields, whose lengths + The above header is followed by the following fields, whose lengths depend on the contents of the header: - o tzh_timecnt four-byte signed integer values sorted in ascending - order. These values are written in network byte order. Each is - used as a transition time (as returned by time(2)) at which the + • tzh_timecnt four-byte signed integer values sorted in ascending + order. These values are written in network byte order. Each is + used as a transition time (as returned by time(2)) at which the rules for computing local time change. - o tzh_timecnt one-byte unsigned integer values; each one but the - last tells which of the different types of local time types - described in the file is associated with the time period starting + • tzh_timecnt one-byte unsigned integer values; each one but the + last tells which of the different types of local time types + described in the file is associated with the time period starting with the same-indexed transition time and continuing up to but not - including the next transition time. (The last time type is + including the next transition time. (The last time type is present only for consistency checking with the proleptic TZ string - described below.) These values serve as indices into the next + described below.) These values serve as indices into the next field. - o tzh_typecnt ttinfo entries, each defined as follows: + • tzh_typecnt ttinfo entries, each defined as follows: struct ttinfo { int32_t tt_utoff; @@ -72,317 +72,335 @@ DESCRIPTION unsigned char tt_desigidx; }; - Each structure is written as a four-byte signed integer value for - tt_utoff, in network byte order, followed by a one-byte boolean - for tt_isdst and a one-byte value for tt_desigidx. In each + Each structure is written as a four-byte signed integer value for + tt_utoff, in network byte order, followed by a one-byte boolean + for tt_isdst and a one-byte value for tt_desigidx. In each structure, tt_utoff gives the number of seconds to be added to UT, - tt_isdst tells whether tm_isdst should be set by localtime(3) and - tt_desigidx serves as an index into the array of time zone - abbreviation bytes that follow the ttinfo entries in the file; if - the designated string is "-00", the ttinfo entry is a placeholder - indicating that local time is unspecified. The tt_utoff value is - never equal to -2**31, to let 32-bit clients negate it without - overflow. Also, in realistic applications tt_utoff is in the - range [-89999, 93599] (i.e., more than -25 hours and less than 26 - hours); this allows easy support by implementations that already + tt_isdst tells whether tm_isdst should be set by localtime(3) and + tt_desigidx serves as an index into the array of time zone + abbreviation bytes that follow the ttinfo entries in the file; if + the designated string is "-00", the ttinfo entry is a placeholder + indicating that local time is unspecified. The tt_utoff value is + never equal to -2**31, to let 32-bit clients negate it without + overflow. Also, in realistic applications tt_utoff is in the + range [-89999, 93599] (i.e., more than -25 hours and less than 26 + hours); this allows easy support by implementations that already support the POSIX-required range [-24:59:59, 25:59:59]. - o tzh_charcnt bytes that represent time zone designations, which are - null-terminated byte strings, each indexed by the tt_desigidx - values mentioned above. The byte strings can overlap if one is a - suffix of the other. The encoding of these strings is not - specified. + • tzh_charcnt bytes that represent time zone designations, which are + null-terminated byte strings, each indexed by the tt_desigidx + values mentioned above, and each corresponding to a time zone + abbreviation. The byte strings can overlap if one is a suffix of + the other. The encoding of these strings is not specified. - o tzh_leapcnt pairs of four-byte values, written in network byte - order; the first value of each pair gives the non-negative time + • tzh_leapcnt pairs of four-byte values, written in network byte + order; the first value of each pair gives the non-negative time (as returned by time(2)) at which a leap second occurs or at which - the leap second table expires; the second is a signed integer - specifying the correction, which is the total number of leap + the leap second table expires; the second is a signed integer + specifying the correction, which is the total number of leap seconds to be applied during the time period starting at the given - time. The pairs of values are sorted in strictly ascending order - by time. Each pair denotes one leap second, either positive or - negative, except that if the last pair has the same correction as - the previous one, the last pair denotes the leap second table's + time. The pairs of values are sorted in strictly ascending order + by time. Each pair denotes one leap second, either positive or + negative, except that if the last pair has the same correction as + the previous one, the last pair denotes the leap second table's expiration time. Each leap second is at the end of a UTC calendar - month. The first leap second has a non-negative occurrence time, - and is a positive leap second if and only if its correction is - positive; the correction for each leap second after the first - differs from the previous leap second by either 1 for a positive + month. The first leap second has a non-negative occurrence time, + and is a positive leap second if and only if its correction is + positive; the correction for each leap second after the first + differs from the previous leap second by either 1 for a positive leap second, or -1 for a negative leap second. If the leap second - table is empty, the leap-second correction is zero for all - timestamps; otherwise, for timestamps before the first occurrence - time, the leap-second correction is zero if the first pair's - correction is 1 or -1, and is unspecified otherwise (which can + table is empty, the leap-second correction is zero for all + timestamps; otherwise, for timestamps before the first occurrence + time, the leap-second correction is zero if the first pair's + correction is 1 or -1, and is unspecified otherwise (which can happen only in files truncated at the start). - o tzh_ttisstdcnt standard/wall indicators, each stored as a one-byte - boolean; they tell whether the transition times associated with - local time types were specified as standard time or local (wall + • tzh_ttisstdcnt standard/wall indicators, each stored as a one-byte + boolean; they tell whether the transition times associated with + local time types were specified as standard time or local (wall clock) time. - o tzh_ttisutcnt UT/local indicators, each stored as a one-byte - boolean; they tell whether the transition times associated with - local time types were specified as UT or local time. If a - UT/local indicator is set, the corresponding standard/wall + • tzh_ttisutcnt UT/local indicators, each stored as a one-byte + boolean; they tell whether the transition times associated with + local time types were specified as UT or local time. If a + UT/local indicator is set, the corresponding standard/wall indicator must also be set. - The standard/wall and UT/local indicators were designed for - transforming a TZif file's transition times into transitions - appropriate for another time zone specified via a 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 + The standard/wall and UT/local indicators were designed for + transforming a TZif file's transition times into transitions + appropriate for another time zone specified via a proleptic TZ string + that lacks rules. For example, when TZ="EET-2EEST" and there is no + TZif file "EET-2EEST", the idea was to adapt the transition times from + a TZif file with the well-known name "posixrules" that is present only + for this purpose and is a copy of the file "Europe/Brussels", a file with a different UT offset. POSIX does not specify the details of this obsolete transformational behavior, the default rules are installation- - dependent, and no implementation is known to support this feature for + dependent, and no implementation is known to support this feature for timestamps past 2037, so users desiring (say) Greek time should instead specify TZ="Europe/Athens" for better historical coverage, falling back - on TZ="EET-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required + on TZ="EET-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required and older timestamps need not be handled accurately. - The localtime(3) function normally uses the first ttinfo structure in - the file if either tzh_timecnt is zero or the time argument is less + The localtime(3) function normally uses the first ttinfo structure in + the file if either tzh_timecnt is zero or the time argument is less than the first transition time recorded in the file. Version 2 format - For version-2-format timezone files, the above header and data are - followed by a second header and data, identical in format except that - eight bytes are used for each transition time or leap second time. - (Leap second counts remain four bytes.) After the second header and - data comes a newline-enclosed string in the style of the contents of a - proleptic TZ, for use in handling instants after the last transition - time stored in the file or for all instants if the file has no - transitions. The TZ string is empty (i.e., nothing between the - newlines) if there is no proleptic representation for such instants. - If non-empty, the TZ string must agree with the local time type after - the last transition time if present in the eight-byte data; for - example, given the string "WET0WEST,M3.5.0/1,M10.5.0" then if a last - transition time is in July, the transition's local time type must - specify a daylight-saving time abbreviated "WEST" that is one hour east - of UT. Also, if there is at least one transition, time type 0 is - associated with the time period from the indefinite past up to but not - including the earliest transition time. + For version-2-format timezone files, the above header and data are + followed by a second header and data, identical in format except that + eight bytes are used for each transition time or leap second time. + (Leap second counts remain four bytes.) After the second header and + data comes a newline-enclosed string in the style of the contents of a + proleptic TZ, for use in handling instants after the last transition + time stored in the file or for all instants if the file has no + transitions. The TZ string is empty (i.e., nothing between the + newlines) if there is no proleptic representation for such instants. + + If non-empty, the TZ string must agree with the local time type after + the last transition time if present in the eight-byte data; for + example, given the string “WET0WEST,M3.5.0/1,M10.5.0” then if a last + transition time is in July, the transition's local time type must + specify a daylight-saving time abbreviated “WEST” that is one hour east + of UT. + + The TZ string can contain time zone abbreviations and UT offsets that + do not appear elsewhere in the TZif file. + + Also, if there is at least one transition, time type 0 is associated + with the time period from the indefinite past up to but not including + the earliest transition time. Version 3 format - For version-3-format timezone files, a TZ string (see newtzset(3)) may + For version-3-format timezone files, a TZ string (see newtzset(3)) may use the following POSIX.1-2024 extensions to POSIX.1-2017: First, as in - TZ="<-02>2<-01>,M3.5.0/-1,M10.5.0/0", the hours part of its transition - times may be signed and range from -167 through 167 instead of being - limited to unsigned values from 0 through 24. Second, as in - TZ="XXX3EDT4,0/0,J365/23", DST is in effect all year if it starts - January 1 at 00:00 and ends December 31 at 24:00 plus the difference + TZ="<-02>2<-01>,M3.5.0/-1,M10.5.0/0", the hours part of its transition + times may be signed and range from -167 through 167 instead of being + limited to unsigned values from 0 through 24. Second, as in + TZ="XXX3EDT4,0/0,J365/23", DST is in effect all year if it starts + January 1 at 00:00 and ends December 31 at 24:00 plus the difference between daylight saving and standard time. Version 4 format - For version-4-format TZif files, the first leap second record can have - a correction that is neither +1 nor -1, to represent truncation of the - TZif file at the start. Also, if two or more leap second transitions - are present and the last entry's correction equals the previous one, - the last entry denotes the expiration of the leap second table instead - of a leap second; timestamps after this expiration are unreliable in - that future releases will likely add leap second entries after the - expiration, and the added leap seconds will change how post-expiration + For version-4-format TZif files, the first leap second record can have + a correction that is neither +1 nor -1, to represent truncation of the + TZif file at the start. Also, if two or more leap second transitions + are present and the last entry's correction equals the previous one, + the last entry denotes the expiration of the leap second table instead + of a leap second; timestamps after this expiration are unreliable in + that future releases will likely add leap second entries after the + expiration, and the added leap seconds will change how post-expiration timestamps are treated. Interoperability considerations Future changes to the format may append more data. - Version 1 files are considered a legacy format and should not be + Version 1 files are considered a legacy format and should not be generated, as they do not support transition times after the year 2038. - Readers that understand only Version 1 must ignore any data that + Readers that understand only Version 1 must ignore any data that extends beyond the calculated end of the version 1 data block. Other than version 1, writers should generate the lowest version number - needed by a file's data. For example, a writer should generate a - version 4 file only if its leap second table either expires or is - truncated at the start. Likewise, a writer not generating a version 4 - file should generate a version 3 file only if TZ string extensions are + needed by a file's data. For example, a writer should generate a + version 4 file only if its leap second table either expires or is + truncated at the start. Likewise, a writer not generating a version 4 + file should generate a version 3 file only if TZ string extensions are necessary to accurately model transition times. - The sequence of time changes defined by the version 1 header and data - block should be a contiguous sub-sequence of the time changes defined - by the version 2+ header and data block, and by the footer. This - guideline helps obsolescent version 1 readers agree with current - readers about timestamps within the contiguous sub-sequence. It also - lets writers not supporting obsolescent readers use a tzh_timecnt of + The sequence of time changes defined by the version 1 header and data + block should be a contiguous sub-sequence of the time changes defined + by the version 2+ header and data block, and by the footer. This + guideline helps obsolescent version 1 readers agree with current + readers about timestamps within the contiguous sub-sequence. It also + lets writers not supporting obsolescent readers use a tzh_timecnt of zero in the version 1 data block to save space. - When a TZif file contains a leap second table expiration time, TZif - readers should either refuse to process post-expiration timestamps, or - process them as if the expiration time did not exist (possibly with an + When a TZif file contains a leap second table expiration time, TZif + readers should either refuse to process post-expiration timestamps, or + process them as if the expiration time did not exist (possibly with an error indication). - Time zone designations should consist of at least three (3) and no more - than six (6) ASCII characters from the set of alphanumerics, "-", and - "+". This is for compatibility with POSIX requirements for time zone - abbreviations. + Time zone abbreviations should consist of at least three (3) and no + more than six (6) ASCII characters from the set of alphanumerics, “-”, + and “+”. This is for compatibility with POSIX requirements for time + zone abbreviations. - When reading a version 2 or higher file, readers should ignore the + A numeric time zone abbreviation should match the UT offset. For + example, "+0530" should be used only if the UT offset is 5.5 hours + ahead of UT, and "-00" should be used only if the UT offset is zero. + + When reading a version 2 or higher file, readers should ignore the version 1 header and data block except for the purpose of skipping over them. - Readers should calculate the total lengths of the headers and data + Readers should calculate the total lengths of the headers and data blocks and check that they all fit within the actual file size, as part of a validity check for the file. - When a positive leap second occurs, readers should append an extra - second to the local minute containing the second just before the leap - second. If this occurs when the UTC offset is not a multiple of 60 - seconds, the leap second occurs earlier than the last second of the - local minute and the minute's remaining local seconds are numbered + When a positive leap second occurs, readers should append an extra + second to the local minute containing the second just before the leap + second. If this occurs when the UTC offset is not a multiple of 60 + seconds, the leap second occurs earlier than the last second of the + local minute and the minute's remaining local seconds are numbered through 60 instead of the usual 59; the UTC offset is unaffected. Common interoperability issues - This section documents common problems in reading or writing TZif - files. Most of these are problems in generating TZif files for use by + This section documents common problems in reading or writing TZif + files. Most of these are problems in generating TZif files for use by older readers. The goals of this section are to help: - o TZif writers output files that avoid common pitfalls in older or + • TZif writers output files that avoid common pitfalls in older or buggy TZif readers, - o TZif readers avoid common pitfalls when reading files generated by + • TZif readers avoid common pitfalls when reading files generated by future TZif writers, and - o any future specification authors see what sort of problems arise + • any future specification authors see what sort of problems arise when the TZif format is changed. - When new versions of the TZif format have been defined, a design goal - has been that a reader can successfully use a TZif file even if the - file is of a later TZif version than what the reader was designed for. - When complete compatibility was not achieved, an attempt was made to - limit glitches to rarely used timestamps and allow simple partial - workarounds in writers designed to generate newer-version data useful - even for older-version readers. This section attempts to document + When new versions of the TZif format have been defined, a design goal + has been that a reader can successfully use a TZif file even if the + file is of a later TZif version than what the reader was designed for. + When complete compatibility was not achieved, an attempt was made to + limit glitches to rarely used timestamps and allow simple partial + workarounds in writers designed to generate newer-version data useful + even for older-version readers. This section attempts to document these compatibility issues and workarounds as well as documenting other common bugs in readers. Interoperability problems with TZif include the following: - o Some readers examine only version 1 data. As a partial - workaround, a writer can output as much version 1 data as - possible. However, a reader should ignore version 1 data, and - should use version 2+ data even if the reader's native timestamps + • Some readers examine only version 1 data. As a partial + workaround, a writer can output as much version 1 data as + possible. However, a reader should ignore version 1 data, and + should use version 2+ data even if the reader's native timestamps have only 32 bits. - o Some readers designed for version 2 might mishandle timestamps - after a version 3 or higher file's last transition, because they - cannot parse the POSIX.1-2024 extensions to POSIX.1-2017 in the + • Some readers designed for version 2 might mishandle timestamps + after a version 3 or higher file's last transition, because they + cannot parse the POSIX.1-2024 extensions to POSIX.1-2017 in the proleptic TZ string. As a partial workaround, a writer can output - more transitions than necessary, so that only far-future + more transitions than necessary, so that only far-future timestamps are mishandled by version 2 readers. - o Some readers designed for version 2 do not support permanent - daylight saving time with transitions after 24:00 - e.g., a TZ - string "EST5EDT,0/0,J365/25" denoting permanent Eastern Daylight - Time (-04). As a workaround, a writer can substitute standard - time for two time zones east, e.g., "XXX3EDT4,0/0,J365/23" for a - time zone with a never-used standard time (XXX, -03) and negative - daylight saving time (EDT, -04) all year. Alternatively, as a - partial workaround, a writer can substitute standard time for the - next time zone east - e.g., "AST4" for permanent Atlantic Standard + • Some readers might mishandle timestamps after a file's last + transition, because they require that all abbreviations or UT + offsets in the proleptic TZ string must also occur somewhere in + the file's tables of time zone designations and local time type + records. As a workaround, a writer can output more transitions + than necessary, so that the other tables contain duplicates of the + proleptic TZ string's abbreviations and offsets. + + • Some readers designed for version 2 do not support permanent + daylight saving time with transitions after 24:00 – e.g., a TZ + string “EST5EDT,0/0,J365/25” denoting permanent Eastern Daylight + Time (-04). As a workaround, a writer can substitute standard + time for two time zones east, e.g., “XXX3EDT4,0/0,J365/23” for a + time zone with a never-used standard time (XXX, -03) and negative + daylight saving time (EDT, -04) all year. Alternatively, as a + partial workaround, a writer can substitute standard time for the + next time zone east – e.g., “AST4” for permanent Atlantic Standard Time (-04). - o Some readers designed for version 2 or 3 and that require strict - conformance to RFC 9636 reject version 4 files whose leap second + • Some readers designed for version 2 or 3 and that require strict + conformance to RFC 9636 reject version 4 files whose leap second tables are truncated at the start or end in expiration times. - o Some readers ignore the footer, and instead predict future - timestamps from the time type of the last transition. As a - partial workaround, a writer can output more transitions than + • Some readers ignore the footer, and instead predict future + timestamps from the time type of the last transition. As a + partial workaround, a writer can output more transitions than necessary. - o Some stripped-down readers ignore everything but the footer, and + • Some stripped-down readers ignore everything but the footer, and use its proleptic TZ string to calculate all timestamps. Although - this approach often works for current and future timestamps, it - obviously has problems with past timestamps, and even for current - timestamps it can fail for settings like TZ="Africa/Casablanca". - This corresponds to a TZif file containing explicit transitions - through the year 2087, followed by a footer containing the TZ - string "<+01>-1", which should be used only for timestamps after + this approach often works for current and future timestamps, it + obviously has problems with past timestamps, and even for current + timestamps it can fail for settings like TZ="Africa/Casablanca". + This corresponds to a TZif file containing explicit transitions + through the year 2087, followed by a footer containing the TZ + string “<+01>-1”, which should be used only for timestamps after the last explicit transition. - o Some readers do not use time type 0 for timestamps before the + • Some readers do not use time type 0 for timestamps before the first transition, in that they infer a time type using a heuristic that does not always select time type 0. As a partial workaround, - a writer can output a dummy (no-op) first transition at an early + a writer can output a dummy (no-op) first transition at an early time. - o Some readers mishandle timestamps before the first transition that - has a timestamp that is not less than -2**31. Readers that + • Some readers mishandle timestamps before the first transition that + has a timestamp that is not less than -2**31. Readers that support only 32-bit timestamps are likely to be more prone to this - problem, for example, when they process 64-bit transitions only - some of which are representable in 32 bits. As a partial - workaround, a writer can output a dummy transition at timestamp + problem, for example, when they process 64-bit transitions only + some of which are representable in 32 bits. As a partial + workaround, a writer can output a dummy transition at timestamp -2**31. - o Some readers mishandle a transition if its timestamp has the + • Some readers mishandle a transition if its timestamp has the minimum possible signed 64-bit value. Timestamps less than -2**59 are not recommended. - o Some readers mishandle proleptic TZ strings that contain "<" or - ">". As a partial workaround, a writer can avoid using "<" or ">" + • Some readers mishandle proleptic TZ strings that contain “<” or + “>”. As a partial workaround, a writer can avoid using “<” or “>” for time zone abbreviations containing only alphabetic characters. - o Many readers mishandle time zone abbreviations that contain non- + • Many readers mishandle time zone abbreviations that contain non- ASCII characters. These characters are not recommended. - o Some readers may mishandle time zone abbreviations that contain - fewer than 3 or more than 6 characters or that contain ASCII - characters other than alphanumerics, "-", and "+". These + • Some readers may mishandle time zone abbreviations that contain + fewer than 3 or more than 6 characters or that contain ASCII + characters other than alphanumerics, “-”, and “+”. These abbreviations are not recommended. - o Some readers mishandle TZif files that specify daylight-saving - time UT offsets that are less than the UT offsets for the - corresponding standard time. These readers do not support + • Some readers mishandle TZif files that specify daylight-saving + time UT offsets that are less than the UT offsets for the + corresponding standard time. These readers do not support locations like Ireland, which uses the equivalent of the TZ string - "IST-1GMT0,M10.5.0,M3.5.0/1", observing standard time (IST, +01) - in summer and daylight saving time (GMT, +00) in winter. As a + “IST-1GMT0,M10.5.0,M3.5.0/1”, observing standard time (IST, +01) + in summer and daylight saving time (GMT, +00) in winter. As a partial workaround, a writer can output data for the equivalent of - the TZ string "GMT0IST,M3.5.0/1,M10.5.0", thus swapping standard - and daylight saving time. Although this workaround misidentifies - which part of the year uses daylight saving time, it records UT + the TZ string “GMT0IST,M3.5.0/1,M10.5.0”, thus swapping standard + and daylight saving time. Although this workaround misidentifies + which part of the year uses daylight saving time, it records UT offsets and time zone abbreviations correctly. - o Some readers generate ambiguous timestamps for positive leap - seconds that occur when the UTC offset is not a multiple of 60 - seconds. For example, with UTC offset +01:23:45 and a positive - leap second 78796801 (1972-06-30 23:59:60 UTC), some readers will + • Some readers generate ambiguous timestamps for positive leap + seconds that occur when the UTC offset is not a multiple of 60 + seconds. For example, with UTC offset +01:23:45 and a positive + leap second 78796801 (1972-06-30 23:59:60 UTC), some readers will map both 78796800 and 78796801 to 01:23:45 local time the next day - instead of mapping the latter to 01:23:46, and they will map - 78796815 to 01:23:59 instead of to 01:23:60. This has not yet - been a practical problem, since no civil authority has observed + instead of mapping the latter to 01:23:46, and they will map + 78796815 to 01:23:59 instead of to 01:23:60. This has not yet + been a practical problem, since no civil authority has observed such UTC offsets since leap seconds were introduced in 1972. - Some interoperability problems are reader bugs that are listed here + Some interoperability problems are reader bugs that are listed here mostly as warnings to developers of readers. - o Some readers do not support negative timestamps. Developers of - distributed applications should keep this in mind if they need to + • Some readers do not support negative timestamps. Developers of + distributed applications should keep this in mind if they need to deal with pre-1970 data. - o Some readers mishandle timestamps before the first transition that - has a non-negative timestamp. Readers that do not support + • Some readers mishandle timestamps before the first transition that + has a non-negative timestamp. Readers that do not support negative timestamps are likely to be more prone to this problem. - o Some readers mishandle time zone abbreviations like "-08" that - contain "+", "-", or digits. + • Some readers mishandle time zone abbreviations like “-08” that + contain “+”, “-”, or digits. - o Some readers mishandle UT offsets that are out of the traditional - range of -12 through +12 hours, and so do not support locations + • Some readers mishandle UT offsets that are out of the traditional + range of -12 through +12 hours, and so do not support locations like Kiritimati that are outside this range. - o Some readers mishandle UT offsets in the range [-3599, -1] seconds - from UT because they integer-divide the offset by 3600 to get 0 - and then display the hour part as "+00". + • Some readers mishandle UT offsets in the range [-3599, -1] seconds + from UT because they integer-divide the offset by 3600 to get 0 + and then display the hour part as “+00”. - o Some readers mishandle UT offsets that are not a multiple of one + • Some readers mishandle UT offsets that are not a multiple of one hour, or of 15 minutes, or of 1 minute. SEE ALSO time(2), localtime(3), tzset(3), tzselect(8), zdump(8), zic(8). - Olson A, Eggert P, Murchison K. The Time Zone Information Format + Olson A, Eggert P, Murchison K. The Time Zone Information Format (TZif). October 2024. Internet RFC 9636 doi:10.17487/RFC9636. Time Zone Database tzfile(5) @@ -32,7 +32,7 @@ ** Each file begins with. . . */ -#define TZ_MAGIC "TZif" +#define TZ_MAGIC "TZif" struct tzhead { char tzh_magic[4]; /* TZ_MAGIC */ diff --git a/tzselect.8.txt b/tzselect.8.txt index 033c77ea82e9..75991e7b4172 100644 --- a/tzselect.8.txt +++ b/tzselect.8.txt @@ -16,29 +16,29 @@ DESCRIPTION OPTIONS -c coord - Instead of asking for continent and then country and then city, - ask for selection from time zones whose largest cities are - closest to the location with geographical coordinates coord. + Instead of asking for continent and then country and then city, + ask for selection from time zones whose largest cities are + closest to the location with geographical coordinates coord. Use ISO 6709 notation for coord, that is, a latitude immediately - followed by a longitude. The latitude and longitude should be - signed integers followed by an optional decimal point and - fraction: positive numbers represent north and east, negative - south and west. Latitudes with two and longitudes with three - integer digits are treated as degrees; latitudes with four or + followed by a longitude. The latitude and longitude should be + signed integers followed by an optional decimal point and + fraction: positive numbers represent north and east, negative + south and west. Latitudes with two and longitudes with three + integer digits are treated as degrees; latitudes with four or six and longitudes with five or seven integer digits are treated - as DDMM, DDDMM, DDMMSS, or DDDMMSS representing DD or DDD - degrees, MM minutes, and zero or SS seconds, with any trailing - fractions represent fractional minutes or (if SS is present) - seconds. The decimal point is that of the current locale. For + as DDMM, DDDMM, DDMMSS, or DDDMMSS representing DD or DDD + degrees, MM minutes, and zero or SS seconds, with any trailing + fractions represent fractional minutes or (if SS is present) + seconds. The decimal point is that of the current locale. For example, in the (default) C locale, -c +40.689-074.045 specifies 40.689 degrees N, 74.045 degrees W, -c +4041.4-07402.7 specifies - 40 degrees 41.4 minutes N, 74 degrees 2.7 minutes W, and + 40 degrees 41.4 minutes N, 74 degrees 2.7 minutes W, and -c +404121-0740240 specifies 40 degrees 41 minutes 21 seconds N, - 74 degrees 2 minutes 40 seconds W. If coord is not one of the + 74 degrees 2 minutes 40 seconds W. If coord is not one of the documented forms, the resulting behavior is unspecified. -n limit - When -c is used, display the closest limit locations (default + When -c is used, display the closest limit locations (default 10). --help Output help information and exit. @@ -49,7 +49,7 @@ OPTIONS ENVIRONMENT VARIABLES AWK Name of a POSIX-compliant awk program (default: awk). - TZDIR Name of the directory containing timezone data files (default: + TZDIR Name of the directory containing timezone data files (default: /usr/share/zoneinfo). FILES @@ -57,21 +57,21 @@ FILES Table of ISO 3166 2-letter country codes and country names. TZDIR/zone1970.tab - Table of country codes, latitude and longitude, timezones, and + Table of country codes, latitude and longitude, timezones, and descriptive comments. TZDIR/TZ Timezone data file for timezone TZ. EXIT STATUS - The exit status is zero if a timezone was successfully obtained from + The exit status is zero if a timezone was successfully obtained from the user, nonzero otherwise. SEE ALSO newctime(3), tzfile(5), zdump(8), zic(8) NOTES - Applications should not assume that tzselect's output matches the + Applications should not assume that tzselect's output matches the user's political preferences. Time Zone Database tzselect(8) diff --git a/tzselect.ksh b/tzselect.ksh index ca3d82c6aab6..85a8c670e0da 100644 --- a/tzselect.ksh +++ b/tzselect.ksh @@ -145,9 +145,11 @@ do t*) # Undocumented option, used for developer testing. zonetabtype=$OPTARG;; -help) - exec echo "$usage";; + say "$usage" + exit;; -version) - exec echo "tzselect $PKGVERSION$TZVERSION";; + say "tzselect $PKGVERSION$TZVERSION" + exit;; -*) say >&2 "$0: -$opt$OPTARG: unknown option; try '$0 --help'"; exit 1;; *) @@ -161,15 +163,15 @@ case $# in *) say >&2 "$0: $1: unknown argument"; exit 1 esac -# translit=true to try transliteration. +# translit=: to try transliteration. # This is false if U+12345 CUNEIFORM SIGN URU TIMES KI has length 1 # which means the shell and (presumably) awk do not need transliteration. -# It is true if the byte string has some other length in characters, or +# It is ':' if the byte string has some other length in characters, or # if this is a POSIX.1-2017 or earlier shell that does not support $'...'. CUNEIFORM_SIGN_URU_TIMES_KI=$'\360\222\215\205' if test ${#CUNEIFORM_SIGN_URU_TIMES_KI} = 1 then translit=false -else translit=true +else translit=: fi # Read into shell variable $1 the contents of file $2. @@ -516,8 +518,7 @@ while ' ="$distance_table" ) echo >&2 'Please select one of the following timezones,' - echo >&2 'listed roughly in increasing order' \ - "of distance from $coord". + say >&2 "listed roughly in increasing order of distance from $coord." doselect $regions region=$select_result tz=$( @@ -1 +1 @@ -2025b +2025c diff --git a/workman.sh b/workman.sh index 29f317cb40c4..5da55654b01c 100644 --- a/workman.sh +++ b/workman.sh @@ -4,17 +4,35 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. -if (type nroff && type perl) >/dev/null 2>&1; then +manflags= +while + case $1 in + -*) :;; + *) false;; + esac +do + manflags="$manflags $1" + shift +done - # Tell groff not to emit SGR escape sequences (ANSI color escapes). - export GROFF_NO_SGR=1 - - echo ".am TH -.hy 0 +groff="groff -dAD=l -rHY=0 $manflags -mtty-char -man -ww -P-bcou" +if ($groff) </dev/null >/dev/null 2>&1; then + $groff "$@" +elif (type mandoc && type col) >/dev/null 2>&1; then + mandoc $manflags -man "$@" | col -bx +elif (type nroff && type perl) >/dev/null 2>&1; then + printf '%s\n' '. +.\" Left-adjust and do not hyphenate. +.am TH .na +.hy 0 .. +.\" Omit internal page headers and footers. +.\" Unfortunately this also omits the starting header and ending footer, +.\" but that is the best old nroff can easily do. .rm }H -.rm }F" | nroff -man - ${1+"$@"} | perl -ne ' +.rm }F +.' | nroff -man - "$@" | perl -ne ' binmode STDIN, '\'':encoding(utf8)'\''; binmode STDOUT, '\'':encoding(utf8)'\''; chomp; @@ -32,9 +50,7 @@ if (type nroff && type perl) >/dev/null 2>&1; then $didprint = 1; } ' -elif (type mandoc && type col) >/dev/null 2>&1; then - mandoc -man -T ascii "$@" | col -bx else - echo >&2 "$0: please install nroff and perl, or mandoc and col" + printf >&2 '%s\n' "$0: please install groff, or mandoc and col" exit 1 fi diff --git a/zdump.8.txt b/zdump.8.txt index ca6d38f87b1c..488e2d8da1f8 100644 --- a/zdump.8.txt +++ b/zdump.8.txt @@ -17,77 +17,77 @@ OPTIONS --help Output short usage message and exit. - -i Output a description of time intervals. For each timezone on - the command line, output an interval-format description of the - timezone. See "INTERVAL FORMAT" below. + -i Output a description of time intervals. For each timezone on + the command line, output an interval-format description of the + timezone. See “INTERVAL FORMAT” below. - -v Output a verbose description of time intervals. For each + -v Output a verbose description of time intervals. For each timezone on the command line, print the times at the two extreme - time values, the times (if present) at and just beyond the - boundaries of years that localtime(3) and gmtime(3) can - represent, and the times both one second before and exactly at - each detected time discontinuity. Each line is followed by - isdst=D where D is positive, zero, or negative depending on - whether the given time is daylight saving time, standard time, - or an unknown time type, respectively. Each line is also - followed by gmtoff=N if the given local time is known to be N + time values, the times (if present) at and just beyond the + boundaries of years that localtime(3) and gmtime(3) can + represent, and the times both one second before and exactly at + each detected time discontinuity. Each line is followed by + isdst=D where D is positive, zero, or negative depending on + whether the given time is daylight saving time, standard time, + or an unknown time type, respectively. Each line is also + followed by gmtoff=N if the given local time is known to be N seconds east of Greenwich. - -V Like -v, except omit output concerning extreme time and year + -V Like -v, except omit output concerning extreme time and year values. This generates output that is easier to compare to that of implementations with different time representations. -c [loyear,]hiyear - Cut off interval output at the given year(s). Cutoff times are - computed using the proleptic Gregorian calendar with year 0 and - with Universal Time (UT) ignoring leap seconds. Cutoffs are at - the start of each year, where the lower-bound timestamp is - inclusive and the upper is exclusive; for example, -c 1970,2070 - selects transitions on or after 1970-01-01 00:00:00 UTC and - before 2070-01-01 00:00:00 UTC. The default cutoff is + Cut off interval output at the given year(s). Cutoff times are + computed using the proleptic Gregorian calendar with year 0 and + with Universal Time (UT) ignoring leap seconds. Cutoffs are at + the start of each year, where the lower-bound timestamp is + inclusive and the upper is exclusive; for example, -c 1970,2070 + selects transitions on or after 1970-01-01 00:00:00 UTC and + before 2070-01-01 00:00:00 UTC. The default cutoff is -500,2500. -t [lotime,]hitime - Cut off interval output at the given time(s), given in decimal - seconds since 1970-01-01 00:00:00 Coordinated Universal Time - (UTC). The timezone determines whether the count includes leap - seconds. As with -c, the cutoff's lower bound is inclusive and + Cut off interval output at the given time(s), given in decimal + seconds since 1970-01-01 00:00:00 Coordinated Universal Time + (UTC). The timezone determines whether the count includes leap + seconds. As with -c, the cutoff's lower bound is inclusive and its upper bound is exclusive. INTERVAL FORMAT - The interval format is a compact text representation that is intended - to be both human- and machine-readable. It consists of an empty line, - then a line "TZ=string" where string is a double-quoted string giving - the timezone, a second line "- - interval" describing the time interval - before the first transition if any, and zero or more following lines - "date time interval", one line for each transition time and following + The interval format is a compact text representation that is intended + to be both human- and machine-readable. It consists of an empty line, + then a line “TZ=string” where string is a double-quoted string giving + the timezone, a second line “- - interval” describing the time interval + before the first transition if any, and zero or more following lines + “date time interval”, one line for each transition time and following interval. Fields are separated by single tabs. Dates are in yyyy-mm-dd format and times are in 24-hour hh:mm:ss format where hh<24. Times are in local time immediately after the transition. - A time interval description consists of a UT offset in signed +-hhmmss - format, a time zone abbreviation, and an isdst flag. An abbreviation - that equals the UT offset is omitted; other abbreviations are double- - quoted strings unless they consist of one or more alphabetic - characters. An isdst flag is omitted for standard time, and otherwise - is a decimal integer that is unsigned and positive (typically 1) for + A time interval description consists of a UT offset in signed ±hhmmss + format, a time zone abbreviation, and an isdst flag. An abbreviation + that equals the UT offset is omitted; other abbreviations are double- + quoted strings unless they consist of one or more alphabetic + characters. An isdst flag is omitted for standard time, and otherwise + is a decimal integer that is unsigned and positive (typically 1) for daylight saving time and negative for unknown. In times and in UT offsets with absolute value less than 100 hours, the - seconds are omitted if they are zero, and the minutes are also omitted + seconds are omitted if they are zero, and the minutes are also omitted if they are also zero. Positive UT offsets are east of Greenwich. The UT offset -00 denotes a UT placeholder in areas where the actual offset - is unspecified; by convention, this occurs when the UT offset is zero - and the time zone abbreviation begins with "-" or is "zzz". + is unspecified; by convention, this occurs when the UT offset is zero + and the time zone abbreviation begins with “-” or is “zzz”. - In double-quoted strings, escape sequences represent unusual + In double-quoted strings, escape sequences represent unusual characters. The escape sequences are \s for space, and \", \\, \f, \n, - \r, \t, and \v with their usual meaning in the C programming language. - E.g., the double-quoted string ""CET\s\"\\"" represents the character - sequence "CET "\". + \r, \t, and \v with their usual meaning in the C programming language. + E.g., the double-quoted string “"CET\s\"\\"” represents the character + sequence “CET "\”. - Here is an example of the output, with the leading empty line omitted. - (This example is shown with tab stops set far enough apart so that the + Here is an example of the output, with the leading empty line omitted. + (This example is shown with tab stops set far enough apart so that the tabbed columns line up.) TZ="Pacific/Honolulu" @@ -101,14 +101,14 @@ INTERVAL FORMAT 1947-06-08 02:30 -10 HST Here, local time begins 10 hours, 31 minutes and 26 seconds west of UT, - and is a standard time abbreviated LMT. Immediately after the first - transition, the date is 1896-01-13 and the time is 12:01:26, and the - following time interval is 10.5 hours west of UT, a standard time - abbreviated HST. Immediately after the second transition, the date is - 1933-04-30 and the time is 03:00:00 and the following time interval is - 9.5 hours west of UT, is abbreviated HDT, and is daylight saving time. - Immediately after the last transition the date is 1947-06-08 and the - time is 02:30:00, and the following time interval is 10 hours west of + and is a standard time abbreviated LMT. Immediately after the first + transition, the date is 1896-01-13 and the time is 12:01:26, and the + following time interval is 10.5 hours west of UT, a standard time + abbreviated HST. Immediately after the second transition, the date is + 1933-04-30 and the time is 03:00:00 and the following time interval is + 9.5 hours west of UT, is abbreviated HDT, and is daylight saving time. + Immediately after the last transition the date is 1947-06-08 and the + time is 02:30:00, and the following time interval is 10 hours west of UT, a standard time abbreviated HST. Here are excerpts from another example: @@ -123,20 +123,20 @@ INTERVAL FORMAT 2014-10-26 01 +03 2016-03-27 03 +04 - This time zone is east of UT, so its UT offsets are positive. Also, - many of its time zone abbreviations are omitted since they duplicate + This time zone is east of UT, so its UT offsets are positive. Also, + many of its time zone abbreviations are omitted since they duplicate the text of the UT offset. LIMITATIONS - Time discontinuities are found by sampling the results returned by - localtime(3) at twelve-hour intervals. This works in all real-world + Time discontinuities are found by sampling the results returned by + localtime(3) at twelve-hour intervals. This works in all real-world cases; one can construct artificial time zones for which this fails. - In the -v and -V output, "UT" denotes the value returned by gmtime(3), - which uses UTC for modern timestamps and some other UT flavor for - timestamps that predate the introduction of UTC. No attempt is - currently made to have the output use "UTC" for newer and "UT" for - older timestamps, partly because the exact date of the introduction of + In the -v and -V output, “UT” denotes the value returned by gmtime(3), + which uses UTC for modern timestamps and some other UT flavor for + timestamps that predate the introduction of UTC. No attempt is + currently made to have the output use “UTC” for newer and “UT” for + older timestamps, partly because the exact date of the introduction of UTC is problematic. SEE ALSO @@ -61,13 +61,6 @@ enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 }; # define timezone_t char ** #endif -#if !HAVE_POSIX_DECLS -extern int getopt(int argc, char * const argv[], - const char * options); -extern char * optarg; -extern int optind; -#endif - /* The minimum and maximum finite time values. */ enum { atime_shift = CHAR_BIT * sizeof(time_t) - 2 }; static time_t const absolute_min_time = @@ -927,6 +920,7 @@ my_snprintf(char *s, size_t size, char const *format, ...) int n; va_list args; char const *arg; + char *cp; size_t arglen, slen; char buf[1024]; va_start(args, format); @@ -943,8 +937,9 @@ my_snprintf(char *s, size_t size, char const *format, ...) arglen = n; } slen = arglen < size ? arglen : size - 1; - memcpy(s, arg, slen); - s[slen] = '\0'; + cp = s; + cp = mempcpy(cp, arg, slen); + *cp = '\0'; n = arglen <= INT_MAX ? arglen : -1; va_end(args); return n; @@ -1073,8 +1068,9 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt, char fbuf[100]; bool oversized = sizeof fbuf <= f_prefix_copy_size; char *f_prefix_copy = oversized ? xmalloc(f_prefix_copy_size) : fbuf; - memcpy(f_prefix_copy, f, f_prefix_len); - strcpy(f_prefix_copy + f_prefix_len, "X"); + char *cp = f_prefix_copy; + cp = mempcpy(cp, f, f_prefix_len); + strcpy(cp, "X"); formatted_len = strftime(b, s, f_prefix_copy, tm); if (oversized) free(f_prefix_copy); @@ -22,8 +22,6 @@ zic \- timezone compiler .el .ds < \(la .ie '\(ra'' .ds > > .el .ds > \(ra -.ie \n(.g .ds : \: -.el .ds : . .ds d " degrees .ds m " minutes .ds s " seconds @@ -63,7 +61,7 @@ is .BR fat , generate additional data entries that work around potential bugs or incompatibilities in older software, such as software that mishandles -the 64-bit generated data. +a TZif file's 64-bit data or proleptic TZ string. If .I bloat is @@ -72,12 +70,19 @@ keep the output files small; this can help check for the bugs and incompatibilities. The default is .BR slim , -as software that mishandles 64-bit data typically -mishandles timestamps after the year 2038 anyway. +as the +.B fat +workarounds are typically good only until the year 2038 anyway. Also see the .B \-r option for another way to alter output size. .TP +.BI \-D +Do not create ancestor directories of output files, +For example, for a zone named America/Los_Angeles +the directory America should already exist. +By default, the directory and its ancestors are created +if they do not already exist. .BI "\-d " directory Create time conversion information files in the named directory rather than in the standard directory named below. @@ -132,6 +137,19 @@ if .IR timezone 's transitions are at standard time or Universal Time (UT) instead of local time. .TP +.BI "\-m " mode +Create TZif files with the given file mode bits. +By default the files are created with mode 644 as modified by the umask. +With this option they are created with the given mode instead. +For portability the mode should be an unsigned octal integer, +typically 644 or 444; +some platforms also support +.BR chmod (1)-style +symbolic modes. +This option does not affect created ancestor directories, +which have mode 755 as modified by the umask. +The option is ignored on platforms lacking the notion of file mode bits. +.TP .BR "\-r " "[\fB@\fP\fIlo\fP][\fB/@\fP\fIhi\fP]" Limit the applicability of output files to timestamps in the range from @@ -185,6 +203,19 @@ it increases the size of the altered output files. When creating local time information, put the configuration link in the named file rather than in the standard location. .TP +.BI "\-u " owner\fR[:\fPgroup\fR]\fP +Change the output regular files' owner and group to those specified. +The +.I owner +is either a user name, or an unsigned decimal integer user ID, +or an empty string meaning no change to the owner. +The +.I group +is similar for group names and IDs. +This option does not affect directories or hard or symbolic links. +It typically needs special privileges to change ownership, +and is ignored on platforms that lack the notions of owners and groups. +.TP .B \-v Be more verbose, and complain about the following situations: .RS @@ -288,8 +319,10 @@ zero or more lines, each ending in a newline byte and containing at most 2048 bytes counting the newline, and without any NUL bytes. The input text's encoding is typically UTF-8 or ASCII; it should have a unibyte representation -for the POSIX Portable Character Set (PPCS) -\*<https://pubs\*:.opengroup\*:.org/\*:onlinepubs/\*:9699919799/\*:basedefs/\*:V1_chap06\*:.html\*> +for the +.UR https://\:pubs\:.opengroup\:.org/\:onlinepubs/\:9799919799/\:basedefs/\:V1_chap06\:.html +POSIX Portable Character Set (PPCS) +.UE and the encoding's non-unibyte characters should consist entirely of non-PPCS bytes. Non-PPCS characters typically occur only in comments: although output file names and time zone abbreviations can contain @@ -681,11 +714,14 @@ Zone America/Menominee \-5:00 \- EST 1973 Apr 29 2:00 .in .fi Here, an incorrect reading would be there were two clock changes on 1973-04-29, -the first from 02:00 EST (\-05) to 01:00 CST (\-06), -and the second an hour later from 02:00 CST (\-06) to 03:00 CDT (\-05). +the first from 02:00 EST (\-05) to 01:00 CST (\-06) according to the +.q "until" +value in the zone line, +and the second an hour later from 02:00 CST (\-06) to 03:00 CDT (\-05) +according to the values in the April rule line. However, .B zic -interprets this more sensibly as a single transition from 02:00 CST (\-05) to +interprets this more sensibly as a single transition from 02:00 EST (\-05) to 02:00 CDT (\-05). .PP A link line has the form diff --git a/zic.8.txt b/zic.8.txt index d5d9afc2975b..2bf66e1aa64d 100644 --- a/zic.8.txt +++ b/zic.8.txt @@ -9,7 +9,7 @@ SYNOPSIS DESCRIPTION The zic program reads text from the file(s) named on the command line and creates the timezone information format (TZif) files specified in - this input. If a filename is "-", standard input is read. + this input. If a filename is “-”, standard input is read. OPTIONS --version @@ -18,22 +18,25 @@ OPTIONS --help Output short usage message and exit. -b bloat - Output backward-compatibility data as specified by bloat. If - bloat is fat, generate additional data entries that work around - potential bugs or incompatibilities in older software, such as - software that mishandles the 64-bit generated data. If bloat is - slim, keep the output files small; this can help check for the - bugs and incompatibilities. The default is slim, as software - that mishandles 64-bit data typically mishandles timestamps - after the year 2038 anyway. Also see the -r option for another - way to alter output size. - - -d directory - Create time conversion information files in the named directory - rather than in the standard directory named below. + Output backward-compatibility data as specified by bloat. If + bloat is fat, generate additional data entries that work around + potential bugs or incompatibilities in older software, such as + software that mishandles a TZif file's 64-bit data or proleptic + TZ string. If bloat is slim, keep the output files small; this + can help check for the bugs and incompatibilities. The default + is slim, as the fat workarounds are typically good only until + the year 2038 anyway. Also see the -r option for another way to + alter output size. + + -D Do not create ancestor directories of output files, For example, + for a zone named America/Los_Angeles the directory America + should already exist. By default, the directory and its + ancestors are created if they do not already exist. -d + directory Create time conversion information files in the named + directory rather than in the standard directory named below. -l timezone - Use timezone as local time. zic will act as if the input + Use timezone as local time. zic will act as if the input contained a link line of the form Link timezone localtime @@ -41,145 +44,165 @@ OPTIONS If timezone is -, any already-existing link is removed. -L leapsecondfilename - Read leap second information from the file with the given name. - If this option is not used, no leap second information appears + Read leap second information from the file with the given name. + If this option is not used, no leap second information appears in output files. -p timezone - Use timezone's rules when handling nonstandard TZ strings like - "EET-2EEST" that lack transition rules. zic will act as if the + Use timezone's rules when handling nonstandard TZ strings like + "EET-2EEST" that lack transition rules. zic will act as if the input contained a link line of the form Link timezone posixrules - If timezone is "-" (the default), any already-existing link is + If timezone is “-” (the default), any already-existing link is removed. - Unless timezone is "-", this option is obsolete and poorly - supported. Among other things it should not be used for - timestamps after the year 2037, and it should not be combined - with -b slim if timezone's transitions are at standard time or + Unless timezone is “-”, this option is obsolete and poorly + supported. Among other things it should not be used for + timestamps after the year 2037, and it should not be combined + with -b slim if timezone's transitions are at standard time or Universal Time (UT) instead of local time. + -m mode + Create TZif files with the given file mode bits. By default the + files are created with mode 644 as modified by the umask. With + this option they are created with the given mode instead. For + portability the mode should be an unsigned octal integer, + typically 644 or 444; some platforms also support chmod(1)-style + symbolic modes. This option does not affect created ancestor + directories, which have mode 755 as modified by the umask. The + option is ignored on platforms lacking the notion of file mode + bits. + -r [@lo][/@hi] - Limit the applicability of output files to timestamps in the + Limit the applicability of output files to timestamps in the range from lo (inclusive) to hi (exclusive), where lo and hi are - possibly signed decimal counts of seconds since the Epoch - (1970-01-01 00:00:00 UTC). Omitted counts default to extreme - values. The output files use UT offset 0 and abbreviation "-00" - in place of the omitted timestamp data. For example, "zic -r - @0" omits data intended for negative timestamps (i.e., before - the Epoch), and "zic -r @0/@2147483648" outputs data intended - only for nonnegative timestamps that fit into 31-bit signed - integers. On platforms with GNU date, "zic -r @$(date +%s)" - omits data intended for past timestamps. Although this option - typically reduces the output file's size, the size can increase - due to the need to represent the timestamp range boundaries, - particularly if hi causes a TZif file to contain explicit - entries for pre-hi transitions rather than concisely - representing them with a proleptic TZ string. Also see the -b + possibly signed decimal counts of seconds since the Epoch + (1970-01-01 00:00:00 UTC). Omitted counts default to extreme + values. The output files use UT offset 0 and abbreviation “-00” + in place of the omitted timestamp data. For example, “zic -r + @0” omits data intended for negative timestamps (i.e., before + the Epoch), and “zic -r @0/@2147483648” outputs data intended + only for nonnegative timestamps that fit into 31-bit signed + integers. On platforms with GNU date, “zic -r @$(date +%s)” + omits data intended for past timestamps. Although this option + typically reduces the output file's size, the size can increase + due to the need to represent the timestamp range boundaries, + particularly if hi causes a TZif file to contain explicit + entries for pre-hi transitions rather than concisely + representing them with a proleptic TZ string. Also see the -b slim option for another way to shrink output size. - -R @hi Generate redundant trailing explicit transitions for timestamps + -R @hi Generate redundant trailing explicit transitions for timestamps that occur less than hi seconds since the Epoch, even though the - transitions could be more concisely represented via the - proleptic TZ string. This option does not affect the - represented timestamps. Although it accommodates nonstandard - TZif readers that ignore the proleptic TZ string, it increases + transitions could be more concisely represented via the + proleptic TZ string. This option does not affect the + represented timestamps. Although it accommodates nonstandard + TZif readers that ignore the proleptic TZ string, it increases the size of the altered output files. -t file When creating local time information, put the configuration link in the named file rather than in the standard location. + -u owner[:group] + Change the output regular files' owner and group to those + specified. The owner is either a user name, or an unsigned + decimal integer user ID, or an empty string meaning no change to + the owner. The group is similar for group names and IDs. This + option does not affect directories or hard or symbolic links. + It typically needs special privileges to change ownership, and + is ignored on platforms that lack the notions of owners and + groups. + -v Be more verbose, and complain about the following situations: The input specifies a link to a link, something not supported by some older parsers, including zic itself through release 2022e. - A year that appears in a data file is outside the range of + A year that appears in a data file is outside the range of representable years. A time of 24:00 or more appears in the input. Pre-1998 versions - of zic prohibit 24:00, and pre-2007 versions prohibit times + of zic prohibit 24:00, and pre-2007 versions prohibit times greater than 24:00. - A rule goes past the start or end of the month. Pre-2004 + A rule goes past the start or end of the month. Pre-2004 versions of zic prohibit this. A time zone abbreviation uses a %z format. Pre-2015 versions of zic do not support this. - A timestamp contains fractional seconds. Pre-2018 versions of + A timestamp contains fractional seconds. Pre-2018 versions of zic do not support this. The input contains abbreviations that are mishandled by pre-2018 - versions of zic due to a longstanding coding bug. These - abbreviations include "L" for "Link", "mi" for "min", "Sa" for - "Sat", and "Su" for "Sun". - - The output file does not contain all the information about the - long-term future of a timezone, because the future cannot be - summarized as 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 + versions of zic due to a longstanding coding bug. These + abbreviations include “L” for “Link”, “mi” for “min”, “Sa” for + “Sat”, and “Su” for “Sun”. + + The output file does not contain all the information about the + long-term future of a timezone, because the future cannot be + summarized as a proleptic TZ string. For example, as of 2023 + this problem occurs for Morocco's daylight-saving rules, as + these rules are based on predictions for when Ramadan will be observed, something that a proleptic TZ string cannot represent. - The output contains data that may not be handled properly by - client code designed for older zic output formats. These + The output contains data that may not be handled properly by + client code designed for older zic output formats. These compatibility issues affect only timestamps before 1970 or after the start of 2038. - The output contains a truncated leap second table, which can - cause some older TZif readers to misbehave. This can occur if - the -L option is used, and either an Expires line is present or + The output contains a truncated leap second table, which can + cause some older TZif readers to misbehave. This can occur if + the -L option is used, and either an Expires line is present or the -r option is also used. - The output file contains more than 1200 transitions, which may - be mishandled by some clients. The current reference client - supports at most 2000 transitions; pre-2014 versions of the + The output file contains more than 1200 transitions, which may + be mishandled by some clients. The current reference client + supports at most 2000 transitions; pre-2014 versions of the reference client support at most 1200 transitions. - A time zone abbreviation has fewer than 3 or more than 6 - characters. POSIX requires at least 3, and requires + A time zone abbreviation has fewer than 3 or more than 6 + characters. POSIX requires at least 3, and requires implementations to support at least 6. An output file name contains a byte that is not an ASCII letter, - "-", "/", or "_"; or it contains a file name component that - contains more than 14 bytes or that starts with "-". + “-”, “/”, or “_”; or it contains a file name component that + contains more than 14 bytes or that starts with “-”. FILES - Input files use the format described in this section; output files use + Input files use the format described in this section; output files use tzfile(5) format. - Input files should be text files, that is, they should be a series of - zero or more lines, each ending in a newline byte and containing at - most 2048 bytes counting the newline, and without any NUL bytes. The - input text's encoding is typically UTF-8 or ASCII; it should have a - unibyte representation for the POSIX Portable Character Set (PPCS) - <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06 - .html> and the encoding's non-unibyte characters should consist - entirely of non-PPCS bytes. Non-PPCS characters typically occur only - in comments: although output file names and time zone abbreviations can - contain nearly any character, other software will work better if these - are limited to the restricted syntax described under the -v option. - - Input lines are made up of fields. Fields are separated from one - another by one or more white space characters. The white space - characters are space, form feed, carriage return, newline, tab, and - vertical tab. Leading and trailing white space on input lines is - ignored. An unquoted sharp character (#) in the input introduces a - comment which extends to the end of the line the sharp character - appears on. White space characters and sharp characters may be + Input files should be text files, that is, they should be a series of + zero or more lines, each ending in a newline byte and containing at + most 2048 bytes counting the newline, and without any NUL bytes. The + input text's encoding is typically UTF-8 or ASCII; it should have a + unibyte representation for the POSIX Portable Character Set (PPCS) and + the encoding's non-unibyte characters should consist entirely of non- + PPCS bytes. Non-PPCS characters typically occur only in comments: + although output file names and time zone abbreviations can contain + nearly any character, other software will work better if these are + limited to the restricted syntax described under the -v option. + + Input lines are made up of fields. Fields are separated from one + another by one or more white space characters. The white space + characters are space, form feed, carriage return, newline, tab, and + vertical tab. Leading and trailing white space on input lines is + ignored. An unquoted sharp character (#) in the input introduces a + comment which extends to the end of the line the sharp character + appears on. White space characters and sharp characters may be enclosed in double quotes (") if they're to be used as part of a field. - Any line that is blank (after comment stripping) is ignored. Nonblank + Any line that is blank (after comment stripping) is ignored. Nonblank lines are expected to be of one of three types: rule lines, zone lines, and link lines. - Names must be in English and are case insensitive. They appear in + Names must be in English and are case insensitive. They appear in several contexts, and include month and weekday names and keywords such - as maximum, only, Rolling, and Zone. A name can be abbreviated by - omitting all but an initial prefix; any abbreviation must be + as maximum, only, Rolling, and Zone. A name can be abbreviated by + omitting all but an initial prefix; any abbreviation must be unambiguous in context. A rule line has the form @@ -192,36 +215,36 @@ FILES The fields that make up a rule line are: - NAME Gives the name of the rule set that contains this line. The - name must start with a character that is neither an ASCII digit - nor "-" nor "+". To allow for future extensions, an unquoted - name should not contain characters from the set - "!$%&'()*,/:;<=>?@[\]^`{|}~". - - FROM Gives the first year in which the rule applies. Any signed - integer year can be supplied; the proleptic Gregorian calendar - is assumed, with year 0 preceding year 1. Rules can describe - times that are not representable as time values, with the - unrepresentable times ignored; this allows rules to be portable + NAME Gives the name of the rule set that contains this line. The + name must start with a character that is neither an ASCII digit + nor “-” nor “+”. To allow for future extensions, an unquoted + name should not contain characters from the set + “!$%&'()*,/:;<=>?@[\]^`{|}~”. + + FROM Gives the first year in which the rule applies. Any signed + integer year can be supplied; the proleptic Gregorian calendar + is assumed, with year 0 preceding year 1. Rules can describe + times that are not representable as time values, with the + unrepresentable times ignored; this allows rules to be portable among hosts with differing time value types. - TO Gives the final year in which the rule applies. The word - maximum (or an abbreviation) means the indefinite future, and - the word only (or an abbreviation) may be used to repeat the + TO Gives the final year in which the rule applies. The word + maximum (or an abbreviation) means the indefinite future, and + the word only (or an abbreviation) may be used to repeat the value of the FROM field. - - Is a reserved field and should always contain "-" for - compatibility with older versions of zic. It was previously - known as the TYPE field, which could contain values to allow a - separate script to further restrict in which "types" of years + - Is a reserved field and should always contain “-” for + compatibility with older versions of zic. It was previously + known as the TYPE field, which could contain values to allow a + separate script to further restrict in which “types” of years the rule would apply. IN Names the month in which the rule takes effect. Month names may be abbreviated as mentioned previously; for example, January can - appear as "January", "JANU" or "Ja", but not as "j" which would + appear as “January”, “JANU” or “Ja”, but not as “j” which would be ambiguous with both June and July. - ON Gives the day on which the rule takes effect. Recognized forms + ON Gives the day on which the rule takes effect. Recognized forms include: 5 the fifth of the month @@ -230,17 +253,17 @@ FILES Sun>=8 first Sunday on or after the eighth Sun<=25 last Sunday on or before the 25th - A weekday name (e.g., Sunday) or a weekday name preceded by - "last" (e.g., lastSunday) may be abbreviated as mentioned - previously, e.g., "Su" for Sunday and "lastsa" for the last + A weekday name (e.g., Sunday) or a weekday name preceded by + “last” (e.g., lastSunday) may be abbreviated as mentioned + previously, e.g., “Su” for Sunday and “lastsa” for the last Saturday. There must be no white space characters within the ON - field. The "<=" and ">=" constructs can result in a day in the - neighboring month; for example, the IN-ON combination "Oct - Sun>=31" stands for the first Sunday on or after October 31, + field. The “<=” and “>=” constructs can result in a day in the + neighboring month; for example, the IN-ON combination “Oct + Sun>=31” stands for the first Sunday on or after October 31, even if that Sunday occurs in November. - AT Gives the time of day at which the rule takes effect, relative - to 00:00, the start of a calendar day. Recognized forms + AT Gives the time of day at which the rule takes effect, relative + to 00:00, the start of a calendar day. Recognized forms include: 2 time in hours @@ -254,39 +277,39 @@ FILES -2:30 2.5 hours before 00:00 - equivalent to 0 - Although zic rounds times to the nearest integer second + Although zic rounds times to the nearest integer second (breaking ties to the even integer), the fractions may be useful - to other applications requiring greater precision. The source - format does not specify any maximum precision. Any of these + to other applications requiring greater precision. The source + format does not specify any maximum precision. Any of these forms may be followed by the letter w if the given time is local - or "wall clock" time, s if the given time is standard time - without any adjustment for daylight saving, or u (or g or z) if - the given time is universal time; in the absence of an - indicator, local (wall clock) time is assumed. These forms - ignore leap seconds; for example, if a leap second occurs at - 00:59:60 local time, "1:00" stands for 3601 seconds after local - midnight instead of the usual 3600 seconds. The intent is that - a rule line describes the instants when a clock/calendar set to - the type of time specified in the AT field would show the + or “wall clock” time, s if the given time is standard time + without any adjustment for daylight saving, or u (or g or z) if + the given time is universal time; in the absence of an + indicator, local (wall clock) time is assumed. These forms + ignore leap seconds; for example, if a leap second occurs at + 00:59:60 local time, “1:00” stands for 3601 seconds after local + midnight instead of the usual 3600 seconds. The intent is that + a rule line describes the instants when a clock/calendar set to + the type of time specified in the AT field would show the specified date and time of day. SAVE Gives the amount of time to be added to local standard time when - the rule is in effect, and whether the resulting time is - standard or daylight saving. This field has the same format as - the AT field except with a different set of suffix letters: s - for standard time and d for daylight saving time. The suffix - letter is typically omitted, and defaults to s if the offset is - zero and to d otherwise. Negative offsets are allowed; in + the rule is in effect, and whether the resulting time is + standard or daylight saving. This field has the same format as + the AT field except with a different set of suffix letters: s + for standard time and d for daylight saving time. The suffix + letter is typically omitted, and defaults to s if the offset is + zero and to d otherwise. Negative offsets are allowed; in Ireland, for example, daylight saving time is observed in winter - and has a negative offset relative to Irish Standard Time. The - offset is merely added to standard time; for example, zic does - not distinguish a 10:30 standard time plus an 0:30 SAVE from a + and has a negative offset relative to Irish Standard Time. The + offset is merely added to standard time; for example, zic does + not distinguish a 10:30 standard time plus an 0:30 SAVE from a 10:00 standard time plus a 1:00 SAVE. LETTER/S - Gives the "variable part" (for example, the "S" or "D" in "EST" - or "EDT") of time zone abbreviations to be used when this rule - is in effect. If this field is "-", the variable part is null. + Gives the “variable part” (for example, the “S” or “D” in “EST” + or “EDT”) of time zone abbreviations to be used when this rule + is in effect. If this field is “-”, the variable part is null. A zone line has the form @@ -299,75 +322,75 @@ FILES The fields that make up a zone line are: NAME The name of the timezone. This is the name used in creating the - time conversion information file for the timezone. It should - not contain a file name component "." or ".."; a file name - component is a maximal substring that does not contain "/". - - STDOFF The amount of time to add to UT to get standard time, without - any adjustment for daylight saving. This field has the same - format as the AT and SAVE fields of rule lines, except without - suffix letters; begin the field with a minus sign if time must + time conversion information file for the timezone. It should + not contain a file name component “.” or “..”; a file name + component is a maximal substring that does not contain “/”. + + STDOFF The amount of time to add to UT to get standard time, without + any adjustment for daylight saving. This field has the same + format as the AT and SAVE fields of rule lines, except without + suffix letters; begin the field with a minus sign if time must be subtracted from UT. - RULES The name of the rules that apply in the timezone or, - alternatively, a field in the same format as a rule-line SAVE - field, giving the amount of time to be added to local standard - time and whether the resulting time is standard or daylight - saving. Standard time applies if this field is - or for - timestamps occurring before any rule takes effect. When an - amount of time is given, only the sum of standard time and this + RULES The name of the rules that apply in the timezone or, + alternatively, a field in the same format as a rule-line SAVE + field, giving the amount of time to be added to local standard + time and whether the resulting time is standard or daylight + saving. Standard time applies if this field is - or for + timestamps occurring before any rule takes effect. When an + amount of time is given, only the sum of standard time and this amount matters. - FORMAT The format for time zone abbreviations. The pair of characters - %s shows where to put the time zone abbreviation's variable - part, which is taken from the LETTER/S field of the - corresponding rule; any timestamps that precede the earliest - rule use the LETTER/S of the earliest standard-time rule (which - in this case must exist). Alternatively, a format can use the - pair of characters %z to stand for the UT offset in the form - +-hh, +-hhmm, or +-hhmmss, using the shortest form that does not - lose information, where hh, mm, and ss are the hours, minutes, - and seconds east (+) or west (-) of UT. Alternatively, a slash - (/) separates standard and daylight abbreviations. To conform - to POSIX, a time zone abbreviation should contain only - alphanumeric ASCII characters, "+" and "-". By convention, the - time zone abbreviation "-00" is a placeholder that means local + FORMAT The format for time zone abbreviations. The pair of characters + %s shows where to put the time zone abbreviation's variable + part, which is taken from the LETTER/S field of the + corresponding rule; any timestamps that precede the earliest + rule use the LETTER/S of the earliest standard-time rule (which + in this case must exist). Alternatively, a format can use the + pair of characters %z to stand for the UT offset in the form + ±hh, ±hhmm, or ±hhmmss, using the shortest form that does not + lose information, where hh, mm, and ss are the hours, minutes, + and seconds east (+) or west (-) of UT. Alternatively, a slash + (/) separates standard and daylight abbreviations. To conform + to POSIX, a time zone abbreviation should contain only + alphanumeric ASCII characters, “+” and “-”. By convention, the + time zone abbreviation “-00” is a placeholder that means local time is unspecified. - UNTIL The time at which the UT offset or the rule(s) change for a - location. It takes the form of one to four fields YEAR [MONTH - [DAY [TIME]]]. If this is specified, the time zone information - is generated from the given UT offset and rule change until the - time specified, which is interpreted using the rules in effect - just before the transition. The month, day, and time of day - have the same format as the IN, ON, and AT fields of a rule; - trailing fields can be omitted, and default to the earliest + UNTIL The time at which the UT offset or the rule(s) change for a + location. It takes the form of one to four fields YEAR [MONTH + [DAY [TIME]]]. If this is specified, the time zone information + is generated from the given UT offset and rule change until the + time specified, which is interpreted using the rules in effect + just before the transition. The month, day, and time of day + have the same format as the IN, ON, and AT fields of a rule; + trailing fields can be omitted, and default to the earliest possible value for the missing fields. - The next line must be a "continuation" line; this has the same - form as a zone line except that the string "Zone" and the name - are omitted, as the continuation line will place information - starting at the time specified as the "until" information in the - previous line in the file used by the previous line. - Continuation lines may contain "until" information, just as zone - lines do, indicating that the next line is a further + The next line must be a “continuation” line; this has the same + form as a zone line except that the string “Zone” and the name + are omitted, as the continuation line will place information + starting at the time specified as the “until” information in the + previous line in the file used by the previous line. + Continuation lines may contain “until” information, just as zone + lines do, indicating that the next line is a further continuation. - If a zone changes at the same instant that a rule would otherwise take - effect in the earlier zone or continuation line, the rule is ignored. - A zone or continuation line L with a named rule set starts with - standard time by default: that is, any of L's timestamps preceding L's - earliest rule use the rule in effect after L's first transition into - standard time. In a single zone it is an error if two rules take - effect at the same instant, or if two zone changes take effect at the + If a zone changes at the same instant that a rule would otherwise take + effect in the earlier zone or continuation line, the rule is ignored. + A zone or continuation line L with a named rule set starts with + standard time by default: that is, any of L's timestamps preceding L's + earliest rule use the rule in effect after L's first transition into + standard time. In a single zone it is an error if two rules take + effect at the same instant, or if two zone changes take effect at the same instant. - If a continuation line subtracts N seconds from the UT offset after a - transition that would be interpreted to be later if using the - continuation line's UT offset and rules, the "until" time of the - previous zone or continuation line is interpreted according to the - continuation line's UT offset and rules, and any rule that would - otherwise take effect in the next N seconds is instead assumed to take + If a continuation line subtracts N seconds from the UT offset after a + transition that would be interpreted to be later if using the + continuation line's UT offset and rules, the “until” time of the + previous zone or continuation line is interpreted according to the + continuation line's UT offset and rules, and any rule that would + otherwise take effect in the next N seconds is instead assumed to take effect simultaneously. For example: # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -377,11 +400,12 @@ FILES Zone America/Menominee -5:00 - EST 1973 Apr 29 2:00 -6:00 US C%sT - Here, an incorrect reading would be there were two clock changes on - 1973-04-29, the first from 02:00 EST (-05) to 01:00 CST (-06), and the - second an hour later from 02:00 CST (-06) to 03:00 CDT (-05). However, - zic interprets this more sensibly as a single transition from 02:00 CST - (-05) to 02:00 CDT (-05). + 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) according + to the “until” value in the zone line, and the second an hour later + from 02:00 CST (-06) to 03:00 CDT (-05) according to the values in the + April rule line. However, zic interprets this more sensibly as a + single transition from 02:00 EST (-05) to 02:00 CDT (-05). A link line has the form @@ -391,26 +415,26 @@ FILES Link Europe/Istanbul Asia/Istanbul - The TARGET field should appear as the NAME field in some zone line or - as the LINK-NAME field in some link line. The LINK-NAME field is used - as an alternative name for that zone; it has the same syntax as a zone - line's NAME field. Links can chain together, although the behavior is - unspecified if a chain of one or more links does not terminate in a - Zone name. A link line can appear before the line that defines the + The TARGET field should appear as the NAME field in some zone line or + as the LINK-NAME field in some link line. The LINK-NAME field is used + as an alternative name for that zone; it has the same syntax as a zone + line's NAME field. Links can chain together, although the behavior is + unspecified if a chain of one or more links does not terminate in a + Zone name. A link line can appear before the line that defines the link target. For example: Link Greenwich G_M_T Link Etc/GMT Greenwich Zone Etc/GMT 0 - GMT - The two links are chained together, and G_M_T, Greenwich, and Etc/GMT + The two links are chained together, and G_M_T, Greenwich, and Etc/GMT all name the same zone. - Except for continuation lines, lines may appear in any order in the - input. However, the behavior is unspecified if multiple zone or link + Except for continuation lines, lines may appear in any order in the + input. However, the behavior is unspecified if multiple zone or link lines define the same name. - The file that describes leap seconds can have leap lines and an + The file that describes leap seconds can have leap lines and an expiration line. Leap lines have the following form: Leap YEAR MONTH DAY HH:MM:SS CORR R/S @@ -419,21 +443,21 @@ FILES Leap 2016 Dec 31 23:59:60 + S - The YEAR, MONTH, DAY, and HH:MM:SS fields tell when the leap second - happened. The CORR field should be "+" if a second was added or "-" if - a second was skipped. The R/S field should be (an abbreviation of) - "Stationary" if the leap second time given by the other fields should - be interpreted as UTC or (an abbreviation of) "Rolling" if the leap - second time given by the other fields should be interpreted as local + The YEAR, MONTH, DAY, and HH:MM:SS fields tell when the leap second + happened. The CORR field should be “+” if a second was added or “-” if + a second was skipped. The R/S field should be (an abbreviation of) + “Stationary” if the leap second time given by the other fields should + be interpreted as UTC or (an abbreviation of) “Rolling” if the leap + second time given by the other fields should be interpreted as local (wall clock) time. - Rolling leap seconds would let one see Times Square ball drops where - there'd be a "3... 2... 1... leap... Happy New Year" countdown, placing - the leap second at midnight New York time rather than midnight UTC. - Although stationary leap seconds are the common practice, rolling leap - seconds can be useful in specialized applications like SMPTE timecodes - that may prefer to put leap second discontinuities at the end of a - local broadcast day. However, rolling leap seconds are not supported + Rolling leap seconds would let one see Times Square ball drops where + there'd be a “3... 2... 1... leap... Happy New Year” countdown, placing + the leap second at midnight New York time rather than midnight UTC. + Although stationary leap seconds are the common practice, rolling leap + seconds can be useful in specialized applications like SMPTE timecodes + that may prefer to put leap second discontinuities at the end of a + local broadcast day. However, rolling leap seconds are not supported if the -r option is used. The expiration line, if present, has the form: @@ -448,7 +472,7 @@ FILES in UTC for the leap second table. EXTENDED EXAMPLE - Here is an extended example of zic input, intended to illustrate many + Here is an extended example of zic input, intended to illustrate many of its features. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -469,29 +493,29 @@ EXTENDED EXAMPLE Link Europe/Zurich Europe/Vaduz - In this example, the EU rules are for the European Union and for its - predecessor organization, the European Communities. The timezone is - named Europe/Zurich and it has the alias Europe/Vaduz. This example - says that Zurich was 34 minutes and 8 seconds east of UT until - 1853-07-16 at 00:00, when the legal offset was changed to 7 degrees 26 - minutes 22.50 seconds, which works out to 0:29:45.50; zic treats this - by rounding it to 0:29:46. After 1894-06-01 at 00:00 the UT offset - became one hour and Swiss daylight saving rules (defined with lines - beginning with "Rule Swiss") apply. From 1981 to the present, EU - daylight saving rules have applied, and the UTC offset has remained at + In this example, the EU rules are for the European Union and for its + predecessor organization, the European Communities. The timezone is + named Europe/Zurich and it has the alias Europe/Vaduz. This example + says that Zurich was 34 minutes and 8 seconds east of UT until + 1853-07-16 at 00:00, when the legal offset was changed to 7 degrees 26 + minutes 22.50 seconds, which works out to 0:29:45.50; zic treats this + by rounding it to 0:29:46. After 1894-06-01 at 00:00 the UT offset + became one hour and Swiss daylight saving rules (defined with lines + beginning with “Rule Swiss”) apply. From 1981 to the present, EU + daylight saving rules have applied, and the UTC offset has remained at one hour. In 1941 and 1942, daylight saving time applied from the first Monday in - May at 01:00 to the first Monday in October at 02:00. The pre-1981 EU - daylight-saving rules have no effect here, but are included for + May at 01:00 to the first Monday in October at 02:00. The pre-1981 EU + daylight-saving rules have no effect here, but are included for completeness. Since 1981, daylight saving has begun on the last Sunday - in March at 01:00 UTC. Until 1995 it ended the last Sunday in - September at 01:00 UTC, but this changed to the last Sunday in October + in March at 01:00 UTC. Until 1995 it ended the last Sunday in + September at 01:00 UTC, but this changed to the last Sunday in October starting in 1996. - For purposes of display, "LMT" and "BMT" were initially used, - respectively. Since Swiss rules and later EU rules were applied, the - time zone abbreviation has been CET for standard time and CEST for + For purposes of display, “LMT” and “BMT” were initially used, + respectively. Since Swiss rules and later EU rules were applied, the + time zone abbreviation has been CET for standard time and CEST for daylight saving time. FILES @@ -502,15 +526,15 @@ FILES Default timezone information directory. NOTES - For areas with more than two types of local time, you may need to use - local standard time in the AT field of the earliest transition time's - rule to ensure that the earliest transition time recorded in the + For areas with more than two types of local time, you may need to use + local standard time in the AT field of the earliest transition time's + rule to ensure that the earliest transition time recorded in the compiled file is correct. - If, for a particular timezone, a clock advance caused by the start of - daylight saving coincides with and is equal to a clock retreat caused - by a change in UT offset, zic produces a single transition to daylight - saving at the new UT offset without any change in local (wall clock) + If, for a particular timezone, a clock advance caused by the start of + daylight saving coincides with and is equal to a clock retreat caused + by a change in UT offset, zic produces a single transition to daylight + saving at the new UT offset without any change in local (wall clock) time. To get separate transitions use multiple zone continuation lines specifying transition instants using universal time. @@ -18,6 +18,10 @@ #include "tzfile.h" #include <fcntl.h> +#ifndef O_BINARY +# define O_BINARY 0 /* MS-Windows */ +#endif + #include <locale.h> #include <signal.h> #include <stdarg.h> @@ -44,8 +48,8 @@ enum { FORMAT_LEN_GROWTH_BOUND = 5 }; #ifdef HAVE_DIRECT_H # include <direct.h> # include <io.h> -# undef mkdir # define mkdir(name, mode) _mkdir(name) +typedef unsigned short gid_t, mode_t, uid_t; #endif #ifndef HAVE_GETRANDOM @@ -61,13 +65,94 @@ enum { FORMAT_LEN_GROWTH_BOUND = 5 }; # include <sys/random.h> #endif + #if HAVE_SYS_STAT_H # include <sys/stat.h> #endif -#ifdef S_IRUSR -# define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) + +#ifndef S_IRWXU +# define S_IRUSR 0400 +# define S_IWUSR 0200 +# define S_IXUSR 0100 +# define S_IRGRP 0040 +# define S_IWGRP 0020 +# define S_IXGRP 0010 +# define S_IROTH 0004 +# define S_IWOTH 0002 +# define S_IXOTH 0001 +# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif + +/* All file permission bits. */ +#define ALL_PERMS (S_IRWXU | S_IRWXG | S_IRWXO) + +/* Troublesome file permission bits. */ +#define TROUBLE_PERMS (S_IWGRP | S_IWOTH) + +/* File permission bits for making directories. + The umask modifies these bits. */ +#define MKDIR_PERMS (ALL_PERMS & ~TROUBLE_PERMS) + +/* File permission bits for making regular files. + The umask modifies these bits. */ +#define CREAT_PERMS (MKDIR_PERMS & ~(S_IXUSR | S_IXGRP | S_IXOTH)) +static mode_t creat_perms = CREAT_PERMS; + +#ifndef HAVE_PWD_H +# ifdef __has_include +# if __has_include(<pwd.h>) && __has_include(<grp.h>) +# define HAVE_PWD_H 1 +# else +# define HAVE_PWD_H 0 +# endif +# endif +#endif +#ifndef HAVE_PWD_H +# define HAVE_PWD_H 1 +#endif +#if HAVE_PWD_H +# include <grp.h> +# include <pwd.h> #else -# define MKDIR_UMASK 0755 +struct group { gid_t gr_gid; }; +struct passwd { uid_t pw_uid; }; +# define getgrnam(arg) NULL +# define getpwnam(arg) NULL +# define fchown(fd, owner, group) ((fd) < 0 ? -1 : 0) +#endif +static gid_t const no_gid = -1; +static uid_t const no_uid = -1; +static gid_t output_group = -1; +static uid_t output_owner = -1; +#ifndef GID_T_MAX +# define GID_T_MAX_NO_PADDING MAXVAL(gid_t, TYPE_BIT(gid_t)) +# if HAVE__GENERIC +# define GID_T_MAX \ + (TYPE_SIGNED(gid_t) \ + ? _Generic((gid_t) 0, \ + signed char: SCHAR_MAX, short: SHRT_MAX, \ + int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \ + default: GID_T_MAX_NO_PADDING) \ + : (gid_t) -1) +# else +# define GID_T_MAX GID_T_MAX_NO_PADDING +# endif +#endif +#ifndef UID_T_MAX +# define UID_T_MAX_NO_PADDING MAXVAL(uid_t, TYPE_BIT(uid_t)) +# if HAVE__GENERIC +# define UID_T_MAX \ + (TYPE_SIGNED(uid_t) \ + ? _Generic((uid_t) 0, \ + signed char: SCHAR_MAX, short: SHRT_MAX, \ + int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \ + default: UID_T_MAX_NO_PADDING) \ + : (uid_t) -1) +# else +# define UID_T_MAX UID_T_MAX_NO_PADDING +# endif #endif /* The minimum alignment of a type, for pre-C23 platforms. @@ -144,14 +229,6 @@ struct zone { zic_t z_untiltime; }; -#if !HAVE_POSIX_DECLS -extern int getopt(int argc, char * const argv[], - const char * options); -extern int link(const char * target, const char * linkname); -extern char * optarg; -extern int optind; -#endif - #if ! HAVE_SYMLINK static ssize_t readlink(char const *restrict file, char *restrict buf, size_t size) @@ -167,8 +244,8 @@ symlink(char const *target, char const *linkname) } #endif #ifndef AT_SYMLINK_FOLLOW -# define linkat(targetdir, target, linknamedir, linkname, flag) \ - (errno = ENOTSUP, -1) +# define linkat(targetdir, target, linknamedir, linkname, flag) \ + (errno = ENOTSUP, -1) #endif static void addtt(zic_t starttime, int type); @@ -202,6 +279,13 @@ static bool rulesub(struct rule * rp, const char * dayp, const char * timep); static zic_t tadd(zic_t t1, zic_t t2); +/* Is C an ASCII digit? */ +static bool +is_digit(char c) +{ + return '0' <= c && c <= '9'; +} + /* Bound on length of what %z can expand to. */ enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 }; @@ -219,6 +303,7 @@ static int max_format_len; static zic_t max_year; static zic_t min_year; static bool noise; +static bool skip_mkdir; static int rfilenum; static lineno rlinenum; static const char * progname; @@ -643,14 +728,96 @@ warning(const char *const string, ...) warnings = true; } -/* Close STREAM. If it had an I/O error, report it against DIR/NAME, - remove TEMPNAME if nonnull, and then exit. */ +/* Convert ARG, a string in base BASE, to an unsigned long value no + greater than MAXVAL. On failure, diagnose with MSGID and exit. */ +static unsigned long +arg2num(char const *arg, int base, unsigned long maxval, char const *msgid) +{ + unsigned long n; + char *ep; + errno = 0; + n = strtoul(arg, &ep, base); + if (ep == arg || *ep || maxval < n || errno) { + fprintf(stderr, _(msgid), progname, arg); + exit(EXIT_FAILURE); + } + return n; +} + +#ifndef MODE_T_MAX +# define MODE_T_MAX_NO_PADDING MAXVAL(mode_t, TYPE_BIT(mode_t)) +# if HAVE__GENERIC +# define MODE_T_MAX \ + (TYPE_SIGNED(mode_t) \ + ? _Generic((mode_t) 0, \ + signed char: SCHAR_MAX, short: SHRT_MAX, \ + int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \ + default: MODE_T_MAX_NO_PADDING) \ + : (mode_t) -1) +# else +# define MODE_T_MAX MODE_T_MAX_NO_PADDING +# endif +#endif + +#ifndef HAVE_FCHMOD +# define HAVE_FCHMOD 1 +#endif +#if !HAVE_FCHMOD +# define fchmod(fd, mode) 0 +#endif + +#ifndef HAVE_SETMODE +# if (defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ + || (defined __APPLE__ && defined __MACH__)) +# define HAVE_SETMODE 1 +# else +# define HAVE_SETMODE 0 +# endif +#endif + +static mode_t const no_mode = -1; +static mode_t output_mode = -1; + +static mode_t +mode_option(char const *arg) +{ +#if HAVE_SETMODE + void *set = setmode(arg); + if (set) { + mode_t mode = getmode(set, CREAT_PERMS); + free(set); + return mode; + } +#endif + return arg2num(arg, 8, min(MODE_T_MAX, ULONG_MAX), + N_("%s: -m '%s': invalid mode\n")); +} + +static int +chmetadata(FILE *stream) +{ + if (output_owner != no_uid || output_group != no_gid) { + int r = fchown(fileno(stream), output_owner, output_group); + if (r < 0) + return r; + } + return output_mode == no_mode ? 0 : fchmod(fileno(stream), output_mode); +} + +/* Close STREAM. + If it had an I/O error, report it against DIR/NAME, + remove TEMPNAME if nonnull, and then exit. + If TEMPNAME is nonnull, and if requested, + change the stream's metadata before closing. */ static void close_file(FILE *stream, char const *dir, char const *name, char const *tempname) { char const *e = (ferror(stream) ? _("I/O error") - : fclose(stream) != 0 ? strerror(errno) : NULL); + : (fflush(stream) < 0 + || (tempname && chmetadata(stream) < 0) + || fclose(stream) < 0) + ? strerror(errno) : NULL); if (e) { if (name && *name == '/') dir = NULL; @@ -665,14 +832,21 @@ close_file(FILE *stream, char const *dir, char const *name, } ATTRIBUTE_NORETURN static void +duplicate_options(char const *opt) +{ + fprintf(stderr, _("%s: More than one %s option specified\n"), progname, opt); + exit(EXIT_FAILURE); +} + +ATTRIBUTE_NORETURN static void usage(FILE *stream, int status) { fprintf(stream, _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n" - "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]" - " [ -L leapseconds ] \\\n" - "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R '@hi' ] \\\n" - "\t[ -t localtime-link ] \\\n" + "\t[ -b {slim|fat} ] [ -d directory ] [ -D ] \\\n" + "\t[ -l localtime ] [ -L leapseconds ] [ -m mode ] \\\n" + "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R @hi ] \\\n" + "\t[ -t localtime-link ] [ -u 'owner[:group]' ] \\\n" "\t[ filename ... ]\n\n" "Report bugs to %s.\n"), progname, progname, REPORT_BUGS_TO); @@ -681,6 +855,71 @@ usage(FILE *stream, int status) exit(status); } +static void +group_option(char const *arg) +{ + if (*arg) { + if (output_group != no_gid) { + fprintf(stderr, _("multiple groups specified")); + exit(EXIT_FAILURE); + } else { + struct group *gr = getgrnam(arg); + output_group = (gr ? gr->gr_gid + : arg2num(arg, 10, min(GID_T_MAX, ULONG_MAX), + N_("%s: invalid group: %s\n"))); + } + } +} + +static void +owner_option(char const *arg) +{ + if (*arg) { + if (output_owner != no_uid) { + fprintf(stderr, _("multiple owners specified")); + exit(EXIT_FAILURE); + } else { + struct passwd *pw = getpwnam(arg); + output_owner = (pw ? pw->pw_uid + : arg2num(arg, 10, min(UID_T_MAX, ULONG_MAX), + N_("%s: invalid owner: %s\n"))); + } + } +} + +/* If setting owner or group, use temp file permissions that avoid + security races before the fchmod at the end. */ +static void +use_safe_temp_permissions(void) +{ + if (output_owner != no_uid || output_group != no_gid) { + + /* The mode when done with the file. */ + mode_t omode; + if (output_mode == no_mode) { + mode_t cmask = umask(0); + umask(cmask); + omode = CREAT_PERMS & ~cmask; + } else + omode = output_mode; + + /* The mode passed to open+O_CREAT. Do not bother with executable + permissions, as they should not be used and this mode is merely + a nicety (even a mode of 0 still work). */ + creat_perms = ((((omode & (S_IRUSR | S_IRGRP | S_IROTH)) + == (S_IRUSR | S_IRGRP | S_IROTH)) + ? S_IRUSR | S_IRGRP | S_IROTH : 0) + | (((omode & (S_IWUSR | S_IWGRP | S_IWOTH)) + == (S_IWUSR | S_IWGRP | S_IWOTH)) + ? S_IWUSR | S_IWGRP | S_IWOTH : 0)); + + /* If creat_perms is not the final mode, arrange to run + fchmod later, even if -m was not used. */ + if (creat_perms != omode) + output_mode = omode; + } +} + /* Change the working directory to DIR, possibly creating DIR and its ancestors. After this is done, all files are accessed with names relative to DIR. */ @@ -980,9 +1219,6 @@ main(int argc, char **argv) register ptrdiff_t i, j; bool timerange_given = false; -#ifdef S_IWGRP - umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); -#endif #if HAVE_GETTEXT setlocale(LC_ALL, ""); # ifdef TZ_DOMAINDIR @@ -1005,8 +1241,7 @@ main(int argc, char **argv) } else if (strcmp(argv[k], "--help") == 0) { usage(stdout, EXIT_SUCCESS); } - while ((c = getopt(argc, argv, "b:d:l:L:p:r:R:st:vy:")) != EOF - && c != -1) + while ((c = getopt(argc, argv, "b:d:Dg:l:L:m:p:r:R:st:u:vy:")) != -1) switch (c) { default: usage(stderr, EXIT_FAILURE); @@ -1023,73 +1258,62 @@ main(int argc, char **argv) error(_("invalid option: -b '%s'"), optarg); break; case 'd': - if (directory == NULL) - directory = optarg; - else { - fprintf(stderr, - _("%s: More than one -d option" - " specified\n"), - progname); - return EXIT_FAILURE; - } + if (directory) + duplicate_options("-d"); + directory = optarg; + break; + case 'D': + skip_mkdir = true; + break; + case 'g': + /* This undocumented option is present for + compatibility with FreeBSD 14. */ + group_option(optarg); break; case 'l': - if (lcltime == NULL) - lcltime = optarg; - else { - fprintf(stderr, - _("%s: More than one -l option" - " specified\n"), - progname); - return EXIT_FAILURE; - } + if (lcltime) + duplicate_options("-l"); + lcltime = optarg; + break; + case 'm': + if (output_mode != no_mode) + duplicate_options("-m"); + output_mode = mode_option(optarg); break; case 'p': - if (psxrules == NULL) - psxrules = optarg; - else { - fprintf(stderr, - _("%s: More than one -p option" - " specified\n"), - progname); - return EXIT_FAILURE; - } + if (psxrules) + duplicate_options("-p"); + psxrules = optarg; break; case 't': - if (tzdefault != NULL) { - fprintf(stderr, - _("%s: More than one -t option" - " specified\n"), - progname); - return EXIT_FAILURE; - } + if (tzdefault) + duplicate_options("-t"); tzdefault = optarg; break; + case 'u': + { + char *colon = strchr(optarg, ':'); + if (colon) + *colon = '\0'; + owner_option(optarg); + if (colon) + group_option(colon + 1); + } + break; case 'y': warning(_("-y ignored")); break; case 'L': - if (leapsec == NULL) - leapsec = optarg; - else { - fprintf(stderr, - _("%s: More than one -L option" - " specified\n"), - progname); - return EXIT_FAILURE; - } + if (leapsec) + duplicate_options("-L"); + leapsec = optarg; break; case 'v': noise = true; break; case 'r': - if (timerange_given) { - fprintf(stderr, - _("%s: More than one -r option" - " specified\n"), - progname); - return EXIT_FAILURE; - } + if (timerange_given) + duplicate_options("-r"); if (! timerange_option(optarg)) { fprintf(stderr, _("%s: invalid time range: %s\n"), @@ -1141,6 +1365,7 @@ main(int argc, char **argv) if (errors) return EXIT_FAILURE; associate(); + use_safe_temp_permissions(); change_directory(directory); directory_ends_in_slash = directory[strlen(directory) - 1] == '/'; catch_signals(); @@ -1327,10 +1552,10 @@ random_dirent(char const **name, char **namealloc) uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6); if (!dst) { - dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); - memcpy(dst, src, dirlen); - memcpy(dst + dirlen, prefix, prefixlen); - dst[dirlen + prefixlen + suffixlen] = '\0'; + char *cp = dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); + cp = mempcpy(cp, src, dirlen); + cp = mempcpy(cp, prefix, prefixlen); + cp[suffixlen] = '\0'; *name = *namealloc = dst; } @@ -1367,33 +1592,35 @@ diagslash(char const *filename) static FILE * open_outfile(char const **outname, char **tempname) { -#if __STDC_VERSION__ < 201112 - static char const fopen_mode[] = "wb"; -#else - static char const fopen_mode[] = "wbx"; -#endif - - FILE *fp; bool dirs_made = false; if (!*tempname) random_dirent(outname, tempname); - while (! (fp = fopen(*outname, fopen_mode))) { - int fopen_errno = errno; - if (fopen_errno == ENOENT && !dirs_made) { + while (true) { + int oflags = O_WRONLY | O_BINARY | O_CREAT | O_EXCL; + int fd = open(*outname, oflags, creat_perms); + int err; + if (fd < 0) + err = errno; + else { + FILE *fp = fdopen(fd, "wb"); + if (fp) + return fp; + err = errno; + close(fd); + } + if (err == ENOENT && !dirs_made) { mkdirs(*outname, true); dirs_made = true; - } else if (fopen_errno == EEXIST) + } else if (err == EEXIST) random_dirent(outname, tempname); else { fprintf(stderr, _("%s: Can't create %s%s%s: %s\n"), progname, diagdir(*outname), diagslash(*outname), *outname, - strerror(fopen_errno)); + strerror(err)); exit(EXIT_FAILURE); } } - - return fp; } /* If TEMPNAME, the result is in the temporary file TEMPNAME even @@ -1430,15 +1657,17 @@ relname(char const *target, char const *linkname) if (*linkname == '/') { /* Make F absolute too. */ size_t len = strlen(directory); - size_t lenslash = len + (len && directory[len - 1] != '/'); + bool needs_slash = len && directory[len - 1] != '/'; + size_t lenslash = len + needs_slash; size_t targetsize = strlen(target) + 1; + char *cp; if (*directory != '/') return NULL; linksize = size_sum(lenslash, targetsize); - f = result = xmalloc(linksize); - memcpy(result, directory, len); - result[len] = '/'; - memcpy(result + lenslash, target, targetsize); + f = cp = result = xmalloc(linksize); + cp = mempcpy(cp, directory, len); + *cp = '/'; + memcpy(cp + needs_slash, target, targetsize); } for (i = 0; f[i] && f[i] == linkname[i]; i++) if (f[i] == '/') @@ -1448,11 +1677,13 @@ relname(char const *target, char const *linkname) taillen = strlen(f + dir_len); dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1); if (dotdotetcsize <= linksize) { + char *cp; if (!result) result = xmalloc(dotdotetcsize); + cp = result; for (i = 0; i < dotdots; i++) - memcpy(result + 3 * i, "../", 3); - memmove(result + 3 * dotdots, f + dir_len, taillen + 1); + cp = mempcpy(cp, "../", 3); + memmove(cp, f + dir_len, taillen + 1); } return result; } @@ -1820,7 +2051,7 @@ gethms(char const *string, char const *errstring) &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) { default: ok = false; break; case 8: - ok = '0' <= xr && xr <= '9'; + ok = is_digit(xr); ATTRIBUTE_FALLTHROUGH; case 7: ok &= ssx == '.'; @@ -2875,11 +3106,11 @@ doabbr(char *abbr, struct zone const *zp, char const *letters, else if (letters == disable_percent_s) return 0; sprintf(abbr, format, letters); - } else if (isdst) { - strcpy(abbr, slashp + 1); - } else { - memcpy(abbr, format, slashp - format); - abbr[slashp - format] = '\0'; + } else if (isdst) + strcpy(abbr, slashp + 1); + else { + char *abbrend = mempcpy(abbr, format, slashp - format); + *abbrend = '\0'; } len = strlen(abbr); if (!doquotes) @@ -3920,7 +4151,7 @@ newabbr(const char *string) cp = string; mp = NULL; - while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9') + while (is_alpha(*cp) || is_digit(*cp) || *cp == '-' || *cp == '+') ++cp; if (noise && cp - string < 3) @@ -3932,7 +4163,7 @@ mp = _("time zone abbreviation differs from POSIX standard"); if (mp != NULL) warning("%s (%s)", mp, string); } - i = strlen(string) + 1; + i = strnlen(string, TZ_MAX_CHARS - charcnt) + 1; if (charcnt + i > TZ_MAX_CHARS) { error(_("too many, or too long, time zone abbreviations")); exit(EXIT_FAILURE); @@ -3948,6 +4179,11 @@ mp = _("time zone abbreviation differs from POSIX standard"); static void mkdirs(char const *argname, bool ancestors) { + /* If -D was specified, do not create directories. + If a file operation's parent directory is missing, + the operation will fail and be diagnosed. */ + if (!skip_mkdir) { + char *name = xstrdup(argname); char *cp = name; @@ -3972,7 +4208,7 @@ mkdirs(char const *argname, bool ancestors) ** not check first whether it already exists, as that ** is checked anyway if the mkdir fails. */ - if (mkdir(name, MKDIR_UMASK) != 0) { + if (mkdir(name, MKDIR_PERMS) < 0) { /* Do not report an error if err == EEXIST, because some other process might have made the directory in the meantime. Likewise for ENOSYS, because @@ -3994,4 +4230,5 @@ mkdirs(char const *argname, bool ancestors) *cp++ = '/'; } free(name); + } } |
