From 3a52798841cec67c951b80e102a0248df80eb782 Mon Sep 17 00:00:00 2001 From: Stuart Bishop Date: Sun, 18 Dec 2022 12:35:11 +1100 Subject: [PATCH] Squashed 'tz/' changes from d3dc2a9d6..9baf0d34d MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 4e604e411 Release 2022g b92f566d6 The northern edge of Chihuahua changes to US rules 36acd567f Greenland change should affect only America/Nuuk 6443cc1b3 * backzone: Recommend a patch format. 76ca2b309 Fix Singapore 1981/2 time zone change 897c2968f * zic.8: Work better with Solaris 10 troff. 9b71469c5 * date.1: Change one more CW to CR. 6f94ec99e * zic.8: Port \(ha \(ga \(ti back to old troff caf02839f * zic.8: Port \(aq back to old troff. 220c21f6b Use CR font instead of CW 2fb292264 Most of Greenland stops clock-changing after March 7adffa0cd Put public-domain notices at man page starts df13da715 A few more caps and apostrophe fixes 02e725891 Use lower case page titles for commands b93c3f012 zic.8: Use correct escape sequences instead of special characters 7c6c20ebe Fix Singapore 1981/2 time zone change b8b937ac2 Use C23 [[fallthrough]] if available afcf8d223 Use C23 [[unsequenced]] if available d64e85f4d Use C23 [[reproducible]] if available. de0a1a51c Pacify gcc -std=c89 -pedantic with new attributes dbfcefe0c Use C23 [[noreturn]] if available 15c01af93 Omit unnecessary double-underscores 53b3f12f9 Use C23 [[maybe_unused]] if available 57b8fc957 Prefer for overflow checking 82889559c Fix another theoretical zic.c overflow 2d933eafb Fix theoretical integer overflow in zic.c dcc6bcf06 Improve integer overflow checking in zdump 50a255193 date: integer overflow fixes f55f17a28 Fix size_t overflow check if SIZE_MAX == INT_MAX 1d7ab5621 Don’t assume INT_MAX < UINT_FAST64_MAX c49f08703 Avoid some size_t values in localtime.c ad10807c7 Refactor zic overflow checking 8e303be7a Refactor zic to simplify overflow checking 1f15b7cd4 Minor time2sub refactor cc8291361 Simplify inputline return value 43faca98a * NEWS: Deprecate C89. b5a8115da Port int_fast64_t to C89 64-bit long 8b1c6abf9 Port UINT_FAST64_MAX back to C89 85a4b4ac6 Port to C89 gcc -pedantic f4ca780b5 Improve NEWS "Briefly" summary 1d1aa38f9 Change TF spelling in iso3166.tab bc2942ecb Colombia’s 1993 fallback was 02-06 24:00 aaca8fad7 * localtime.c (mktmcpy): Fix misplaced ‘const’. dd0ed4e11 Support timegm by default, as per C23 40c12e6e4 * strftime.c: Improve comment. 6c713aecc Port mktime and strftime to strict C bc4e7f00b Generate nicer 'make check' output 9c0117326 * northamerica: pacify 'make check_character_set' 3609abf3e * northamerica: Fix comment typo in last change. 45ee615e8 Fix some pre-1996 timestamps in northern Canada f4808ee8f Fix unlikely conversion bug in zic 4a69a067a Rename ecpyalloc to estrdup f10493358 Port to AIX 6.1 malloc b4253bbe8 Add NEWS item for previous patch ee3ddc6c2 Work around MS-Windows nmake bug 377e31128 Revert change re default HAVE_GETTEXT on macOS 317cc2c05 Port better to old Linux kernels 71958dd87 Require explicit -DHAVE_GETTEXT on macOS 841183210 Pacify compilers re #undef HAVE_GETRANDOM 2a18b7474 Make it easier to skip backcheck 0e1616ec0 * africa: Restore Morocco comment (thanks to Stephen Colebourne). 5db8b3ba4 Fix GET_RANDOM default on macOS 359a7ae00 Update Mexico comments some more 9f1f40cd6 Update Mexico zone table comments b03713259 Don’t assume nonempty argv f4c096760 * NEWS: Remove incorrect comment re musl. dbe87fe42 Port struct tm guessing to musl a91830b78 Fix tzalloc bug on platforms lacking tm_zone 5600d65e2 * theory.html: Mazatlan no longer observes DST. e5a71615d * NEWS: Credit gera. git-subtree-dir: tz git-subtree-split: 9baf0d34d95174cb9a3cfd9cb17dd9a18609a358 --- Makefile | 55 ++++++---- NEWS | 89 +++++++++++++++- africa | 4 + asia | 2 +- backward | 1 + backzone | 55 +++++++++- date.1 | 8 +- date.c | 44 ++++---- europe | 28 ++++- iso3166.tab | 6 +- localtime.c | 94 +++++++++++++---- newctime.3 | 6 +- newstrftime.3 | 4 +- newtzset.3 | 8 +- northamerica | 161 ++++++++++++++++------------ private.h | 202 ++++++++++++++++++++++++++--------- southamerica | 9 +- strftime.c | 21 ++-- theory.html | 1 - time2posix.3 | 16 +-- tzfile.5 | 6 +- tzselect.8 | 6 +- zdump.8 | 12 +-- zdump.c | 103 ++++++++++-------- zic.8 | 12 ++- zic.c | 285 +++++++++++++++++++++++++++++--------------------- zone.tab | 26 ++--- zone1970.tab | 26 ++--- 28 files changed, 868 insertions(+), 422 deletions(-) diff --git a/Makefile b/Makefile index 34cec49..afb9d53 100644 --- a/Makefile +++ b/Makefile @@ -196,6 +196,7 @@ PACKRATLIST= UTF8_LOCALE= en_US.utf8 # Non-default libraries needed to link. +# On some hosts, this should have -lintl unless CFLAGS has -DHAVE_GETTEXT=0. LDLIBS= # Add the following to the end of the "CFLAGS=" line as needed to override @@ -208,14 +209,18 @@ LDLIBS= # For example, N is 252460800 on AmigaOS. # -DHAVE_DECL_ASCTIME_R=0 if does not declare asctime_r # -DHAVE_DECL_ENVIRON if declares 'environ' +# -DHAVE_DECL_TIMEGM=0 if does not declare timegm # -DHAVE_DIRECT_H if mkdir needs (MS-Windows) -# -DHAVE_GENERIC=0 if _Generic does not work -# -DHAVE_GETRANDOM if getgrandom works (e.g., GNU/Linux)* -# -DHAVE_GETTEXT if 'gettext' works (e.g., GNU/Linux, FreeBSD, Solaris)* +# -DHAVE_GENERIC=0 if _Generic does not work* +# -DHAVE_GETRANDOM if getrandom works (e.g., GNU/Linux), +# -DHAVE_GETRANDOM=0 to avoid using getrandom +# -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 # -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares # ctime_r and asctime_r incompatibly with the POSIX standard # (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined). -# -DHAVE_INTTYPES_H if you have a non-C99 compiler with +# -DHAVE_INTTYPES_H=0 if does not work* # -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 @@ -225,15 +230,17 @@ LDLIBS= # functions like 'link' or variables like 'tzname' required by POSIX # -DHAVE_SETENV=0 if your system lacks the setenv function # -DHAVE_SNPRINTF=0 if your system lacks the snprintf function -# -DHAVE_STDINT_H if you have a non-C99 compiler with * +# -DHAVE_STDCKDINT_H=0 if neither nor substitutes like +# __builtin_add_overflow work* +# -DHAVE_STDINT_H=0 if does not work* # -DHAVE_STRFTIME_L if declares locale_t and strftime_l # -DHAVE_STRDUP=0 if your system lacks the strdup function # -DHAVE_STRTOLL=0 if your system lacks the strtoll function # -DHAVE_SYMLINK=0 if your system lacks the symlink function -# -DHAVE_SYS_STAT_H=0 if your compiler lacks a * +# -DHAVE_SYS_STAT_H=0 if does not work* # -DHAVE_TZSET=0 if your system lacks a tzset function -# -DHAVE_UNISTD_H=0 if your compiler lacks a * -# -DHAVE_UTMPX_H=0 if your compiler lacks a * +# -DHAVE_UNISTD_H=0 if does not work* +# -DHAVE_UTMPX_H=0 if does not work* # -Dlocale_t=XXX if your system uses XXX instead of locale_t # -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers # with external linkage, e.g., applications cannot define 'localtime'. @@ -280,7 +287,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ -Wdeclaration-after-statement -Wdouble-promotion \ -Wduplicated-branches -Wduplicated-cond \ -Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \ - -Winit-self -Wlogical-op \ + -Wimplicit-fallthrough=5 -Winit-self -Wlogical-op \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wnull-dereference \ -Wold-style-definition -Woverlength-strings -Wpointer-arith \ @@ -293,7 +300,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ -Wtrampolines -Wundef -Wuninitialized -Wunused-macros -Wuse-after-free=3 \ -Wvariadic-macros -Wvla -Wwrite-strings \ -Wno-address -Wno-format-nonliteral -Wno-sign-compare \ - -Wno-type-limits -Wno-unused-parameter + -Wno-type-limits # # If your system has a "GMT offset" field in its "struct tm"s # (or if you decide to add such a field in your system's "time.h" file), @@ -340,14 +347,11 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \ # If you want functions that were inspired by early versions of X3J11's work, # add # -DSTD_INSPIRED -# to the end of the "CFLAGS=" line. This arranges for the functions -# "offtime", "timelocal", "timegm", "timeoff", -# "posix2time", and "time2posix" to be added to the time conversion library. +# to the end of the "CFLAGS=" line. This arranges for the following +# 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. # "timelocal" is equivalent to "mktime". -# "timegm" is like "timelocal" except that it turns a struct tm into -# a time_t using UT (rather than local time as "timelocal" does). # "timeoff" is like "timegm" except that it accepts a second (long) argument # that gives an offset to use when converting to a time_t. # "posix2time" and "time2posix" are described in an included manual page. @@ -495,6 +499,11 @@ TARFLAGS= `if tar $(GNUTARFLAGS) --version >/dev/null 2>&1; \ # Flags to give 'gzip' when making a distribution. GZIPFLAGS= -9n +# When comparing .tzs files, use GNU diff's -F'^TZ=' option if supported. +# This makes it easier to see which Zone has been affected. +DIFF_TZS= diff -u$$(! diff -u -F'^TZ=' - - <>/dev/null >&0 2>&1 \ + || echo ' -F^TZ=') + ############################################################################### #MAKE= make @@ -773,7 +782,8 @@ tzselect: tzselect.ksh version chmod +x $@.out mv $@.out $@ -check: check_character_set check_white_space check_links \ +check: check_back check_mild +check_mild: check_character_set check_white_space check_links \ check_name_lengths check_slashed_abbrs check_sorted \ check_tables check_web check_ziguard check_zishrink check_tzs @@ -824,16 +834,19 @@ check_slashed_abbrs: $(TDATA_TO_CHECK) CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; } check_sorted: backward backzone iso3166.tab zone.tab zone1970.tab - $(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} /^$$/ {g++}' \ + $(AWK) '/^Link/ {printf "%.5d %s\n", g, $$3} !/./ {g++}' \ backward | LC_ALL=C sort -cu $(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu touch $@ -check_links: checklinks.awk $(TDATA_TO_CHECK) tzdata.zi +check_back: checklinks.awk $(TDATA_TO_CHECK) $(AWK) \ -v DATAFORM=$(DATAFORM) \ -v backcheck=backward \ -f checklinks.awk $(TDATA_TO_CHECK) + touch $@ + +check_links: checklinks.awk tzdata.zi $(AWK) \ -v DATAFORM=$(DATAFORM) \ -f checklinks.awk tzdata.zi @@ -849,7 +862,7 @@ check_tables: checktab.awk $(YDATA) backward $(ZONETABLES) check_tzs: $(TZS) $(TZS_NEW) if test -s $(TZS); then \ - diff -u $(TZS) $(TZS_NEW); \ + $(DIFF_TZS) $(TZS) $(TZS_NEW); \ else \ cp $(TZS_NEW) $(TZS); \ fi @@ -1050,7 +1063,7 @@ $(TIME_T_ALTERNATIVES): $(VERSION_DEPS) TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \ D=$$wd/$@.dir \ to$$range.tzs) && \ - diff -u $(TIME_T_ALTERNATIVES_HEAD).dir/to$$range.tzs \ + $(DIFF_TZS) $(TIME_T_ALTERNATIVES_HEAD).dir/to$$range.tzs \ $@.dir/to$$range.tzs && \ if diff -q Makefile Makefile 2>/dev/null; then \ quiet_option='-q'; \ @@ -1220,7 +1233,7 @@ zdump.o: version.h zic.o: private.h tzfile.h version.h .PHONY: ALL INSTALL all -.PHONY: check check_time_t_alternatives +.PHONY: check check_mild check_time_t_alternatives .PHONY: check_web check_zishrink .PHONY: clean clean_misc dummy.zd force_tzs .PHONY: install install_data maintainer-clean names diff --git a/NEWS b/NEWS index 0861510..701e490 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,91 @@ News for the tz database +Release 2022g - 2022-11-29 08:58:31 -0800 + + Briefly: + The northern edge of Chihuahua changes to US timekeeping. + Much of Greenland stops changing clocks after March 2023. + Fix some pre-1996 timestamps in northern Canada. + C89 is now deprecated; please use C99 or later. + Portability fixes for AIX, libintl, MS-Windows, musl, z/OS + In C code, use more C23 features if available. + C23 timegm now supported by default + Fixes for unlikely integer overflows + + Changes to future timestamps + + In the Mexican state of Chihuahua, the border strip near the US + will change to agree with nearby US locations on 2022-11-30. + The strip's western part, represented by Ciudad Juárez, switches + from -06 all year to -07/-06 with US DST rules, like El Paso, TX. + The eastern part, represented by Ojinaga, will observe US DST next + year, like Presidio, TX. (Thanks to Heitor David Pinto.) + A new Zone America/Ciudad_Juarez splits from America/Ojinaga. + + Much of Greenland, represented by America/Nuuk, stops observing + winter time after March 2023, so its daylight saving time becomes + standard time. (Thanks to Jonas Nyrup and Jürgen Appel.) + + Changes to past timestamps + + Changes for pre-1996 northern Canada (thanks to Chris Walton): + + Merge America/Iqaluit and America/Pangnirtung into the former, + with a backward compatibility link for the latter name. + There is no good evidence the two locations differ since 1970. + This change affects pre-1996 America/Pangnirtung timestamps. + + Cambridge Bay, Inuvik, Iqaluit, Rankin Inlet, Resolute and + Yellowknife did not observe DST in 1965, and did observe DST + from 1972 through 1979. + + Whitehorse moved from -09 to -08 on 1966-02-27, not 1967-05-28. + + Colombia's 1993 fallback was 02-06 24:00, not 04-04 00:00. + (Thanks to Alois Treindl.) + + Singapore's 1981-12-31 change was at 16:00 UTC (23:30 local time), + not 24:00 local time. (Thanks to Geoff Clare via Robert Elz.) + + Changes to code + + Although tzcode still works with C89, bugs found in recent routine + maintenance indicate that bitrot has set in and that in practice + C89 is no longer used to build tzcode. As it is a maintenance + burden, support for C89 is planned to be removed soon. Instead, + please use compilers compatible with C99, C11, C17, or C23. + + timegm, which tzcode implemented in 1989, will finally be + standardized 34 years later as part of C23, so timegm is now + supported even if STD_INSPIRED is not defined. + + Fix bug in zdump's tzalloc emulation on hosts that lack tm_zone. + (Problem reported by Đoàn Trần Công Danh.) + + Fix bug in zic on hosts where malloc(0) yields NULL on success. + (Problem reported by Tim McBrayer for AIX 6.1.) + + Fix zic configuration to avoid linkage failures on some platforms. + (Problems reported by Gilmore Davidson and Igor Ivanov.) + + Work around MS-Windows nmake incompatibility with POSIX. + (Problem reported by Manuela Friedrich.) + + Port mktime and strftime to debugging platforms where accessing + uninitialized data has undefined behavior (strftime problem + reported by Robert Elz). + + Check more carefully for unlikely integer overflows, preferring + C23 to overflow checking by hand, as the latter has + had obscure bugs. + + Changes to build procedure + + New Makefile rule check_mild that skips checking whether Link + lines are in the file 'backward'. (Inspired by a suggestion from + Stephen Colebourne.) + + Release 2022f - 2022-10-28 18:04:57 -0700 Briefly: @@ -16,7 +102,7 @@ Release 2022f - 2022-10-28 18:04:57 -0700 In C code, use some C23 features if available. Remove no-longer-needed workaround for Qt bug 53071. - Changes to future timestamps. + Changes to future timestamps Mexico will no longer observe DST after 2022, except for areas near the US border that continue to observe US DST rules. @@ -24,6 +110,7 @@ Release 2022f - 2022-10-28 18:04:57 -0700 from -07 (-06 with DST) to year-round -06, thus not changing its clocks that day. The new law states that Chihuahua near the US border no longer observes US DST. + (Thanks to gera for the heads-up about Chihuahua.) Fiji will not observe DST in 2022/3. (Thanks to Shalvin Narayan.) For now, assume DST is suspended indefinitely. diff --git a/africa b/africa index 92a6125..cfb9283 100644 --- a/africa +++ b/africa @@ -588,6 +588,10 @@ Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis # Agalega Is, Rodriguez # no information; probably like Indian/Mauritius + +# Morocco +# See Africa/Ceuta for Spanish Morocco. + # From Alex Krivenyshev (2008-05-09): # Here is an article that Morocco plan to introduce Daylight Saving Time between # 1 June, 2008 and 27 September, 2008. diff --git a/asia b/asia index 6e8ad28..199e6ad 100644 --- a/asia +++ b/asia @@ -3585,7 +3585,7 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 7:20 - +0720 1941 Sep 1 7:30 - +0730 1942 Feb 16 9:00 - +09 1945 Sep 12 - 7:30 - +0730 1982 Jan 1 + 7:30 - +0730 1981 Dec 31 16:00u 8:00 - +08 # Spratly Is diff --git a/backward b/backward index 4c1c5d5..0ae5d74 100644 --- a/backward +++ b/backward @@ -267,6 +267,7 @@ Link America/Tijuana America/Ensenada Link America/Indiana/Indianapolis America/Fort_Wayne Link America/Toronto America/Montreal Link America/Toronto America/Nipigon +Link America/Iqaluit America/Pangnirtung Link America/Rio_Branco America/Porto_Acre Link America/Winnipeg America/Rainy_River Link America/Argentina/Cordoba America/Rosario diff --git a/backzone b/backzone index b4ebd2e..7803c57 100644 --- a/backzone +++ b/backzone @@ -7,6 +7,10 @@ # tz@iana.org for general use in the future). For more, please see # the file CONTRIBUTING in the tz distribution. +# When proposing changes to this file, please use 'git format-patch' +# format, either by attaching the resulting .patch file to your email, +# or by using 'git send-email'. This will help maintainers save time. + # From Paul Eggert (2014-10-31): @@ -750,6 +754,55 @@ Zone America/Nipigon -5:53:04 - LMT 1895 -5:00 1:00 EDT 1942 Feb 9 2:00s -5:00 Canada E%sT +# From Rives McDow (1999-11-08): +# On October 31, when the rest of Nunavut went to Central time, +# Pangnirtung wobbled. Here is the result of their wobble: +# +# The following businesses and organizations in Pangnirtung use Central Time: +# +# First Air, Power Corp, Nunavut Construction, Health Center, RCMP, +# Eastern Arctic National Parks, A & D Specialist +# +# The following businesses and organizations in Pangnirtung use Eastern Time: +# +# Hamlet office, All other businesses, Both schools, Airport operator +# +# This has made for an interesting situation there, which warranted the news. +# No one there that I spoke with seems concerned, or has plans to +# change the local methods of keeping time, as it evidently does not +# really interfere with any activities or make things difficult locally. +# They plan to celebrate New Year's turn-over twice, one hour apart, +# so it appears that the situation will last at least that long. +# The Nunavut Intergovernmental Affairs hopes that they will "come to +# their senses", but the locals evidently don't see any problem with +# the current state of affairs. + +# From Michaela Rodrigue, writing in the +# Nunatsiaq News (1999-11-19): +# http://www.nunatsiaqonline.ca/archives/nunavut991130/nvt91119_17.html +# Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones, +# central - or Nunavut time - for government offices, and eastern time +# for municipal offices and schools.... Igloolik [was similar but then] +# made the switch to central time on Saturday, Nov. 6. + +# From Chris Walton (2022-11-06): +# The implication is that Pangnirtung and Qikiqtarjuaq have observed Eastern +# Time as far back as 1984 (and likely even further back than that). +# It is possible that these communities never actually observed Atlantic +# Time, but that would be difficult to prove. +# From Paul Eggert (2022-11-06): +# This is in 'backzone' as we have no good evidence that Pangnirtung differs +# from America/Iqaluit since 1970. A Google Books snippet view of +# volume 2, page 186 of "Pilot of Arctic Canada", published 1959 by +# the Canadian Hydrographic Service, suggests (though does not state) +# that Pangnirtung observed EST then. +# +# aka Panniqtuuq +Zone America/Pangnirtung 0 - -00 1921 # trading post est. + -5:00 NT_YK E%sT 1999 Oct 31 2:00 + -6:00 Canada C%sT 2000 Oct 29 2:00 + -5:00 Canada E%sT + # United States # # From Paul Eggert (2018-03-18): @@ -1043,7 +1096,7 @@ Zone Asia/Kuala_Lumpur 6:46:46 - LMT 1901 Jan 1 7:20 - +0720 1941 Sep 1 7:30 - +0730 1942 Feb 16 9:00 - +09 1945 Sep 12 - 7:30 - +0730 1982 Jan 1 + 7:30 - +0730 1981 Dec 31 16:00u 8:00 - +08 # Kuwait diff --git a/date.1 b/date.1 index 1ecd63a..043e568 100644 --- a/date.1 +++ b/date.1 @@ -1,10 +1,12 @@ -.TH DATE 1 +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH date 1 .SH NAME date \- show and set date and time .SH SYNOPSIS .if n .nh .if n .na -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .B date [ @@ -163,5 +165,3 @@ If is absent, UTC leap seconds are loaded from .BR /usr/share/zoneinfo/posixrules . -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/date.c b/date.c index 4e4b355..11c5e5f 100644 --- a/date.c +++ b/date.c @@ -42,7 +42,7 @@ static void display(const char *, time_t); static void dogmt(void); static void errensure(void); static void timeout(FILE *, const char *, const struct tm *); -static _Noreturn void usage(void); +static ATTRIBUTE_NORETURN void usage(void); int main(const int argc, char *argv[]) @@ -117,14 +117,19 @@ dogmt(void) static char ** fakeenv; if (fakeenv == NULL) { - register int from; - register int to; - register int n; static char tzeutc0[] = "TZ=UTC0"; + ptrdiff_t from, to, n; for (n = 0; environ[n] != NULL; ++n) continue; - fakeenv = malloc((n + 2) * sizeof *fakeenv); +#if defined ckd_add && defined ckd_mul + if (!ckd_add(&n, n, 2) && !ckd_mul(&n, n, sizeof *fakeenv) + && n <= SIZE_MAX) + fakeenv = malloc(n); +#else + if (n <= min(PTRDIFF_MAX, SIZE_MAX) / sizeof *fakeenv - 2) + fakeenv = malloc((n + 2) * sizeof *fakeenv); +#endif if (fakeenv == NULL) { fprintf(stderr, _("date: Memory exhausted\n")); errensure(); @@ -183,33 +188,28 @@ display(char const *format, time_t now) static void timeout(FILE *fp, char const *format, struct tm const *tmp) { - char * cp; - size_t result; - size_t size; - struct tm tm; - int INCR = 1024; + char *cp = NULL; + ptrdiff_t result; + ptrdiff_t size = 1024 / 2; - if (!tmp) { - fprintf(stderr, _("date: error: time out of range\n")); - errensure(); - return; - } - tm = *tmp; - tmp = &tm; - size = INCR; - cp = malloc(size); for ( ; ; ) { - if (cp == NULL) { +#ifdef ckd_mul + bool bigger = !ckd_mul(&size, size, 2) && size <= SIZE_MAX; +#else + bool bigger = (size <= min(PTRDIFF_MAX, SIZE_MAX) / 2 + && (size *= 2, true)); +#endif + char *newcp = bigger ? realloc(cp, size) : NULL; + if (!newcp) { fprintf(stderr, _("date: error: can't get memory\n")); errensure(); exit(retval); } + cp = newcp; result = strftime(cp, size, format, tmp); if (result != 0) break; - size += INCR; - cp = realloc(cp, size); } fwrite(cp + 1, 1, result - 1, fp); free(cp); diff --git a/europe b/europe index 6ac41e7..a3547b4 100644 --- a/europe +++ b/europe @@ -1103,7 +1103,30 @@ Zone Atlantic/Faroe -0:27:04 - LMT 1908 Jan 11 # Tórshavn # "National Park" by Executive Order: # http://naalakkersuisut.gl/~/media/Nanoq/Files/Attached%20Files/Engelske-tekster/Legislation/Executive%20Order%20National%20Park.rtf # It is their only National Park. -# + +# From Jonas Nyrup (2022-11-24): +# On last Saturday in October 2023 when DST ends America/Nuuk will switch +# from -03/-02 to -02/-01 +# https://sermitsiaq.ag/forslagtidsforskel-danmark-mindskes-sommertid-beholdes +# ... +# https://sermitsiaq.ag/groenland-skifte-tidszone-trods-bekymringer +# +# From Jürgen Appel (2022-11-25): +# https://ina.gl/samlinger/oversigt-over-samlinger/samling/dagsordener/dagsorden.aspx?lang=da&day=24-11-2022 +# If I understand this correctly, from the next planned switch to +# summer time, Greenland will permanently stay at that time, i.e. no +# switch back to winter time in 2023 will occur. +# +# From Paul Eggert (2022-11-28): +# The official document in Danish +# https://naalakkersuisut.gl/-/media/naalakkersuisut/filer/kundgoerelser/2022/11/2511/31_da_inatsisartutlov-om-tidens-bestemmelse.pdf?la=da&hash=A33597D8A38CC7038465241119EF34F3 +# says standard time for Greenland is -02, that Naalakkersuisut can lay down +# rules for DST and can require some areas to use a different time zone, +# and that this all takes effect 2023-03-25 22:00. The abovementioned +# "bekymringer" URL says the intent is no transition March 25, that +# Greenland will not go back to winter time in fall 2023, and that +# only America/Nuuk is affected (though further changes may occur). + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Thule 1991 1992 - Mar lastSun 2:00 1:00 D Rule Thule 1991 1992 - Sep lastSun 2:00 0 S @@ -1126,7 +1149,8 @@ Zone America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 # Ittoqqortoormiit -1:00 EU -01/+00 Zone America/Nuuk -3:26:56 - LMT 1916 Jul 28 # Godthåb -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 + -3:00 EU -03/-02 2023 Mar 25 22:00 + -2:00 - -02 Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik -4:00 Thule A%sT diff --git a/iso3166.tab b/iso3166.tab index a4ff61a..911af5e 100644 --- a/iso3166.tab +++ b/iso3166.tab @@ -3,13 +3,13 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # -# From Paul Eggert (2015-05-02): +# From Paul Eggert (2022-11-18): # This file contains a table of two-letter country codes. Columns are # separated by a single tab. Lines beginning with '#' are comments. # All text uses UTF-8 encoding. The columns of the table are as follows: # # 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 N976 (2018-11-06). See: Updates on ISO 3166-1 +# ISO 3166-1 N1087 (2022-09-02). See: Updates on ISO 3166-1 # https://isotc.iso.org/livelink/livelink/Open/16944257 # 2. The usual English name for the coded region, # chosen so that alphabetic sorting of subsets produces helpful lists. @@ -238,7 +238,7 @@ SY Syria SZ Eswatini (Swaziland) TC Turks & Caicos Is TD Chad -TF French Southern & Antarctic Lands +TF French Southern Territories TG Togo TH Thailand TJ Tajikistan diff --git a/localtime.c b/localtime.c index c556531..1d22d35 100644 --- a/localtime.c +++ b/localtime.c @@ -425,8 +425,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend, #endif if (!doaccess) { char const *dot; - size_t namelen = strlen(name); - if (sizeof lsp->fullname - sizeof tzdirslash <= namelen) + if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name)) return ENAMETOOLONG; /* Create a string "TZDIR/NAME". Using sprintf here @@ -839,7 +838,7 @@ is_digit(char c) ** Return a pointer to that character. */ -static ATTRIBUTE_PURE const char * +static ATTRIBUTE_REPRODUCIBLE const char * getzname(register const char *strp) { register char c; @@ -860,7 +859,7 @@ getzname(register const char *strp) ** We don't do any checking here; checking is done later in common-case code. */ -static ATTRIBUTE_PURE const char * +static ATTRIBUTE_REPRODUCIBLE const char * getqzname(register const char *strp, const int delim) { register int c; @@ -1120,13 +1119,11 @@ tzparse(const char *name, struct state *sp, struct state *basep) { const char * stdname; const char * dstname; - size_t stdlen; - size_t dstlen; - size_t charcnt; int_fast32_t stdoffset; int_fast32_t dstoffset; register char * cp; register bool load_ok; + ptrdiff_t stdlen, dstlen, charcnt; time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN; stdname = name; @@ -1568,6 +1565,14 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, return NULL; /* "cannot happen" */ result = localsub(sp, &newt, setname, tmp); if (result) { +#if defined ckd_add && defined ckd_sub + if (t < sp->ats[0] + ? ckd_sub(&result->tm_year, + result->tm_year, years) + : ckd_add(&result->tm_year, + result->tm_year, years)) + return NULL; +#else register int_fast64_t newy; newy = result->tm_year; @@ -1577,6 +1582,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, if (! (INT_MIN <= newy && newy <= INT_MAX)) return NULL; result->tm_year = newy; +#endif } return result; } @@ -1656,8 +1662,8 @@ localtime_r(const time_t *timep, struct tm *tmp) */ static struct tm * -gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset, - struct tm *tmp) +gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep, + int_fast32_t offset, struct tm *tmp) { register struct tm * result; @@ -1786,6 +1792,12 @@ timesub(const time_t *timep, int_fast32_t offset, y = newy; } +#ifdef ckd_add + if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) { + errno = EOVERFLOW; + return NULL; + } +#else if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) { int signed_y = y; tmp->tm_year = signed_y - TM_YEAR_BASE; @@ -1796,6 +1808,7 @@ timesub(const time_t *timep, int_fast32_t offset, errno = EOVERFLOW; return NULL; } +#endif tmp->tm_yday = idays; /* ** The "extra" mods below avoid overflow problems. @@ -1870,6 +1883,9 @@ ctime_r(const time_t *timep, char *buf) static bool increment_overflow(int *ip, int j) { +#ifdef ckd_add + return ckd_add(ip, *ip, j); +#else register int const i = *ip; /* @@ -1882,22 +1898,30 @@ increment_overflow(int *ip, int j) return true; *ip += j; return false; +#endif } static bool increment_overflow32(int_fast32_t *const lp, int const m) { +#ifdef ckd_add + return ckd_add(lp, *lp, m); +#else register int_fast32_t const l = *lp; if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) return true; *lp += m; return false; +#endif } static bool increment_overflow_time(time_t *tp, int_fast32_t j) { +#ifdef ckd_add + return ckd_add(tp, *tp, j); +#else /* ** This is like ** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...', @@ -1909,6 +1933,7 @@ increment_overflow_time(time_t *tp, int_fast32_t j) return true; *tp += j; return false; +#endif } static bool @@ -1951,6 +1976,23 @@ tmcomp(register const struct tm *const atmp, return result; } +/* Copy to *DEST from *SRC. Copy only the members needed for mktime, + as other members might not be initialized. */ +static void +mktmcpy(struct tm *dest, struct tm const *src) +{ + dest->tm_sec = src->tm_sec; + dest->tm_min = src->tm_min; + dest->tm_hour = src->tm_hour; + dest->tm_mday = src->tm_mday; + dest->tm_mon = src->tm_mon; + dest->tm_year = src->tm_year; + dest->tm_isdst = src->tm_isdst; +#if defined TM_GMTOFF && ! UNINIT_TRAP + dest->TM_GMTOFF = src->TM_GMTOFF; +#endif +} + static time_t time2sub(struct tm *const tmp, struct tm *(*funcp)(struct state const *, time_t const *, @@ -1972,7 +2014,8 @@ time2sub(struct tm *const tmp, struct tm yourtm, mytm; *okayp = false; - yourtm = *tmp; + mktmcpy(&yourtm, tmp); + if (do_norm_secs) { if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) @@ -2014,14 +2057,19 @@ time2sub(struct tm *const tmp, return WRONG; } } +#ifdef ckd_add + if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE)) + return WRONG; +#else if (increment_overflow32(&y, -TM_YEAR_BASE)) return WRONG; if (! (INT_MIN <= y && y <= INT_MAX)) return WRONG; yourtm.tm_year = y; +#endif if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) saved_seconds = 0; - else if (y + TM_YEAR_BASE < EPOCH_YEAR) { + else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) { /* ** We can't set tm_sec to 0, because that might push the ** time below the minimum representable time. @@ -2278,7 +2326,6 @@ mktime(struct tm *tmp) } #ifdef STD_INSPIRED - time_t timelocal(struct tm *tmp) { @@ -2286,13 +2333,9 @@ timelocal(struct tm *tmp) tmp->tm_isdst = -1; /* in case it wasn't initialized */ return mktime(tmp); } - -time_t -timegm(struct tm *tmp) -{ - return timeoff(tmp, 0); -} - +#else +static +#endif time_t timeoff(struct tm *tmp, long offset) { @@ -2302,7 +2345,18 @@ timeoff(struct tm *tmp, long offset) return time1(tmp, gmtsub, gmtptr, offset); } -#endif /* defined STD_INSPIRED */ +time_t +timegm(struct tm *tmp) +{ + time_t t; + struct tm tmcpy; + mktmcpy(&tmcpy, tmp); + tmcpy.tm_wday = -1; + t = timeoff(&tmcpy, 0); + if (0 <= tmcpy.tm_wday) + *tmp = tmcpy; + return t; +} static int_fast32_t leapcorr(struct state const *sp, time_t t) diff --git a/newctime.3 b/newctime.3 index 8661549..e25d841 100644 --- a/newctime.3 +++ b/newctime.3 @@ -1,9 +1,11 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. .TH NEWCTIME 3 .SH NAME asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .B #include .PP @@ -340,5 +342,3 @@ restricted to years in the range 1900 through 2099. To avoid this portability mess, new programs should use .B strftime instead. -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/newstrftime.3 b/newstrftime.3 index d68bc33..d5d8ee1 100644 --- a/newstrftime.3 +++ b/newstrftime.3 @@ -40,7 +40,7 @@ strftime \- format date and time .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .B #include .PP @@ -55,7 +55,7 @@ strftime \- format date and time .ie '\(rq'' .ds rq \&"\" .el .ds rq \(rq\" .de c -.ie \n(.g \f(CW\\$1\fP\\$2 +.ie \n(.g \f(CR\\$1\fP\\$2 .el \\$1\\$2 .. .de q diff --git a/newtzset.3 b/newtzset.3 index 8aaa0ff..1e75acf 100644 --- a/newtzset.3 +++ b/newtzset.3 @@ -1,9 +1,11 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. .TH NEWTZSET 3 .SH NAME tzset \- initialize time conversion information .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .B #include .PP @@ -331,7 +333,7 @@ from the rest of the specification. .br /usr/share/zoneinfo/localtime local timezone file .br -/usr/share/zoneinfo/posixrules used with POSIX-style TZ's +/usr/share/zoneinfo/posixrules used with POSIX-style TZ .br /usr/share/zoneinfo/GMT for UTC leap seconds .sp @@ -346,5 +348,3 @@ newctime(3), newstrftime(3), time(2), tzfile(5) -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/northamerica b/northamerica index df19543..d50581d 100644 --- a/northamerica +++ b/northamerica @@ -1969,6 +1969,37 @@ Zone America/Fort_Nelson -8:10:47 - LMT 1884 # Northwest Territories, Nunavut, Yukon +# From Chris Walton (2022-11-06): +# Whitehorse Star - Thursday April 22, 1965 - page 1 +# title: DST Starts Monday ... +# https://www.newspapers.com/image/578587481/ +# The title of this first article is wrong and/or misleading. +# Also, the start time shown in the article is vague; it simply says "after +# midnight" when it probably should have stated 2:00a.m.... +# +# Whitehorse Star - Monday October 25, 1965 - page 15 ... +# https://www.newspapers.com/image/578589147/ +# The 1965 Yukon Council minutes can be found here: +# http://assets.yukonarchives.ca/PER_YG_06_1965_C20_S02_v1.pdf +# ... I do not currently believe that NWT touched any of its clocks in 1965.... +# +# Whitehorse Star - Thursday Feb 24,1966 - page 2 +# title: It's Time for YDT ... +# https://www.newspapers.com/image/578575979/ ... +# America/Whitehorse as a permanent change from UTC-9(YST) to +# UTC-8(PST) at 00:00 on Sunday February 27, 1966.... +# +# Whitehorse Star - Friday April 28,1972 - page 6 +# title: Daylight Saving Time for N.W.T.... +# https://www.newspapers.com/image/578701610/ ... +# Nunavut and NWT zones ... DST starting in 1972.... Start and End ... +# should be the same as the rest of Canada +# +# +# From Paul Eggert (2022-11-06): +# For now, assume Yukon's 1965-04-22 spring forward was 00:00 -> 02:00, as this +# seems likely than 02:00 -> 04:00 and matches "after midnight". + # From Paul Eggert (2006-03-22): # Dawson switched to PST in 1973. Inuvik switched to MST in 1979. # Mathew Englander (1996-10-07) gives the following refs: @@ -2083,6 +2114,13 @@ Zone America/Fort_Nelson -8:10:47 - LMT 1884 # * Interpretation Act, RSY 2002, c 125 # https://www.canlii.org/en/yk/laws/stat/rsy-2002-c-125/latest/rsy-2002-c-125.html +# From Chris Walton (2022-11-06): +# The 5th edition of the Atlas of Canada contains a time zone map that +# shows both legislated and observed time zone boundaries. +# All communities on Baffin Island are shown to be observing Eastern time. +# The date on the map is 1984. +# https://ftp.maps.canada.ca/pub/nrcan_rncan/raster/atlas_5_ed/eng/other/referencemaps/mcr4056.pdf + # From Rives McDow (1999-09-04): # Nunavut ... moved ... to incorporate the whole territory into one time zone. # Nunavut moves to single time zone Oct. 31 @@ -2095,40 +2133,7 @@ Zone America/Fort_Nelson -8:10:47 - LMT 1884 # From Paul Eggert (1999-09-20): # Basic Facts: The New Territory # http://www.nunavut.com/basicfacts/english/basicfacts_1territory.html -# (1999) reports that Pangnirtung operates on eastern time, -# and that Coral Harbour does not observe DST. We don't know when -# Pangnirtung switched to eastern time; we'll guess 1995. - -# From Rives McDow (1999-11-08): -# On October 31, when the rest of Nunavut went to Central time, -# Pangnirtung wobbled. Here is the result of their wobble: -# -# The following businesses and organizations in Pangnirtung use Central Time: -# -# First Air, Power Corp, Nunavut Construction, Health Center, RCMP, -# Eastern Arctic National Parks, A & D Specialist -# -# The following businesses and organizations in Pangnirtung use Eastern Time: -# -# Hamlet office, All other businesses, Both schools, Airport operator -# -# This has made for an interesting situation there, which warranted the news. -# No one there that I spoke with seems concerned, or has plans to -# change the local methods of keeping time, as it evidently does not -# really interfere with any activities or make things difficult locally. -# They plan to celebrate New Year's turn-over twice, one hour apart, -# so it appears that the situation will last at least that long. -# The Nunavut Intergovernmental Affairs hopes that they will "come to -# their senses", but the locals evidently don't see any problem with -# the current state of affairs. - -# From Michaela Rodrigue, writing in the -# Nunatsiaq News (1999-11-19): -# http://www.nunatsiaqonline.ca/archives/nunavut991130/nvt91119_17.html -# Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones, -# central - or Nunavut time - for government offices, and eastern time -# for municipal offices and schools.... Igloolik [was similar but then] -# made the switch to central time on Saturday, Nov. 6. +# (1999) reports that ... Coral Harbour does not observe DST. # From Paul Eggert (2000-10-02): # Matthews and Vincent (1998) say the following, but we lack histories @@ -2287,18 +2292,12 @@ Rule NT_YK 1919 only - Nov 1 0:00 0 S Rule NT_YK 1942 only - Feb 9 2:00 1:00 W # War Rule NT_YK 1945 only - Aug 14 23:00u 1:00 P # Peace Rule NT_YK 1945 only - Sep 30 2:00 0 S -Rule NT_YK 1965 only - Apr lastSun 0:00 2:00 DD -Rule NT_YK 1965 only - Oct lastSun 2:00 0 S -Rule NT_YK 1980 1986 - Apr lastSun 2:00 1:00 D -Rule NT_YK 1980 2006 - Oct lastSun 2:00 0 S +Rule NT_YK 1972 1986 - Apr lastSun 2:00 1:00 D +Rule NT_YK 1972 2006 - Oct lastSun 2:00 0 S Rule NT_YK 1987 2006 - Apr Sun>=1 2:00 1:00 D +Rule Yukon 1965 only - Apr lastSun 0:00 2:00 DD +Rule Yukon 1965 only - Oct lastSun 2:00 0 S # Zone NAME STDOFF RULES FORMAT [UNTIL] -# aka Panniqtuuq -Zone America/Pangnirtung 0 - -00 1921 # trading post est. - -4:00 NT_YK A%sT 1995 Apr Sun>=1 2:00 - -5:00 Canada E%sT 1999 Oct 31 2:00 - -6:00 Canada C%sT 2000 Oct 29 2:00 - -5:00 Canada E%sT # formerly Frobisher Bay Zone America/Iqaluit 0 - -00 1942 Aug # Frobisher Bay est. -5:00 NT_YK E%sT 1999 Oct 31 2:00 @@ -2331,13 +2330,15 @@ Zone America/Inuvik 0 - -00 1953 # Inuvik founded -7:00 NT_YK M%sT 1980 -7:00 Canada M%sT Zone America/Whitehorse -9:00:12 - LMT 1900 Aug 20 - -9:00 NT_YK Y%sT 1967 May 28 0:00 - -8:00 NT_YK P%sT 1980 + -9:00 NT_YK Y%sT 1965 + -9:00 Yukon Y%sT 1966 Feb 27 0:00 + -8:00 - PST 1980 -8:00 Canada P%sT 2020 Nov 1 -7:00 - MST Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 - -9:00 NT_YK Y%sT 1973 Oct 28 0:00 - -8:00 NT_YK P%sT 1980 + -9:00 NT_YK Y%sT 1965 + -9:00 Yukon Y%sT 1973 Oct 28 0:00 + -8:00 - PST 1980 -8:00 Canada P%sT 2020 Nov 1 -7:00 - MST @@ -2559,6 +2560,14 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 # This abolishes DST except where US DST rules are observed, # and in addition changes all of Chihuahua to -06 with no DST. +# From Heitor David Pinto (2022-11-28): +# Now the northern municipalities want to have the same time zone as the +# respective neighboring cities in the US, for example Juárez in UTC-7 with +# DST, matching El Paso, and Ojinaga in UTC-6 with DST, matching Presidio.... +# the president authorized the publication of the decree for November 29, +# so the time change would occur on November 30 at 0:00. +# http://puentelibre.mx/noticia/ciudad_juarez_cambio_horario_noviembre_2022/ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Mexico 1931 only - May 1 23:00 1:00 D Rule Mexico 1931 only - Oct 1 0:00 0 S @@ -2590,14 +2599,12 @@ Zone America/Merida -5:58:28 - LMT 1922 Jan 1 6:00u -6:00 Mexico C%sT # Coahuila, Nuevo León, Tamaulipas (near US border) # This includes the following municipalities: -# in Coahuila: Ocampo, Acuña, Zaragoza, Jiménez, Piedras Negras, Nava, -# Guerrero, Hidalgo. -# in Nuevo León: Anáhuac, Los Aldama. +# in Coahuila: Acuña, Allende, Guerrero, Hidalgo, Jiménez, Morelos, Nava, +# Ocampo, Piedras Negras, Villa Unión, Zaragoza +# in Nuevo León: Anáhuac # in Tamaulipas: Nuevo Laredo, Guerrero, Mier, Miguel Alemán, Camargo, # Gustavo Díaz Ordaz, Reynosa, Río Bravo, Valle Hermoso, Matamoros. -# See: Inicia mañana Horario de Verano en zona fronteriza, El Universal, -# 2016-03-12 -# http://www.eluniversal.com.mx/articulo/estados/2016/03/12/inicia-manana-horario-de-verano-en-zona-fronteriza +# https://www.dof.gob.mx/nota_detalle.php?codigo=5670045&fecha=28/10/2022 Zone America/Matamoros -6:30:00 - LMT 1922 Jan 1 6:00u -6:00 - CST 1988 -6:00 US C%sT 1989 @@ -2616,10 +2623,24 @@ Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u -6:00 Mexico C%sT 2001 Sep 30 2:00 -6:00 - CST 2002 Feb 20 -6:00 Mexico C%sT -# Chihuahua (near US border) +# Chihuahua (near US border - western side) # This includes the municipalities of Janos, Ascensión, Juárez, Guadalupe, -# Práxedis G Guerrero, Coyame del Sotol, Ojinaga, and Manuel Benavides. -# (See the 2016-03-12 El Universal source mentioned above.) +# and Práxedis G Guerrero. +# http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf +Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 + -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1996 + -6:00 Mexico C%sT 1998 + -6:00 - CST 1998 Apr Sun>=1 3:00 + -7:00 Mexico M%sT 2010 + -7:00 US M%sT 2022 Oct 30 2:00 + -6:00 - CST 2022 Nov 30 0:00 + -7:00 US M%sT +# Chihuahua (near US border - eastern side) +# The municipalities of Coyame del Sotol, Ojinaga, and Manuel Benavides. +# http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u -7:00 - MST 1927 Jun 10 23:00 -6:00 - CST 1930 Nov 15 @@ -2629,7 +2650,8 @@ Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u -6:00 - CST 1998 Apr Sun>=1 3:00 -7:00 Mexico M%sT 2010 -7:00 US M%sT 2022 Oct 30 2:00 - -6:00 - CST + -6:00 - CST 2022 Nov 30 0:00 + -6:00 US C%sT # Chihuahua (away from US border) Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u -7:00 - MST 1927 Jun 10 23:00 @@ -2651,6 +2673,18 @@ Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u -7:00 Mexico M%sT 1999 -7:00 - MST +# Baja California Sur, Nayarit (except Bahía de Banderas), Sinaloa +Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 + -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1942 Apr 24 + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1970 + -7:00 Mexico M%sT + +# Bahía de Banderas + # From Alexander Krivenyshev (2010-04-21): # According to news, Bahía de Banderas (Mexican state of Nayarit) # changed time zone UTC-7 to new time zone UTC-6 on April 4, 2010 (to @@ -2678,17 +2712,6 @@ Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u # From Arthur David Olson (2010-05-01): # Use "Bahia_Banderas" to keep the name to fourteen characters. -# Mazatlán -Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u - -7:00 - MST 1927 Jun 10 23:00 - -6:00 - CST 1930 Nov 15 - -7:00 Mexico M%sT 1932 Apr 1 - -6:00 - CST 1942 Apr 24 - -7:00 - MST 1949 Jan 14 - -8:00 - PST 1970 - -7:00 Mexico M%sT - -# Bahía de Banderas Zone America/Bahia_Banderas -7:01:00 - LMT 1922 Jan 1 7:00u -7:00 - MST 1927 Jun 10 23:00 -6:00 - CST 1930 Nov 15 diff --git a/private.h b/private.h index 18f6a05..7a73eff 100644 --- a/private.h +++ b/private.h @@ -17,6 +17,10 @@ ** Thank you! */ +#ifndef __STDC_VERSION__ +# define __STDC_VERSION__ 0 +#endif + /* Define true, false and bool if they don't work out of the box. */ #if __STDC_VERSION__ < 199901 # define true 1 @@ -56,24 +60,13 @@ # endif #endif /* _Generic is buggy in pre-4.9 GCC. */ -#if !defined HAVE_GENERIC && defined __GNUC__ +#if !defined HAVE_GENERIC && defined __GNUC__ && !defined __STRICT_ANSI__ # define HAVE_GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__)) #endif #ifndef HAVE_GENERIC # define HAVE_GENERIC (201112 <= __STDC_VERSION__) #endif -#if !defined HAVE_GETRANDOM && defined __has_include -# if __has_include() -# define HAVE_GETRANDOM true -# else -# define HAVE_GETRANDOM false -# endif -#endif -#ifndef HAVE_GETRANDOM -# define HAVE_GETRANDOM (2 < __GLIBC__ + (25 <= __GLIBC_MINOR__)) -#endif - #if !defined HAVE_GETTEXT && defined __has_include # if __has_include() # define HAVE_GETTEXT true @@ -289,36 +282,36 @@ #endif /* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */ -#ifdef __LONG_LONG_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 -# ifdef LLONG_MAX -typedef long long int_fast64_t; -# define INT_FAST64_MIN LLONG_MIN -# define INT_FAST64_MAX LLONG_MAX -# else -# if LONG_MAX >> 31 < 0xffffffff -Please use a compiler that supports a 64-bit integer type (or wider); -you may need to compile with "-DHAVE_STDINT_H". -# endif -typedef long int_fast64_t; +# if 1 <= LONG_MAX >> 31 >> 31 +typedef long int_fast64_t; # 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 # endif #endif #ifndef PRIdFAST64 -# if INT_FAST64_MAX == LLONG_MAX -# define PRIdFAST64 "lld" -# else +# if INT_FAST64_MAX == LONG_MAX # define PRIdFAST64 "ld" +# else +# define PRIdFAST64 "lld" # endif #endif @@ -364,24 +357,27 @@ typedef long intmax_t; # endif #endif +#ifndef PTRDIFF_MAX +# define PTRDIFF_MAX MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t)) +#endif + #ifndef UINT_FAST32_MAX typedef unsigned long uint_fast32_t; #endif #ifndef UINT_FAST64_MAX -# if defined ULLONG_MAX || defined __LONG_LONG_MAX__ -typedef unsigned long long uint_fast64_t; +# if 3 <= ULONG_MAX >> 31 >> 31 +typedef unsigned long uint_fast64_t; +# define UINT_FAST64_MAX ULONG_MAX # else -# if ULONG_MAX >> 31 >> 1 < 0xffffffff -Please use a compiler that supports a 64-bit integer type (or wider); -you may need to compile with "-DHAVE_STDINT_H". -# endif -typedef unsigned long uint_fast64_t; +/* 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 # endif #endif #ifndef UINTMAX_MAX -# if defined ULLONG_MAX || defined __LONG_LONG_MAX__ +# ifdef ULLONG_MAX typedef unsigned long long uintmax_t; # else typedef unsigned long uintmax_t; @@ -389,7 +385,7 @@ typedef unsigned long uintmax_t; #endif #ifndef PRIuMAX -# if defined ULLONG_MAX || defined __LONG_LONG_MAX__ +# ifdef ULLONG_MAX # define PRIuMAX "llu" # else # define PRIuMAX "lu" @@ -400,23 +396,114 @@ typedef unsigned long uintmax_t; # define SIZE_MAX ((size_t) -1) #endif +/* Support ckd_add, ckd_sub, ckd_mul on C23 or recent-enough GCC-like + hosts, unless compiled with -DHAVE_STDCKDINT_H=0 or with pre-C23 EDG. */ +#if !defined HAVE_STDCKDINT_H && defined __has_include +# if __has_include() +# define HAVE_STDCKDINT_H true +# endif +#endif +#ifdef HAVE_STDCKDINT_H +# if HAVE_STDCKDINT_H +# include +# endif +#elif defined __EDG__ +/* Do nothing, to work around EDG bug . */ +#elif defined __has_builtin +# if __has_builtin(__builtin_add_overflow) +# define ckd_add(r, a, b) __builtin_add_overflow(a, b, r) +# endif +# if __has_builtin(__builtin_sub_overflow) +# define ckd_sub(r, a, b) __builtin_sub_overflow(a, b, r) +# endif +# if __has_builtin(__builtin_mul_overflow) +# define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r) +# endif +#elif 7 <= __GNUC__ +# define ckd_add(r, a, b) __builtin_add_overflow(a, b, r) +# define ckd_sub(r, a, b) __builtin_sub_overflow(a, b, r) +# define ckd_mul(r, a, b) __builtin_mul_overflow(a, b, r) +#endif + #if 3 <= __GNUC__ -# define ATTRIBUTE_CONST __attribute__((const)) -# define ATTRIBUTE_MALLOC __attribute__((__malloc__)) -# define ATTRIBUTE_PURE __attribute__((__pure__)) -# define ATTRIBUTE_FORMAT(spec) __attribute__((__format__ spec)) +# define ATTRIBUTE_MALLOC __attribute__((malloc)) +# define ATTRIBUTE_FORMAT(spec) __attribute__((format spec)) #else -# define ATTRIBUTE_CONST /* empty */ # define ATTRIBUTE_MALLOC /* empty */ -# define ATTRIBUTE_PURE /* empty */ # define ATTRIBUTE_FORMAT(spec) /* empty */ #endif -#if !defined _Noreturn && __STDC_VERSION__ < 201112 -# if 2 < __GNUC__ + (8 <= __GNUC_MINOR__) -# define _Noreturn __attribute__((__noreturn__)) +#if (defined __has_c_attribute \ + && (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__)) +# define HAVE_HAS_C_ATTRIBUTE true +#else +# define HAVE_HAS_C_ATTRIBUTE false +#endif + +#if HAVE_HAS_C_ATTRIBUTE +# if __has_c_attribute(fallthrough) +# define ATTRIBUTE_FALLTHROUGH [[fallthrough]] +# endif +#endif +#ifndef ATTRIBUTE_FALLTHROUGH +# if 7 <= __GNUC__ +# define ATTRIBUTE_FALLTHROUGH __attribute__((fallthrough)) +# else +# define ATTRIBUTE_FALLTHROUGH ((void) 0) +# endif +#endif + +#if HAVE_HAS_C_ATTRIBUTE +# if __has_c_attribute(maybe_unused) +# define ATTRIBUTE_MAYBE_UNUSED [[maybe_unused]] +# endif +#endif +#ifndef ATTRIBUTE_MAYBE_UNUSED +# if 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define ATTRIBUTE_MAYBE_UNUSED __attribute__((unused)) +# else +# define ATTRIBUTE_MAYBE_UNUSED /* empty */ +# endif +#endif + +#if HAVE_HAS_C_ATTRIBUTE +# if __has_c_attribute(noreturn) +# define ATTRIBUTE_NORETURN [[noreturn]] +# endif +#endif +#ifndef ATTRIBUTE_NORETURN +# if 201112 <= __STDC_VERSION__ +# define ATTRIBUTE_NORETURN _Noreturn +# elif 2 < __GNUC__ + (8 <= __GNUC_MINOR__) +# define ATTRIBUTE_NORETURN __attribute__((noreturn)) # else -# define _Noreturn +# define ATTRIBUTE_NORETURN /* empty */ +# endif +#endif + +#if HAVE_HAS_C_ATTRIBUTE +# if __has_c_attribute(reproducible) +# define ATTRIBUTE_REPRODUCIBLE [[reproducible]] +# endif +#endif +#ifndef ATTRIBUTE_REPRODUCIBLE +# if 3 <= __GNUC__ +# define ATTRIBUTE_REPRODUCIBLE __attribute__((pure)) +# else +# define ATTRIBUTE_REPRODUCIBLE /* empty */ +# endif +#endif + +#if HAVE_HAS_C_ATTRIBUTE +# if __has_c_attribute(unsequenced) +# define ATTRIBUTE_UNSEQUENCED [[unsequenced]] +# endif +#endif +#ifndef ATTRIBUTE_UNSEQUENCED +# if 3 <= __GNUC__ +# define ATTRIBUTE_UNSEQUENCED __attribute__((const)) +# else +# define ATTRIBUTE_UNSEQUENCED /* empty */ # endif #endif @@ -541,7 +628,7 @@ char *asctime(struct tm const *); char *asctime_r(struct tm const *restrict, char *restrict); char *ctime(time_t const *); char *ctime_r(time_t const *, char *); -double difftime(time_t, time_t) ATTRIBUTE_CONST; +double difftime(time_t, time_t) ATTRIBUTE_UNSEQUENCED; size_t strftime(char *restrict, size_t, char const *restrict, struct tm const *restrict); # if HAVE_STRFTIME_L @@ -554,9 +641,24 @@ struct tm *localtime(time_t const *); struct tm *localtime_r(time_t const *restrict, struct tm *restrict); time_t mktime(struct tm *); time_t time(time_t *); +time_t timegm(struct tm *); void tzset(void); #endif +#ifndef HAVE_DECL_TIMEGM +# if (202311 <= __STDC_VERSION__ \ + || defined __GLIBC__ || defined __tm_zone /* musl */ \ + || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ + || (defined __APPLE__ && defined __MACH__)) +# define HAVE_DECL_TIMEGM true +# else +# define HAVE_DECL_TIMEGM false +# endif +#endif +#if !HAVE_DECL_TIMEGM && !defined timegm +time_t timegm(struct tm *); +#endif + #if !HAVE_DECL_ASCTIME_R && !defined asctime_r extern char *asctime_r(struct tm const *restrict, char *restrict); #endif @@ -593,9 +695,6 @@ extern long altzone; # if TZ_TIME_T || !defined offtime struct tm *offtime(time_t const *, long); # endif -# if TZ_TIME_T || !defined timegm -time_t timegm(struct tm *); -# endif # if TZ_TIME_T || !defined timelocal time_t timelocal(struct tm *); # endif @@ -613,6 +712,7 @@ time_t posix2time(time_t); /* Infer TM_ZONE on systems where this information is known, but suppress guessing if NO_TM_ZONE is defined. Similarly for TM_GMTOFF. */ #if (defined __GLIBC__ \ + || defined __tm_zone /* musl */ \ || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ || (defined __APPLE__ && defined __MACH__)) # if !defined TM_GMTOFF && !defined NO_TM_GMTOFF @@ -640,10 +740,10 @@ timezone_t tzalloc(char const *); void tzfree(timezone_t); # ifdef STD_INSPIRED # if TZ_TIME_T || !defined posix2time_z -time_t posix2time_z(timezone_t, time_t) ATTRIBUTE_PURE; +time_t posix2time_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE; # endif # if TZ_TIME_T || !defined time2posix_z -time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE; +time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE; # endif # endif #endif diff --git a/southamerica b/southamerica index 13cc65e..87b71d5 100644 --- a/southamerica +++ b/southamerica @@ -1418,9 +1418,14 @@ Zone Antarctica/Palmer 0 - -00 1965 # Milne gives 4:56:16.4 for Bogotá time in 1899. He writes, # "A variation of fifteen minutes in the public clocks of Bogota is not rare." +# From Alois Treindl (2022-11-10): +# End of time change in Colombia 1993 ... should be 6 February 24h ... +# DECRETO 267 DE 1993 +# https://www.suin-juriscol.gov.co/viewDocument.asp?ruta=Decretos/1061335 + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S -Rule CO 1992 only - May 3 0:00 1:00 - -Rule CO 1993 only - Apr 4 0:00 0 - +Rule CO 1992 only - May 3 0:00 1:00 - +Rule CO 1993 only - Feb 6 24:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] #STDOFF -4:56:16.4 Zone America/Bogota -4:56:16 - LMT 1884 Mar 13 diff --git a/strftime.c b/strftime.c index deba2b5..b23b610 100644 --- a/strftime.c +++ b/strftime.c @@ -117,7 +117,7 @@ static char * _yconv(int, int, bool, bool, char *, char const *); #if HAVE_STRFTIME_L size_t strftime_l(char *s, size_t maxsize, char const *format, struct tm const *t, - locale_t locale) + ATTRIBUTE_MAYBE_UNUSED locale_t locale) { /* Just call strftime, as only the C locale is supported. */ return strftime(s, maxsize, format, t); @@ -319,12 +319,21 @@ _fmt(const char *format, const struct tm *t, char *pt, time_t) + 1]; time_t mkt; - tm = *t; + tm.tm_sec = t->tm_sec; + tm.tm_min = t->tm_min; + tm.tm_hour = t->tm_hour; + tm.tm_mday = t->tm_mday; + tm.tm_mon = t->tm_mon; + tm.tm_year = t->tm_year; + tm.tm_isdst = t->tm_isdst; +#if defined TM_GMTOFF && ! UNINIT_TRAP + tm.TM_GMTOFF = t->TM_GMTOFF; +#endif mkt = mktime(&tm); - /* There is no portable, definitive - test for whether whether mktime - succeeded, so treat (time_t) -1 as - the success that it might be. */ + /* If mktime fails, %s expands to the + value of (time_t) -1 as a failure + marker; this is better in practice + than strftime failing. */ if (TYPE_SIGNED(time_t)) { intmax_t n = mkt; sprintf(buf, "%"PRIdMAX, n); diff --git a/theory.html b/theory.html index 298db86..75e347f 100644 --- a/theory.html +++ b/theory.html @@ -60,7 +60,6 @@

Scope of the tz database

American mountain time zone can choose from the timezones America/Denver which observes US-style daylight saving time (DST), -America/Mazatlan which observes Mexican-style DST, and America/Phoenix which does not observe DST. Applications that also deal with past timestamps in the mountain time zone can choose from over a dozen timezones, such as diff --git a/time2posix.3 b/time2posix.3 index 1fcdf9e..e13c431 100644 --- a/time2posix.3 +++ b/time2posix.3 @@ -1,9 +1,11 @@ -.TH TIME2POSIX 3 +.\" This file is in the public domain, so clarified as of +.\" 1996-06-05 by Arthur David Olson. +.TH time2posix 3 .SH NAME time2posix, posix2time \- convert seconds since the Epoch .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .B #include .PP @@ -58,7 +60,7 @@ expression for directly computing a time_t value from a given date/time, and the same relationship is assumed by some (usually older) applications. -Any programs creating/dissecting time_t's +Any programs creating/dissecting time_t values using such a relationship will typically not handle intervals over leap seconds correctly. .PP @@ -93,7 +95,7 @@ Both of these are good indicators of the inferiority of the POSIX representation. .PP The following table summarizes the relationship between a time -T and it's conversion to, +T and its conversion to, and back from, the POSIX representation over the leap second inserted at the end of June, 1993. @@ -117,8 +119,8 @@ DATE TIME T X=time2posix(T) posix2time(X) .fi .PP If leap-second support is not enabled, -local time_t's and -POSIX time_t's are equivalent, +local time_t and +POSIX time_t values are equivalent, and both .B time2posix and @@ -129,5 +131,3 @@ difftime(3), localtime(3), mktime(3), time(2) -.\" This file is in the public domain, so clarified as of -.\" 1996-06-05 by Arthur David Olson. diff --git a/tzfile.5 b/tzfile.5 index 280e8d8..c3e86c6 100644 --- a/tzfile.5 +++ b/tzfile.5 @@ -1,3 +1,5 @@ +.\" This file is in the public domain, so clarified as of +.\" 1996-06-05 by Arthur David Olson. .TH TZFILE 5 .SH NAME tzfile \- timezone information @@ -9,7 +11,7 @@ tzfile \- timezone information .de q \\$3\*(lq\\$1\*(rq\\$2 .. -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- The timezone information files used by .BR tzset (3) @@ -492,5 +494,3 @@ Internet RFC 8536 .UR https://\:doi.org/\:10.17487/\:RFC8536 doi:10.17487/RFC8536 .UE . -.\" This file is in the public domain, so clarified as of -.\" 1996-06-05 by Arthur David Olson. diff --git a/tzselect.8 b/tzselect.8 index 1a5ce11..846b867 100644 --- a/tzselect.8 +++ b/tzselect.8 @@ -1,8 +1,10 @@ +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. .TH TZSELECT 8 .SH NAME tzselect \- select a timezone .SH SYNOPSIS -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- .ds d " degrees .ds m " minutes @@ -121,5 +123,3 @@ newctime(3), tzfile(5), zdump(8), zic(8) Applications should not assume that .BR tzselect 's output matches the user's political preferences. -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/zdump.8 b/zdump.8 index 131a6cb..170e18d 100644 --- a/zdump.8 +++ b/zdump.8 @@ -1,4 +1,6 @@ -.TH ZDUMP 8 +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH zdump 8 .SH NAME zdump \- timezone dumper .SH SYNOPSIS @@ -16,7 +18,7 @@ zdump \- timezone dumper .de q \\$3\*(lq\\$1\*(rq\\$2 .. -.ie \n(.g .ds - \f(CW-\fP +.ie \n(.g .ds - \f(CR-\fP .el .ds - \- The .B zdump @@ -149,7 +151,7 @@ Here is an example of the output, with the leading empty line omitted. tabbed columns line up.) .nf .sp -.if \n(.g .ft CW +.if \n(.g .ft CR .if t .in +.5i .if n .in +2 .nr w \w'1896-01-13 'u+\n(.i @@ -182,7 +184,7 @@ UT, a standard time abbreviated HST. Here are excerpts from another example: .nf .sp -.if \n(.g .ft CW +.if \n(.g .ft CR .if t .in +.5i .if n .in +2 TZ="Europe/Astrakhan" @@ -227,5 +229,3 @@ introduction of UTC is problematic. .SH SEE ALSO .BR tzfile (5), .BR zic (8) -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/zdump.c b/zdump.c index ffb321a..7acb3e2 100644 --- a/zdump.c +++ b/zdump.c @@ -84,20 +84,20 @@ static time_t const absolute_max_time = ? (((time_t) 1 << atime_shift) - 1 + ((time_t) 1 << atime_shift)) : -1); static int longest; -static char * progname; +static char const *progname; static bool warned; static bool errout; static char const *abbr(struct tm const *); -static intmax_t delta(struct tm *, struct tm *) ATTRIBUTE_PURE; +static intmax_t delta(struct tm *, struct tm *) ATTRIBUTE_REPRODUCIBLE; static void dumptime(struct tm const *); -static time_t hunt(timezone_t, char *, time_t, time_t, bool); +static time_t hunt(timezone_t, time_t, time_t, bool); static void show(timezone_t, char *, time_t, bool); static void showextrema(timezone_t, char *, time_t, struct tm *, time_t); static void showtrans(char const *, struct tm const *, time_t, char const *, char const *); static const char *tformat(void); -static time_t yeartot(intmax_t) ATTRIBUTE_PURE; +static time_t yeartot(intmax_t) ATTRIBUTE_REPRODUCIBLE; /* Is C an ASCII digit? */ static bool @@ -125,16 +125,28 @@ is_alpha(char a) } } -/* Return A + B, exiting if the result would overflow. */ -static size_t +static ATTRIBUTE_NORETURN void +size_overflow(void) +{ + fprintf(stderr, _("%s: size overflow\n"), progname); + exit(EXIT_FAILURE); +} + +/* Return A + B, exiting if the result would overflow either ptrdiff_t + or size_t. */ +static ATTRIBUTE_REPRODUCIBLE ptrdiff_t sumsize(size_t a, size_t b) { - size_t sum = a + b; - if (sum < a) { - fprintf(stderr, _("%s: size overflow\n"), progname); - exit(EXIT_FAILURE); - } - return sum; +#ifdef ckd_add + ptrdiff_t sum; + if (!ckd_add(&sum, a, b) && sum <= SIZE_MAX) + return sum; +#else + ptrdiff_t sum_max = min(PTRDIFF_MAX, SIZE_MAX); + if (a <= sum_max && b <= sum_max - a) + return a + b; +#endif + size_overflow(); } /* Return a pointer to a newly allocated buffer of size SIZE, exiting @@ -234,22 +246,30 @@ tzalloc(char const *val) exit(EXIT_FAILURE); } tzset(); - return NULL; + return &optarg; /* Any valid non-null char ** will do. */ # else enum { TZeqlen = 3 }; static char const TZeq[TZeqlen] = "TZ="; static char **fakeenv; - static size_t fakeenv0size; + static ptrdiff_t fakeenv0size; void *freeable = NULL; char **env = fakeenv, **initial_environ; size_t valsize = strlen(val) + 1; if (fakeenv0size < valsize) { char **e = environ, **to; - ptrdiff_t initial_nenvptrs; /* Counting the trailing NULL pointer. */ - - while (*e++) - continue; - initial_nenvptrs = e - environ; + ptrdiff_t initial_nenvptrs = 1; /* Counting the trailing NULL pointer. */ + + while (*e++) { +# ifdef ckd_add + if (ckd_add(&initial_nenvptrs, initial_envptrs, 1) + || SIZE_MAX < initial_envptrs) + size_overflow(); +# else + if (initial_nenvptrs == min(PTRDIFF_MAX, SIZE_MAX) / sizeof *environ) + size_overflow(); + initial_nenvptrs++; +# endif + } fakeenv0size = sumsize(valsize, valsize); fakeenv0size = max(fakeenv0size, 64); freeable = env; @@ -385,7 +405,7 @@ abbrok(const char *const abbrp, const char *const zone) return the abbreviation. Get the abbreviation from TMP. Exit on memory allocation failure. */ static char const * -saveabbr(char **buf, size_t *bufalloc, struct tm const *tmp) +saveabbr(char **buf, ptrdiff_t *bufalloc, struct tm const *tmp) { char const *ab = abbr(tmp); if (HAVE_LOCALTIME_RZ) @@ -442,7 +462,7 @@ main(int argc, char *argv[]) { /* These are static so that they're initially zero. */ static char * abbrev; - static size_t abbrevsize; + static ptrdiff_t abbrevsize; register int i; register bool vflag; @@ -463,7 +483,7 @@ main(int argc, char *argv[]) # endif /* defined TEXTDOMAINDIR */ textdomain(TZ_DOMAIN); #endif /* HAVE_GETTEXT */ - progname = argv[0]; + progname = argv[0] ? argv[0] : "zdump"; for (i = 1; i < argc; ++i) if (strcmp(argv[i], "--version") == 0) { printf("zdump %s%s\n", PKGVERSION, TZVERSION); @@ -483,7 +503,7 @@ main(int argc, char *argv[]) case -1: if (! (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) goto arg_processing_done; - /* Fall through. */ + ATTRIBUTE_FALLTHROUGH; default: usage(stderr, EXIT_FAILURE); } @@ -607,7 +627,7 @@ main(int argc, char *argv[]) || (ab && (delta(&newtm, &tm) != newt - t || newtm.tm_isdst != tm.tm_isdst || strcmp(abbr(&newtm), ab) != 0))) { - newt = hunt(tz, argv[i], t, newt, false); + newt = hunt(tz, t, newt, false); newtmp = localtime_rz(tz, &newt, &newtm); newtm_ok = newtmp != NULL; if (iflag) @@ -687,7 +707,7 @@ yeartot(intmax_t y) return t; } -/* Search for a discontinuity in timezone TZ with name NAME, in the +/* Search for a discontinuity in timezone TZ, in the timestamps ranging from LOT through HIT. LOT and HIT disagree about some aspect of timezone. If ONLY_OK, search only for definedness changes, i.e., localtime succeeds on one side of the @@ -695,10 +715,10 @@ yeartot(intmax_t y) before the transition from LOT's settings. */ static time_t -hunt(timezone_t tz, char *name, time_t lot, time_t hit, bool only_ok) +hunt(timezone_t tz, time_t lot, time_t hit, bool only_ok) { static char * loab; - static size_t loabsize; + static ptrdiff_t loabsize; struct tm lotm; struct tm tm; @@ -787,7 +807,8 @@ adjusted_yday(struct tm const *a, struct tm const *b) my_gmtime_r and use its result instead of B. Otherwise, B is the possibly nonnull result of an earlier call to my_gmtime_r. */ static long -gmtoff(struct tm const *a, time_t *t, struct tm const *b) +gmtoff(struct tm const *a, ATTRIBUTE_MAYBE_UNUSED time_t *t, + ATTRIBUTE_MAYBE_UNUSED struct tm const *b) { #ifdef TM_GMTOFF return a->TM_GMTOFF; @@ -858,7 +879,7 @@ static void showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi) { struct tm localtm[2], gmtm[2]; - time_t t, boundary = hunt(tz, zone, lo, hi, true); + time_t t, boundary = hunt(tz, lo, hi, true); bool old = false; hi = (SECSPERDAY < hi - boundary ? boundary + SECSPERDAY @@ -937,7 +958,7 @@ my_snprintf(char *s, size_t size, char const *format, ...) fit, return the length that the string would have been if it had fit; do not overrun the output buffer. */ static int -format_local_time(char *buf, size_t size, struct tm const *tm) +format_local_time(char *buf, ptrdiff_t size, struct tm const *tm) { int ss = tm->tm_sec, mm = tm->tm_min, hh = tm->tm_hour; return (ss @@ -960,7 +981,7 @@ format_local_time(char *buf, size_t size, struct tm const *tm) the length that the string would have been if it had fit; do not overrun the output buffer. */ static int -format_utc_offset(char *buf, size_t size, struct tm const *tm, time_t t) +format_utc_offset(char *buf, ptrdiff_t size, struct tm const *tm, time_t t) { long off = gmtoff(tm, &t, NULL); char sign = ((off < 0 @@ -989,11 +1010,11 @@ format_utc_offset(char *buf, size_t size, struct tm const *tm, time_t t) If the representation's length is less than SIZE, return the length; the representation is not null terminated. Otherwise return SIZE, to indicate that BUF is too small. */ -static size_t -format_quoted_string(char *buf, size_t size, char const *p) +static ptrdiff_t +format_quoted_string(char *buf, ptrdiff_t size, char const *p) { char *b = buf; - size_t s = size; + ptrdiff_t s = size; if (!s) return size; *b++ = '"', s--; @@ -1031,11 +1052,11 @@ format_quoted_string(char *buf, size_t size, char const *p) and omit any trailing tabs. */ static bool -istrftime(char *buf, size_t size, char const *time_fmt, +istrftime(char *buf, ptrdiff_t size, char const *time_fmt, struct tm const *tm, time_t t, char const *ab, char const *zone_name) { char *b = buf; - size_t s = size; + ptrdiff_t s = size; char const *f = time_fmt, *p; for (p = f; ; p++) @@ -1044,9 +1065,9 @@ istrftime(char *buf, size_t size, char const *time_fmt, else if (!*p || (*p == '%' && (p[1] == 'f' || p[1] == 'L' || p[1] == 'Q'))) { - size_t formatted_len; - size_t f_prefix_len = p - f; - size_t f_prefix_copy_size = p - f + 2; + ptrdiff_t formatted_len; + ptrdiff_t f_prefix_len = p - f; + ptrdiff_t f_prefix_copy_size = sumsize(f_prefix_len, 2); char fbuf[100]; bool oversized = sizeof fbuf <= f_prefix_copy_size; char *f_prefix_copy = oversized ? xmalloc(f_prefix_copy_size) : fbuf; @@ -1078,7 +1099,7 @@ istrftime(char *buf, size_t size, char const *time_fmt, b += offlen, s -= offlen; if (show_abbr) { char const *abp; - size_t len; + ptrdiff_t len; if (s <= 1) return false; *b++ = '\t', s--; @@ -1117,7 +1138,7 @@ showtrans(char const *time_fmt, struct tm const *tm, time_t t, char const *ab, putchar('\n'); } else { char stackbuf[1000]; - size_t size = sizeof stackbuf; + ptrdiff_t size = sizeof stackbuf; char *buf = stackbuf; char *bufalloc = NULL; while (! istrftime(buf, size, time_fmt, tm, t, ab, zone_name)) { diff --git a/zic.8 b/zic.8 index f79148f..019a289 100644 --- a/zic.8 +++ b/zic.8 @@ -1,4 +1,6 @@ -.TH ZIC 8 +.\" This file is in the public domain, so clarified as of +.\" 2009-05-17 by Arthur David Olson. +.TH zic 8 .SH NAME zic \- timezone compiler .SH SYNOPSIS @@ -22,7 +24,7 @@ zic \- timezone compiler .el .ds > \(ra .ie \n(.g \{\ . ds : \: -. ds - \f(CW-\fP +. ds - \f(CR-\fP .\} .el \{\ . ds : @@ -347,7 +349,9 @@ nor .q + . To allow for future extensions, an unquoted name should not contain characters from the set -.q !$%&'()*,/:;<=>?@[\e]^`{|}~ . +.ie \n(.g .q \f(CR!$%&\(aq()*,/:;<=>?@[\e]\(ha\(ga{|}\(ti\fP . +.el .ie t .q \f(CW!$%&'()*,/:;<=>?@[\e]^\(ga{|}~\fP . +.el .q !$%&'()*,/:;<=>?@[\e]^`{|}~ . .TP .B FROM Gives the first year in which the rule applies. @@ -894,5 +898,3 @@ specifying transition instants using universal time. .SH SEE ALSO .BR tzfile (5), .BR zdump (8) -.\" This file is in the public domain, so clarified as of -.\" 2009-05-17 by Arthur David Olson. diff --git a/zic.c b/zic.c index 501718f..892414a 100644 --- a/zic.c +++ b/zic.c @@ -34,6 +34,9 @@ static zic_t const # define ZIC_MAX_ABBR_LEN_WO_WARN 6 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ +/* An upper bound on how much a format might grow due to concatenation. */ +enum { FORMAT_LEN_GROWTH_BOUND = 5 }; + #ifdef HAVE_DIRECT_H # include # include @@ -41,7 +44,16 @@ static zic_t const # define mkdir(name, mode) _mkdir(name) #endif -#if HAVE_GETRANDOM +#ifndef HAVE_GETRANDOM +# ifdef __has_include +# if __has_include() +# include +# endif +# elif 2 < __GLIBC__ + (25 <= __GLIBC_MINOR__) +# include +# endif +# define HAVE_GETRANDOM GRND_RANDOM +#elif HAVE_GETRANDOM # include #endif @@ -54,11 +66,6 @@ static zic_t const # define MKDIR_UMASK 0755 #endif -/* The maximum ptrdiff_t value, for pre-C99 platforms. */ -#ifndef PTRDIFF_MAX -static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t)); -#endif - /* The minimum alignment of a type, for pre-C23 platforms. */ #if __STDC_VERSION__ < 201112 # define alignof(type) offsetof(struct { char a; type b; }, b) @@ -452,29 +459,54 @@ static char roll[TZ_MAX_LEAPS]; ** Memory allocation. */ -static _Noreturn void +static ATTRIBUTE_NORETURN void memory_exhausted(const char *msg) { fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg); exit(EXIT_FAILURE); } -static ATTRIBUTE_PURE size_t -size_product(size_t nitems, size_t itemsize) +static ATTRIBUTE_NORETURN void +size_overflow(void) +{ + memory_exhausted(_("size overflow")); +} + +static ATTRIBUTE_REPRODUCIBLE ptrdiff_t +size_sum(size_t a, size_t b) +{ +#ifdef ckd_add + ptrdiff_t sum; + if (!ckd_add(&sum, a, b) && sum <= SIZE_MAX) + return sum; +#else + ptrdiff_t sum_max = min(PTRDIFF_MAX, SIZE_MAX); + if (a <= sum_max && b <= sum_max - a) + return a + b; +#endif + size_overflow(); +} + +static ATTRIBUTE_REPRODUCIBLE ptrdiff_t +size_product(ptrdiff_t nitems, ptrdiff_t itemsize) { - if (SIZE_MAX / itemsize < nitems) - memory_exhausted(_("size overflow")); - return nitems * itemsize; +#ifdef ckd_mul + ptrdiff_t product; + if (!ckd_mul(&product, nitems, itemsize) && product <= SIZE_MAX) + return product; +#else + ptrdiff_t nitems_max = min(PTRDIFF_MAX, SIZE_MAX) / itemsize; + if (nitems <= nitems_max) + return nitems * itemsize; +#endif + size_overflow(); } -static ATTRIBUTE_PURE size_t -align_to(size_t size, size_t alignment) +static ATTRIBUTE_REPRODUCIBLE ptrdiff_t +align_to(ptrdiff_t size, ptrdiff_t alignment) { - size_t aligned_size = size + alignment - 1; - aligned_size -= aligned_size % alignment; - if (aligned_size < size) - memory_exhausted(_("alignment overflow")); - return aligned_size; + ptrdiff_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits); + return sum & ~lo_bits; } #if !HAVE_STRDUP @@ -507,23 +539,37 @@ erealloc(void *ptr, size_t size) } static char * ATTRIBUTE_MALLOC -ecpyalloc(char const *str) +estrdup(char const *str) { return memcheck(strdup(str)); } +static ptrdiff_t +grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize) +{ + ptrdiff_t addend = (*nitems_alloc >> 1) + 1; +#if defined ckd_add && defined ckd_mul + ptrdiff_t product; + if (!ckd_add(nitems_alloc, *nitems_alloc, addend) + && !ckd_mul(&product, *nitems_alloc, itemsize) && product <= SIZE_MAX) + return product; +#else + ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX); + if (*nitems_alloc <= ((amax - 1) / 3 * 2) / itemsize) { + *nitems_alloc += addend; + return *nitems_alloc * itemsize; + } +#endif + memory_exhausted(_("integer overflow")); +} + static void * -growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc) +growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems, + ptrdiff_t *nitems_alloc) { - if (nitems < *nitems_alloc) - return ptr; - else { - ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX); - if ((amax - 1) / 3 * 2 < *nitems_alloc) - memory_exhausted(_("integer overflow")); - *nitems_alloc += (*nitems_alloc >> 1) + 1; - return erealloc(ptr, size_product(*nitems_alloc, itemsize)); - } + return (nitems < *nitems_alloc + ? ptr + : erealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize))); } /* @@ -620,7 +666,7 @@ close_file(FILE *stream, char const *dir, char const *name, } } -static _Noreturn void +static ATTRIBUTE_NORETURN void usage(FILE *stream, int status) { fprintf(stream, @@ -943,7 +989,7 @@ main(int argc, char **argv) textdomain(TZ_DOMAIN); #endif /* HAVE_GETTEXT */ main_argv = argv; - progname = argv[0]; + progname = argv[0] ? argv[0] : "zic"; if (TYPE_BIT(zic_t) < 64) { fprintf(stderr, "%s: %s\n", progname, _("wild compilation-time specification of zic_t")); @@ -1201,21 +1247,12 @@ get_rand_u64(void) #endif /* getrandom didn't work, so fall back on portable code that is - not the best because the seed doesn't necessarily have enough bits, - the seed isn't cryptographically random on platforms lacking - getrandom, and 'rand' might not be cryptographically secure. */ + not the best because the seed isn't cryptographically random and + 'rand' might not be cryptographically secure. */ { static bool initialized; if (!initialized) { - unsigned seed; -#ifdef CLOCK_REALTIME - struct timespec now; - clock_gettime (CLOCK_REALTIME, &now); - seed = now.tv_sec ^ now.tv_nsec; -#else - seed = time(NULL); -#endif - srand(seed); + srand(time(NULL)); initialized = true; } } @@ -1224,13 +1261,21 @@ get_rand_u64(void) the typical case where RAND_MAX is one less than a power of two. In other cases this code yields a sort-of-random number. */ { - uint_fast64_t - rand_max = RAND_MAX, - multiplier = rand_max + 1, /* It's OK if this overflows to 0. */ + uint_fast64_t rand_max = RAND_MAX, + nrand = rand_max < UINT_FAST64_MAX ? rand_max + 1 : 0, + rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1, r = 0, rmax = 0; + do { - uint_fast64_t rmax1 = rmax * multiplier + rand_max; - r = r * multiplier + rand(); + uint_fast64_t rmax1 = rmax; + if (rmod) { + /* Avoid signed integer overflow on theoretical platforms + where uint_fast64_t promotes to int. */ + rmax1 %= rmod; + r %= rmod; + } + rmax1 = nrand * rmax1 + rand_max; + r = nrand * r + rand(); rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX; } while (rmax < UINT_FAST64_MAX); @@ -1272,7 +1317,7 @@ random_dirent(char const **name, char **namealloc) uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6); if (!dst) { - dst = emalloc(dirlen + prefixlen + suffixlen + 1); + dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); memcpy(dst, src, dirlen); memcpy(dst + dirlen, prefix, prefixlen); dst[dirlen + prefixlen + suffixlen] = '\0'; @@ -1351,19 +1396,20 @@ rename_dest(char *tempname, char const *name) static char * relname(char const *target, char const *linkname) { - size_t i, taillen, dotdotetcsize; - size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX; + size_t i, taillen, dir_len = 0, dotdots = 0; + ptrdiff_t dotdotetcsize, linksize = min(PTRDIFF_MAX, SIZE_MAX); char const *f = target; char *result = NULL; if (*linkname == '/') { /* Make F absolute too. */ size_t len = strlen(directory); - bool needslash = len && directory[len - 1] != '/'; - linksize = len + needslash + strlen(target) + 1; + size_t lenslash = len + (len && directory[len - 1] != '/'); + size_t targetsize = strlen(target) + 1; + linksize = size_sum(lenslash, targetsize); f = result = emalloc(linksize); - strcpy(result, directory); + memcpy(result, directory, len); result[len] = '/'; - strcpy(result + len + needslash, target); + memcpy(result + lenslash, target, targetsize); } for (i = 0; f[i] && f[i] == linkname[i]; i++) if (f[i] == '/') @@ -1371,7 +1417,7 @@ relname(char const *target, char const *linkname) for (; linkname[i]; i++) dotdots += linkname[i] == '/' && linkname[i - 1] != '/'; taillen = strlen(f + dir_len); - dotdotetcsize = 3 * dotdots + taillen + 1; + dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1); if (dotdotetcsize <= linksize) { if (!result) result = emalloc(dotdotetcsize); @@ -1575,10 +1621,9 @@ associate(void) /* Read a text line from FP into BUF, which is of size BUFSIZE. Terminate it with a NUL byte instead of a newline. - Return the line's length, not counting the NUL byte. - On EOF, return a negative number. + Return true if successful, false if EOF. On error, report the error and exit. */ -static ptrdiff_t +static bool inputline(FILE *fp, char *buf, ptrdiff_t bufsize) { ptrdiff_t linelen = 0, ch; @@ -1589,7 +1634,7 @@ inputline(FILE *fp, char *buf, ptrdiff_t bufsize) exit(EXIT_FAILURE); } if (linelen == 0) - return -1; + return false; error(_("unterminated line")); exit(EXIT_FAILURE); } @@ -1604,7 +1649,7 @@ inputline(FILE *fp, char *buf, ptrdiff_t bufsize) } } buf[linelen] = '\0'; - return linelen; + return true; } static void @@ -1626,13 +1671,14 @@ infile(int fnum, char const *name) } wantcont = false; for (num = 1; ; ++num) { - ptrdiff_t linelen; - char buf[_POSIX2_LINE_MAX]; + enum { bufsize_bound + = (min(INT_MAX, min(PTRDIFF_MAX, SIZE_MAX)) + / FORMAT_LEN_GROWTH_BOUND) }; + char buf[min(_POSIX2_LINE_MAX, bufsize_bound)]; int nfields; char *fields[MAX_FIELDS]; eat(fnum, num); - linelen = inputline(fp, buf, sizeof buf); - if (linelen < 0) + if (!inputline(fp, buf, sizeof buf)) break; nfields = getfields(buf, fields, sizeof fields / sizeof *fields); @@ -1704,15 +1750,15 @@ gethms(char const *string, char const *errstring) default: ok = false; break; case 8: ok = '0' <= xr && xr <= '9'; - /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; case 7: ok &= ssx == '.'; if (ok && noise) warning(_("fractional seconds rejected by" " pre-2018 versions of zic")); - /* fallthrough */ - case 5: ok &= mmx == ':'; /* fallthrough */ - case 3: ok &= hhx == ':'; /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; + case 5: ok &= mmx == ':'; ATTRIBUTE_FALLTHROUGH; + case 3: ok &= hhx == ':'; ATTRIBUTE_FALLTHROUGH; case 1: break; } if (!ok) { @@ -1742,7 +1788,7 @@ getsave(char *field, bool *isdst) { int dst = -1; zic_t save; - size_t fieldlen = strlen(field); + ptrdiff_t fieldlen = strlen(field); if (fieldlen != 0) { char *ep = field + fieldlen - 1; switch (*ep) { @@ -1780,8 +1826,8 @@ inrule(char **fields, int nfields) fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD])) return; - r.r_name = ecpyalloc(fields[RF_NAME]); - r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); + r.r_name = estrdup(fields[RF_NAME]); + r.r_abbrvar = estrdup(fields[RF_ABBRVAR]); if (max_abbrvar_len < strlen(r.r_abbrvar)) max_abbrvar_len = strlen(r.r_abbrvar); rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); @@ -1838,7 +1884,7 @@ inzsub(char **fields, int nfields, bool iscont) register char * cp; char * cp1; struct zone z; - size_t format_len; + int format_len; register int i_stdoff, i_rule, i_format; register int i_untilyear, i_untilmonth; register int i_untilday, i_untiltime; @@ -1905,9 +1951,9 @@ inzsub(char **fields, int nfields, bool iscont) return false; } } - z.z_name = iscont ? NULL : ecpyalloc(fields[ZF_NAME]); - z.z_rule = ecpyalloc(fields[i_rule]); - z.z_format = cp1 = ecpyalloc(fields[i_format]); + z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]); + z.z_rule = estrdup(fields[i_rule]); + z.z_format = cp1 = estrdup(fields[i_format]); if (z.z_format_specifier == 'z') { cp1[cp - fields[i_format]] = 's'; if (noise) @@ -1924,7 +1970,7 @@ inzsub(char **fields, int nfields, bool iscont) } static zic_t -getleapdatetime(char **fields, int nfields, bool expire_line) +getleapdatetime(char **fields, bool expire_line) { register const char * cp; register const struct lookup * lp; @@ -2002,7 +2048,7 @@ inleap(char **fields, int nfields) if (nfields != LEAP_FIELDS) error(_("wrong number of fields on Leap line")); else { - zic_t t = getleapdatetime(fields, nfields, false); + zic_t t = getleapdatetime(fields, false); if (0 <= t) { struct lookup const *lp = byword(fields[LP_ROLL], leap_types); if (!lp) @@ -2030,7 +2076,7 @@ inexpires(char **fields, int nfields) else if (0 <= leapexpires) error(_("multiple Expires lines")); else - leapexpires = getleapdatetime(fields, nfields, true); + leapexpires = getleapdatetime(fields, true); } static void @@ -2050,8 +2096,8 @@ inlink(char **fields, int nfields) return; l.l_filenum = filenum; l.l_linenum = linenum; - l.l_target = ecpyalloc(fields[LF_TARGET]); - l.l_linkname = ecpyalloc(fields[LF_LINKNAME]); + l.l_target = estrdup(fields[LF_TARGET]); + l.l_linkname = estrdup(fields[LF_LINKNAME]); links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); links[nlinks++] = l; } @@ -2074,7 +2120,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, rp->r_month = lp->l_value; rp->r_todisstd = false; rp->r_todisut = false; - dp = ecpyalloc(timep); + dp = estrdup(timep); if (*dp != '\0') { ep = dp + strlen(dp) - 1; switch (lowerit(*ep)) { @@ -2153,7 +2199,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, ** Sun<=20 ** Sun>=7 */ - dp = ecpyalloc(dayp); + dp = estrdup(dayp); if ((lp = byword(dp, lasts)) != NULL) { rp->r_dycode = DC_DOWLEQ; rp->r_wday = lp->l_value; @@ -2216,7 +2262,7 @@ convert64(uint_fast64_t val, char *buf) } static void -puttzcode(const int_fast32_t val, FILE *const fp) +puttzcode(zic_t val, FILE *fp) { char buf[4]; @@ -2305,8 +2351,10 @@ writezone(const char *const name, const char *const string, char version, char const *outname = name; /* Allocate the ATS and TYPES arrays via a single malloc, - as this is a bit faster. */ - zic_t *ats = emalloc(align_to(size_product(timecnt, sizeof *ats + 1), + as this is a bit faster. Do not malloc(0) if !timecnt, + as that might return NULL even on success. */ + zic_t *ats = emalloc(align_to(size_product(timecnt + !timecnt, + sizeof *ats + 1), alignof(zic_t))); void *typesptr = ats + timecnt; unsigned char *types = typesptr; @@ -2739,13 +2787,13 @@ abbroffset(char *buf, zic_t offset) static char const disable_percent_s[] = ""; -static size_t +static ptrdiff_t doabbr(char *abbr, struct zone const *zp, char const *letters, bool isdst, zic_t save, bool doquotes) { register char * cp; register char * slashp; - register size_t len; + ptrdiff_t len; char const *format = zp->z_format; slashp = strchr(format, '/'); @@ -2911,9 +2959,9 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) register ptrdiff_t i; register int compat = 0; register int c; - size_t len; int offsetlen; struct rule stdr, dstr; + ptrdiff_t len; int dstcmp; struct rule *lastrp[2] = { NULL, NULL }; struct zone zstr[2]; @@ -3046,8 +3094,10 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) check_for_signal(); + /* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND. */ max_abbr_len = 2 + max_format_len + max_abbrvar_len; max_envvar_len = 2 * max_abbr_len + 5 * 9; + startbuf = emalloc(max_abbr_len + 1); ab = emalloc(max_abbr_len + 1); envvar = emalloc(max_envvar_len + 1); @@ -3547,7 +3597,7 @@ lowerit(char a) } /* case-insensitive equality */ -static ATTRIBUTE_PURE bool +static ATTRIBUTE_REPRODUCIBLE bool ciequal(register const char *ap, register const char *bp) { while (lowerit(*ap) == lowerit(*bp++)) @@ -3556,7 +3606,7 @@ ciequal(register const char *ap, register const char *bp) return false; } -static ATTRIBUTE_PURE bool +static ATTRIBUTE_REPRODUCIBLE bool itsabbr(register const char *abbr, register const char *word) { if (lowerit(*abbr) != lowerit(*word)) @@ -3572,7 +3622,7 @@ itsabbr(register const char *abbr, register const char *word) /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */ -static ATTRIBUTE_PURE bool +static ATTRIBUTE_REPRODUCIBLE bool ciprefix(char const *abbr, char const *word) { do @@ -3675,38 +3725,41 @@ getfields(char *cp, char **array, int arrayelts) return nsubs; } -static _Noreturn void +static ATTRIBUTE_NORETURN void time_overflow(void) { error(_("time overflow")); exit(EXIT_FAILURE); } -static ATTRIBUTE_PURE zic_t +static ATTRIBUTE_REPRODUCIBLE zic_t oadd(zic_t t1, zic_t t2) { - if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) - time_overflow(); - return t1 + t2; +#ifdef ckd_add + zic_t sum; + if (!ckd_add(&sum, t1, t2)) + return sum; +#else + if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1) + return t1 + t2; +#endif + time_overflow(); } -static ATTRIBUTE_PURE zic_t +static ATTRIBUTE_REPRODUCIBLE zic_t tadd(zic_t t1, zic_t t2) { - if (t1 < 0) { - if (t2 < min_time - t1) { - if (t1 != min_time) - time_overflow(); - return min_time; - } - } else { - if (max_time - t1 < t2) { - if (t1 != max_time) - time_overflow(); - return max_time; - } - } - return t1 + t2; +#ifdef ckd_add + zic_t sum; + if (!ckd_add(&sum, t1, t2) && min_time <= sum && sum <= max_time) + return sum; +#else + if (t1 < 0 ? min_time - t1 <= t2 : t2 <= max_time - t1) + return t1 + t2; +#endif + if (t1 == min_time || t1 == max_time) + return t1; + time_overflow(); } /* @@ -3830,10 +3883,8 @@ mp = _("time zone abbreviation differs from POSIX standard"); static void mkdirs(char const *argname, bool ancestors) { - register char * name; - register char * cp; - - cp = name = ecpyalloc(argname); + char *name = estrdup(argname); + char *cp = name; /* On MS-Windows systems, do not worry about drive letters or backslashes, as this should suffice in practice. Time zone diff --git a/zone.tab b/zone.tab index 2636e21..6e5adb9 100644 --- a/zone.tab +++ b/zone.tab @@ -114,8 +114,7 @@ CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) -CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) -CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) +CA +6344-06828 America/Iqaluit Eastern - NU (most areas) CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) @@ -277,17 +276,18 @@ MT +3554+01431 Europe/Malta MU -2010+05730 Indian/Mauritius MV +0410+07330 Indian/Maldives MW -1547+03500 Africa/Blantyre -MX +1924-09909 America/Mexico_City Central Time -MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo -MX +2058-08937 America/Merida Central Time - Campeche, Yucatan -MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas) -MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo Leon, Tamaulipas (US border) -MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa -MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) -MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) -MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora -MX +3232-11701 America/Tijuana Pacific Time US - Baja California -MX +2048-10515 America/Bahia_Banderas Central Time - Bahia de Banderas +MX +1924-09909 America/Mexico_City Central Mexico +MX +2105-08646 America/Cancun Quintana Roo +MX +2058-08937 America/Merida Campeche, Yucatan +MX +2540-10019 America/Monterrey Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Coahuila, Nuevo Leon, Tamaulipas (US border) +MX +2838-10605 America/Chihuahua Chihuahua (most areas) +MX +3144-10629 America/Ciudad_Juarez Chihuahua (US border - west) +MX +2934-10425 America/Ojinaga Chihuahua (US border - east) +MX +2313-10625 America/Mazatlan Baja California Sur, Nayarit (most areas), Sinaloa +MX +2048-10515 America/Bahia_Banderas Bahia de Banderas +MX +2904-11058 America/Hermosillo Sonora +MX +3232-11701 America/Tijuana Baja California MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula) MY +0133+11020 Asia/Kuching Sabah, Sarawak MZ -2558+03235 Africa/Maputo diff --git a/zone1970.tab b/zone1970.tab index 75372e3..a9b36d3 100644 --- a/zone1970.tab +++ b/zone1970.tab @@ -102,8 +102,7 @@ CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA,BS +4339-07923 America/Toronto Eastern - ON, QC (most areas), Bahamas -CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) -CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) +CA +6344-06828 America/Iqaluit Eastern - NU (most areas) CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) @@ -214,17 +213,18 @@ MQ +1436-06105 America/Martinique MT +3554+01431 Europe/Malta MU -2010+05730 Indian/Mauritius MV,TF +0410+07330 Indian/Maldives Maldives, Kerguelen, St Paul I, Amsterdam I -MX +1924-09909 America/Mexico_City Central Time -MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo -MX +2058-08937 America/Merida Central Time - Campeche, Yucatán -MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo León, Tamaulipas (most areas) -MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo León, Tamaulipas (US border) -MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa -MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) -MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) -MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora -MX +3232-11701 America/Tijuana Pacific Time US - Baja California -MX +2048-10515 America/Bahia_Banderas Central Time - Bahía de Banderas +MX +1924-09909 America/Mexico_City Central Mexico +MX +2105-08646 America/Cancun Quintana Roo +MX +2058-08937 America/Merida Campeche, Yucatán +MX +2540-10019 America/Monterrey Durango; Coahuila, Nuevo León, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Coahuila, Nuevo León, Tamaulipas (US border) +MX +2838-10605 America/Chihuahua Chihuahua (most areas) +MX +3144-10629 America/Ciudad_Juarez Chihuahua (US border - west) +MX +2934-10425 America/Ojinaga Chihuahua (US border - east) +MX +2313-10625 America/Mazatlan Baja California Sur, Nayarit (most areas), Sinaloa +MX +2048-10515 America/Bahia_Banderas Bahía de Banderas +MX +2904-11058 America/Hermosillo Sonora +MX +3232-11701 America/Tijuana Baja California MY,BN +0133+11020 Asia/Kuching Sabah, Sarawak, Brunei MZ,BI,BW,CD,MW,RW,ZM,ZW -2558+03235 Africa/Maputo Central Africa Time NA -2234+01706 Africa/Windhoek