From 7abdc14abd46937b4a3920723f3dd702ba617e61 Mon Sep 17 00:00:00 2001
From: Stuart Bishop
Date: Fri, 31 Jan 2025 12:02:28 +1100
Subject: [PATCH] Squashed 'tz/' changes from 6903dde39e..5ad5cfba5b
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
a8e2fcd87b Release 2025a
4ab8692704 Fix bugs in -Wcast-qual pacification
1ee9daa918 Pacify gcc -Wcast-qual
e8920e76fc Rename emalloc to xmalloc.
cda7ec0702 Alias asctime, ctime result
edbabecc14 Fix ctime conformace bug
7db03d5b98 Add missing zdump.o dependency
e8e1a3d25b NetBSD defines STD_INSPIRED functions
d89a7468e3 newctime doc improvements
da932ff7ec Stop using \*- in man pages
b6adb83ce3 Warn about 2-digit years in strftime man page
562a1f1631 Modernize date man page
9ab3f52d34 No leap second on 2025-06-30
e5aaf1c7fe For timestamps compare to HEAD not to index
aa8a059d13 State the duplicate guideline more clearly
cb537f2001 Suggest -Dssize_t=int, not long
352dcdf9e3 Port S_ISREG to ancient UNIX, recent MS-Windows
3411494cc7 Define _CRT_DECLARE_NONSTDC_NAMES for MS-Windows
7d776e798c Port ‘utc’ to MS-Windows
7c90916644 Define NOMINMAX for MS-Windows
94931e3006 Fix asctime.o, strftime.o dependencies
d23b9bf5fd Fix to2050.tzs timestamp in distributed tarball
24a4d97fc0 'zdump -' now reads from stdin
6d77c92872 Bring back zdump on a pipe
f5d6c1d7d9 Invalid TZ now abbreviates as "-00" not "UTC"
a7ad244f30 Check for TZ naming a device
43cc9b6149 Fix unlikely multithreaded file descriptor leak
b208d5841e Etc/Unknown is now reserved
13bc796952 Update USDOT map description
de6dab1b23 Fix checknow confusing diagnostics
5e95797d9a * tz-link.html: Mention DoT geodata (thanks to Roozbeh Pournader).
3862447e2d Optimize asctime snprintf calls
161563657b Port recent asctime snprintf changes to NetBSD
e6d6bc3e45 Pacify gcc -Wsuggest-attribute=format sans snprintf in zdump
9955786265 TZNAME_MAXIMUM defaults to 254, not 255
fe5be99d8d Be more consistent about macro true/false vs 1/0
3d5e7acb88 Port asctime_r to POSIX.1-2017 and earlier
31f483a149 Remove dependency of asctime on strftime
7ef7ed06b2 Simplify timeoff redefinition
1bd67a4b75 Move MKTIME_MIGHT_OVERFLOW definition
67f7e8ab9c Pacify GCC 15ish -Wzero-as-null-pointer-constant
535a4e8b25 Pacify GCC 15ish -Wleading-whitespace=blanks
59ae22db9b Revert zone.tab changes for Concordia, EBO
abb83041a2 Fix mktime/timeoff overflow bug
0706ef0bf8 Move iinntt definition
fa004d323c Add two research stations to zone*.tab
38eea0e263 Reorder australia comments
77820eb701 Mention the Eyre Bird Observatory
d9e7a42f11 Avoid time_t + int overflow
ea814e998d strftime %s no longer is limited to time_t range
b2ee68e092 Simplify AmigaOS support
41e5344e6f Fix bug near the year 2**31 - 1 - 1900
4e1de2496e Pacify gcc -Wsuggest-attribute=const
ebd2ed9235 Don’t define _FILE_OFFSET_BITS if _TIME_BITS
26a649a19e Improve zdump overflow checking
81bab74a7f * northamerica: Also mention Sandford Fleming and Cleveland Abbe.
cfacf5ea70 strftime now outputs unknown conversions as-is
9c8221d79c * private.h: Fix timeoff comment.
705dc023c2 Remove now-dead strftime code
d8b6fe65c9 Fix Asia/Manila post-1990 typo
3a83f10003 * NEWS, europe: Belated thanks for Ittoqqortoormiit 2024 fix
17fbd40e5c * NEWS: Belated thanks for Palestine 2072-2075 fix
493df554af Prefer www.rfc-editor.org for RFCs
9db906a00f Switch from RFC 8536 to 9636 for documentation
be62d59182 Talk a bit more about tm_isdst's obsolescence
258a3775c0 tzfile man page editorial changes
af54a9e896 Port better to glibc when used internally there
486e1e890e Paraguay tm_isdst flag goes to 0 today
636e6f983b Paraguay adopts permanent -03 starting spring 2024
e6258faabc Concordia can use Asia/Singapore
19b35d7db2 More changes for global-tz convenience
07731a9f6a "j" could mean June, too
66183d1e25 Fix "many" typo in NEWS
96fa7b7dd4 Document month, weekday names better
7b6fb155ca Improve style checks for months
926b507fa5 "Apr", not "April", in IN column
d4c65d53b9 Improve historical data for the Philippines
git-subtree-dir: tz
git-subtree-split: 5ad5cfba5b092fe6abdc6870438cc09bcffbdd4b
---
Makefile | 32 +--
NEWS | 84 +++++++-
antarctica | 2 +
asctime.c | 118 ++++++-----
asia | 113 ++++++++---
australasia | 113 ++++++-----
checknow.awk | 2 +-
checktab.awk | 39 +++-
date.1 | 122 ++---------
etcetera | 4 +
europe | 2 +-
factory | 10 +
leap-seconds.list | 8 +-
localtime.c | 507 +++++++++++++++++++++++++++++-----------------
newctime.3 | 152 +++++++-------
newstrftime.3 | 86 ++++----
newtzset.3 | 24 +--
northamerica | 9 +-
private.h | 119 +++++++----
southamerica | 27 ++-
strftime.c | 83 ++++++--
theory.html | 40 ++--
time2posix.3 | 4 +-
tz-link.html | 37 ++--
tzfile.5 | 72 ++++---
tzfile.h | 2 +-
tzselect.8 | 26 ++-
zdump.8 | 41 ++--
zdump.c | 62 +++---
zic.8 | 153 +++++++-------
zic.c | 61 +++---
zone.tab | 2 +-
zone1970.tab | 6 +-
zonenow.tab | 9 +-
34 files changed, 1288 insertions(+), 883 deletions(-)
diff --git a/Makefile b/Makefile
index 0087b459..2130582c 100644
--- a/Makefile
+++ b/Makefile
@@ -137,7 +137,7 @@ TIME_T_ALTERNATIVES_TAIL = int_least32_t.ck uint_least32_t.ck \
uint_least64_t.ck
# What kind of TZif data files to generate. (TZif is the binary time
-# zone data format that zic generates; see Internet RFC 8536.)
+# zone data format that zic generates; see Internet RFC 9636.)
# If you want only POSIX time, with time values interpreted as
# seconds since the epoch (not counting leap seconds), use
# REDO= posix_only
@@ -255,6 +255,7 @@ LDLIBS=
# -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
+# -DMKTIME_MIGHT_OVERFLOW if mktime might fail due to time_t overflow
# -DPORT_TO_C89 if tzcode should also run on mostly-C89 platforms+
# Typically it is better to use a later standard. For example,
# with GCC 4.9.4 (2016), prefer '-std=gnu11' to '-DPORT_TO_C89'.
@@ -262,7 +263,7 @@ LDLIBS=
# feature (integers at least 64 bits wide) and maybe more.
# -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers
# with external linkage, e.g., applications cannot define 'localtime'.
-# -Dssize_t=long on hosts like MS-Windows that lack ssize_t
+# -Dssize_t=int on hosts like MS-Windows that lack ssize_t
# -DSUPPORT_C89=0 if the tzcode library should not support C89 callers
# Although -DSUPPORT_C89=0 might work around latent bugs in callers,
# it does not conform to POSIX.
@@ -285,7 +286,7 @@ LDLIBS=
# This mishandles some past timestamps, as US DST rules have changed.
# It also mishandles settings like TZ='EET-2EEST' for eastern Europe,
# as Europe and US DST rules differ.
-# -DTZNAME_MAXIMUM=N to limit time zone abbreviations to N bytes (default 255)
+# -DTZNAME_MAXIMUM=N to limit time zone abbreviations to N bytes (default 254)
# -DUNINIT_TRAP if reading uninitialized storage can cause problems
# other than simply getting garbage data
# -DUSE_LTZ=0 to build zdump with the system time zone library
@@ -319,7 +320,8 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \
$(GCC_INSTRUMENT) \
-Wall -Wextra \
-Walloc-size-larger-than=100000 -Warray-bounds=2 \
- -Wbad-function-cast -Wbidi-chars=any,ucn -Wcast-align=strict -Wdate-time \
+ -Wbad-function-cast -Wbidi-chars=any,ucn -Wcast-align=strict -Wcast-qual \
+ -Wdate-time \
-Wdeclaration-after-statement -Wdouble-promotion \
-Wduplicated-branches -Wduplicated-cond -Wflex-array-member-not-at-end \
-Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \
@@ -336,7 +338,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \
-Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \
-Wtrampolines -Wundef -Wunused-macros -Wuse-after-free=3 \
-Wvariadic-macros -Wvla -Wwrite-strings \
- -Wno-format-nonliteral -Wno-sign-compare
+ -Wno-format-nonliteral -Wno-sign-compare -Wno-type-limits
#
# If your system has a "GMT offset" field in its "struct tm"s
# (or if you decide to add such a field in your system's "time.h" file),
@@ -614,8 +616,8 @@ TZS_YEAR= 2050
TZS_CUTOFF_FLAG= -c $(TZS_YEAR)
TZS= to$(TZS_YEAR).tzs
TZS_NEW= to$(TZS_YEAR)new.tzs
-TZS_DEPS= $(YDATA) asctime.c localtime.c \
- private.h tzfile.h zdump.c zic.c
+TZS_DEPS= $(YDATA) localtime.c private.h \
+ strftime.c tzfile.h zdump.c zic.c
TZDATA_DIST = $(COMMON) $(DATA) $(MISC)
# EIGHT_YARDS is just a yard short of the whole ENCHILADA.
EIGHT_YARDS = $(TZDATA_DIST) $(DOCS) $(SOURCES) tzdata.zi
@@ -855,10 +857,10 @@ tzselect: tzselect.ksh version
chmod +x $@.out
mv $@.out $@
-check: check_mild back.ck
+check: check_mild back.ck now.ck
check_mild: check_web check_zishrink \
character-set.ck white-space.ck links.ck mainguard.ck \
- name-lengths.ck now.ck slashed-abbrs.ck sorted.ck \
+ name-lengths.ck slashed-abbrs.ck sorted.ck \
tables.ck ziguard.ck tzs.ck
# True if UTF8_LOCALE does not work;
@@ -1103,7 +1105,7 @@ set-timestamps.out: $(EIGHT_YARDS)
touch -md @1 test.out; then \
rm -f test.out && \
for file in $$files; do \
- if git diff --quiet $$file; then \
+ if git diff --quiet HEAD $$file; then \
time=$$(TZ=UTC0 git log -1 \
--format='tformat:%cd' \
--date='format:%Y-%m-%dT%H:%M:%SZ' \
@@ -1354,13 +1356,13 @@ long-long.ck unsigned.ck: $(VERSION_DEPS)
zonenames: tzdata.zi
@$(AWK) '/^Z/ { print $$2 } /^L/ { print $$3 }' tzdata.zi
-asctime.o: private.h tzfile.h
+asctime.o: private.h
date.o: private.h
difftime.o: private.h
-localtime.o: private.h tzfile.h tzdir.h
-strftime.o: private.h tzfile.h
-zdump.o: version.h
-zic.o: private.h tzfile.h tzdir.h version.h
+localtime.o: private.h tzdir.h tzfile.h
+strftime.o: localtime.c private.h tzdir.h tzfile.h
+zdump.o: private.h version.h
+zic.o: private.h tzdir.h tzfile.h version.h
.PHONY: ALL INSTALL all
.PHONY: check check_mild check_time_t_alternatives
diff --git a/NEWS b/NEWS
index 83b8b8c8..a5d7ea89 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,83 @@
News for the tz database
+Release 2025a - 2025-01-15 10:47:24 -0800
+
+ Briefly:
+ Paraguay adopts permanent -03 starting spring 2024.
+ Improve pre-1991 data for the Philippines.
+ Etc/Unknown is now reserved.
+
+ Changes to future timestamps
+
+ Paraguay will stop changing its clocks after the spring-forward
+ transition on 2024-10-06, so it is now permanently at -03.
+ (Thanks to Heitor David Pinto and Even Scharning.)
+ This affects timestamps starting 2025-03-22, as well as the
+ obsolescent tm_isdst flags starting 2024-10-15.
+
+ Changes to past timestamps
+
+ Correct timestamps for the Philippines before 1900, and from 1937
+ through 1990. (Thanks to P Chan for the heads-up and citations.)
+ This includes adjusting local mean time before 1899; fixing
+ transitions in September 1899, January 1937, and June 1954; adding
+ transitions in December 1941, November 1945, March and September
+ 1977, and May and July 1990; and removing incorrect transitions in
+ March and September 1978.
+
+ Changes to data
+
+ Add zone1970.tab lines for the Concordia and Eyre Bird Observatory
+ research stations. (Thanks to Derick Rethans and Jule Dabars.)
+
+ Changes to code
+
+ strftime %s now generates the correct numeric string even when the
+ represented number does not fit into time_t. This is better than
+ generating the numeric equivalent of (time_t) -1, as strftime did
+ in TZDB releases 96a (when %s was introduced) through 2020a and in
+ releases 2022b through 2024b. It is also better than failing and
+ returning 0, as strftime did in releases 2020b through 2022a.
+
+ strftime now outputs an invalid conversion specifier as-is,
+ instead of eliding the leading '%', which confused debugging.
+
+ An invalid TZ now generates the time zone abbreviation "-00", not
+ "UTC", to help the user see that an error has occurred. (Thanks
+ to Arthur David Olson for suggesting a "wrong result".)
+
+ mktime and timeoff no longer incorrectly fail merely because a
+ struct tm component near INT_MIN or INT_MAX overflows when a
+ lower-order component carries into it.
+
+ TZNAME_MAXIMUM, the maximum number of bytes in a proleptic TZ
+ string's time zone abbreviation, now defaults to 254 not 255.
+ This helps reduce the size of internal state from 25480 to 21384
+ on common platforms. This change should not be a problem, as
+ nobody uses such long "abbreviations" and the longstanding tzcode
+ maximum was 16 until release 2023a. For those who prefer no
+ arbitrary limits, you can now specify TZNAME_MAXIMUM values up to
+ PTRDIFF_MAX, a limit forced by C anyway; formerly tzcode silently
+ misbehaved unless TZNAME_MAXIMUM was less than INT_MAX.
+
+ tzset and related functions no longer leak a file descriptor if
+ another thread forks or execs at about the same time and if the
+ platform has O_CLOFORK and O_CLOEXEC respectively. Also, the
+ functions no longer let a TZif file become a controlling terminal.
+
+ 'zdump -' now reads TZif data from /dev/stdin.
+ (From a question by Arthur David Olson.)
+
+ Changes to documentation
+
+ The name Etc/Unknown is now reserved: it will not be used by TZDB.
+ This is for compatibility with CLDR, which uses the string
+ "Etc/Unknown" for an unknown or invalid timezone. (Thanks to
+ Justin Grant, Mark Davis, and Guy Harris.)
+
+ Cite Internet RFC 9636, which obsoletes RFC 8536 for TZif format.
+
+
Release 2024b - 2024-09-04 12:27:47 -0700
Briefly:
@@ -116,7 +194,7 @@ Release 2024b - 2024-09-04 12:27:47 -0700
Changes to commentary
Commentary about historical transitions in Portugal and her former
- colonies has been expanded with links to many relevant legislation.
+ colonies has been expanded with links to relevant legislation.
(Thanks to Tim Parenti.)
@@ -204,10 +282,10 @@ Release 2023d - 2023-12-21 20:02:24 -0800
changing its time zone from -01/+00 to -02/-01 at the same moment
as the spring-forward transition. Its clocks will therefore not
spring forward as previously scheduled. The time zone change
- reverts to its common practice before 1981.
+ reverts to its common practice before 1981. (Thanks to Jule Dabars.)
Fix predictions for DST transitions in Palestine in 2072-2075,
- correcting a typo introduced in 2023a.
+ correcting a typo introduced in 2023a. (Thanks to Jule Dabars.)
Changes to past and future timestamps
diff --git a/antarctica b/antarctica
index 8d5d6cd1..2e90a5e0 100644
--- a/antarctica
+++ b/antarctica
@@ -174,6 +174,8 @@ Zone Antarctica/Mawson 0 - -00 1954 Feb 13
# France & Italy - year-round base
# Concordia, -750600+1232000, since 2005
+# https://en.wikipedia.org/wiki/Concordia_Station
+# Can use Asia/Singapore, which it has agreed with since inception.
# Germany - year-round base
# Neumayer III, -704080-0081602, since 2009
diff --git a/asctime.c b/asctime.c
index f75ec868..491d23bf 100644
--- a/asctime.c
+++ b/asctime.c
@@ -7,6 +7,7 @@
/*
** Avoid the temptation to punt entirely to strftime;
+** strftime can behave badly when tm components are out of range, and
** the output of strftime is supposed to be locale specific
** whereas the output of asctime is supposed to be constant.
*/
@@ -16,27 +17,6 @@
#include "private.h"
#include
-/*
-** All years associated with 32-bit time_t values are exactly four digits long;
-** some years associated with 64-bit time_t values are not.
-** Vintage programs are coded for years that are always four digits long
-** and may assume that the newline always lands in the same place.
-** For years that are less than four digits, we pad the output with
-** leading zeroes to get the newline in the traditional place.
-** The -4 ensures that we get four characters of output even if
-** we call a strftime variant that produces fewer characters for some years.
-** This conforms to recent ISO C and POSIX standards, which say behavior
-** is undefined when the year is less than 1000 or greater than 9999.
-*/
-static char const ASCTIME_FMT[] = "%s %s%3d %.2d:%.2d:%.2d %-4s\n";
-/*
-** For years that are more than four digits we put extra spaces before the year
-** so that code trying to overwrite the newline won't end up overwriting
-** a digit within a year and truncating the year (operating on the assumption
-** that no output is better than wrong output).
-*/
-static char const ASCTIME_FMT_B[] = "%s %s%3d %.2d:%.2d:%.2d %s\n";
-
enum { STD_ASCTIME_BUF_SIZE = 26 };
/*
** Big enough for something such as
@@ -50,14 +30,24 @@ enum { STD_ASCTIME_BUF_SIZE = 26 };
*/
static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1];
-/* A similar buffer for ctime.
- C89 requires that they be the same buffer.
- This requirement was removed in C99, so support it only if requested,
- as support is more likely to lead to bugs in badly written programs. */
-#if SUPPORT_C89
-# define buf_ctime buf_asctime
-#else
-static char buf_ctime[sizeof buf_asctime];
+/* On pre-C99 platforms, a snprintf substitute good enough for us. */
+#if !HAVE_SNPRINTF
+# include
+ATTRIBUTE_FORMAT((printf, 3, 4)) static int
+my_snprintf(char *s, size_t size, char const *format, ...)
+{
+ int n;
+ va_list args;
+ char stackbuf[sizeof buf_asctime];
+ va_start(args, format);
+ n = vsprintf(stackbuf, format, args);
+ va_end (args);
+ if (0 <= n && n < size)
+ memcpy (s, stackbuf, n + 1);
+ return n;
+}
+# undef snprintf
+# define snprintf my_snprintf
#endif
/* Publish asctime_r and ctime_r only when supporting older POSIX. */
@@ -84,12 +74,17 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf)
};
register const char * wn;
register const char * mn;
- char year[INT_STRLEN_MAXIMUM(int) + 2];
- char result[sizeof buf_asctime];
+ int year, mday, hour, min, sec;
+ long long_TM_YEAR_BASE = TM_YEAR_BASE;
+ size_t bufsize = (buf == buf_asctime
+ ? sizeof buf_asctime : STD_ASCTIME_BUF_SIZE);
if (timeptr == NULL) {
+ strcpy(buf, "??? ??? ?? ??:??:?? ????\n");
+ /* Set errno now, since strcpy might change it in
+ POSIX.1-2017 and earlier. */
errno = EINVAL;
- return strcpy(buf, "??? ??? ?? ??:??:?? ????\n");
+ return buf;
}
if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
wn = "???";
@@ -97,25 +92,41 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf)
if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
mn = "???";
else mn = mon_name[timeptr->tm_mon];
- /*
- ** Use strftime's %Y to generate the year, to avoid overflow problems
- ** when computing timeptr->tm_year + TM_YEAR_BASE.
- ** Assume that strftime is unaffected by other out-of-range members
- ** (e.g., timeptr->tm_mday) when processing "%Y".
- */
- strftime(year, sizeof year, "%Y", timeptr);
- /*
- ** We avoid using snprintf since it's not available on all systems.
- */
- sprintf(result,
- ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
- wn, mn,
- timeptr->tm_mday, timeptr->tm_hour,
- timeptr->tm_min, timeptr->tm_sec,
- year);
- if (strlen(result) < STD_ASCTIME_BUF_SIZE
- || buf == buf_ctime || buf == buf_asctime)
- return strcpy(buf, result);
+
+ year = timeptr->tm_year;
+ mday = timeptr->tm_mday;
+ hour = timeptr->tm_hour;
+ min = timeptr->tm_min;
+ sec = timeptr->tm_sec;
+
+ /* Vintage programs are coded for years that are always four bytes long
+ and may assume that the newline always lands in the same place.
+ For years that are less than four bytes, pad the output with
+ leading zeroes to get the newline in the traditional place.
+ For years longer than four bytes, put extra spaces before the year
+ so that vintage code trying to overwrite the newline
+ won't overwrite a digit within a year and truncate the year,
+ using the principle that no output is better than wrong output.
+ This conforms to ISO C and POSIX standards, which say behavior
+ is undefined when the year is less than 1000 or greater than 9999.
+
+ Also, avoid overflow when formatting tm_year + TM_YEAR_BASE. */
+
+ if ((year <= LONG_MAX - TM_YEAR_BASE
+ ? snprintf (buf, bufsize,
+ ((-999 - TM_YEAR_BASE <= year
+ && year <= 9999 - TM_YEAR_BASE)
+ ? "%s %s%3d %.2d:%.2d:%.2d %04ld\n"
+ : "%s %s%3d %.2d:%.2d:%.2d %ld\n"),
+ wn, mn, mday, hour, min, sec,
+ year + long_TM_YEAR_BASE)
+ : snprintf (buf, bufsize,
+ "%s %s%3d %.2d:%.2d:%.2d %d%d\n",
+ wn, mn, mday, hour, min, sec,
+ year / 10 + TM_YEAR_BASE / 10,
+ year % 10))
+ < bufsize)
+ return buf;
else {
errno = EOVERFLOW;
return NULL;
@@ -140,5 +151,8 @@ ctime_r(const time_t *timep, char *buf)
char *
ctime(const time_t *timep)
{
- return ctime_r(timep, buf_ctime);
+ /* Do not call localtime_r, as C23 requires ctime to initialize the
+ static storage that localtime updates. */
+ struct tm *tmp = localtime(timep);
+ return tmp ? asctime(tmp) : NULL;
}
diff --git a/asia b/asia
index a2480b02..d4eb0580 100644
--- a/asia
+++ b/asia
@@ -3665,21 +3665,70 @@ Zone Asia/Hebron 2:20:23 - LMT 1900 Oct
# be immediately followed by 1845-01-01; see R.H. van Gent's
# History of the International Date Line
# https://webspace.science.uu.nl/~gent0113/idl/idl_philippines.htm
-# The rest of the data entries are from Shanks & Pottenger.
-
-# From Jesper Nørgaard Welen (2006-04-26):
-# ... claims that Philippines had DST last time in 1990:
-# http://story.philippinetimes.com/p.x/ct/9/id/145be20cc6b121c0/cid/3e5bbccc730d258c/
-# [a story dated 2006-04-25 by Cris Larano of Dow Jones Newswires,
-# but no details]
-
-# From Paul Eggert (2014-08-14):
-# The following source says DST may be instituted November-January and again
-# March-June, but this is not definite. It also says DST was last proclaimed
-# during the Ramos administration (1992-1998); but again, no details.
-# Carcamo D. PNoy urged to declare use of daylight saving time.
-# Philippine Star 2014-08-05
-# http://www.philstar.com/headlines/2014/08/05/1354152/pnoy-urged-declare-use-daylight-saving-time
+
+# From P Chan (2021-05-10):
+# Here's a fairly comprehensive article in Japanese:
+# https://wiki.suikawiki.org/n/Philippine%20Time
+# (2021-05-16):
+# According to the references listed in the article,
+# the periods that the Philippines (Manila) observed DST or used +9 are:
+#
+# 1936-10-31 24:00 to 1937-01-15 24:00
+# (Proclamation No. 104, Proclamation No. 126)
+# 1941-12-15 24:00 to 1945-11-30 24:00
+# (Proclamation No. 789, Proclamation No. 20)
+# 1954-04-11 24:00 to 1954-06-04 24:00
+# (Proclamation No. 13, Proclamation No. 33)
+# 1977-03-27 24:00 to 1977-09-21 24:00
+# (Proclamation No. 1629, Proclamation No. 1641)
+# 1990-05-21 00:00 to 1990-07-28 24:00
+# (National Emergency Memorandum Order No. 17, Executive Order No. 415)
+#
+# Proclamation No. 104 ... October 30, 1936
+# https://www.officialgazette.gov.ph/1936/10/30/proclamation-no-104-s-1936/
+# Proclamation No. 126 ... January 15, 1937
+# https://www.officialgazette.gov.ph/1937/01/15/proclamation-no-126-s-1937/
+# Proclamation No. 789 ... December 13, 1941
+# https://www.officialgazette.gov.ph/1941/12/13/proclamation-no-789-s-1941/
+# Proclamation No. 20 ... November 11, 1945
+# https://www.officialgazette.gov.ph/1945/11/11/proclamation-no-20-s-1945/
+# Proclamation No. 13 ... April 6, 1954
+# https://www.officialgazette.gov.ph/1954/04/06/proclamation-no-13-s-1954/
+# Proclamation No. 33 ... June 3, 1954
+# https://www.officialgazette.gov.ph/1954/06/03/proclamation-no-33-s-1954/
+# Proclamation No. 1629 ... March 25, 1977
+# https://www.officialgazette.gov.ph/1977/03/25/proclamation-no-1629-s-1977/
+# Proclamation No. 1641 ...May 26, 1977
+# https://www.officialgazette.gov.ph/1977/05/26/proclamation-no-1641-s-1977/
+# National Emergency Memorandum Order No. 17 ... May 2, 1990
+# https://www.officialgazette.gov.ph/1990/05/02/national-emergency-memorandum-order-no-17-s-1990/
+# Executive Order No. 415 ... July 20, 1990
+# https://www.officialgazette.gov.ph/1990/07/20/executive-order-no-415-s-1990/
+#
+# During WWII, Proclamation No. 789 fixed two periods of DST. The first period
+# was set to continue only until January 31, 1942. But Manila was occupied by
+# the Japanese earlier in the month....
+#
+# For the date of the adoption of standard time, Shank[s] gives 1899-05-11.
+# The article is not able to state the basis of that. I guess it was based on
+# a US War Department Circular issued on that date.
+# https://books.google.com/books?id=JZ1PAAAAYAAJ&pg=RA3-PA8
+#
+# However, according to other sources, standard time was adopted on
+# 1899-09-06. Also, the LMT was GMT+8:03:52
+# https://books.google.com/books?id=MOYIAQAAIAAJ&pg=PA521
+# https://books.google.com/books?id=lSnqqatpYikC&pg=PA21
+#
+# From Paul Eggert (2024-09-05):
+# The penultimate URL in P Chan's email refers to page 521 of
+# Selga M, The Time Service in the Philippines.
+# Proc Pan-Pacific Science Congress. Vol. 1 (1923), 519-532.
+# It says, "The change from the meridian 120° 58' 04" to the 120th implied a
+# change of 3 min. 52s.26 in time; consequently on 6th September, 1899,
+# Manila Observatory gave the noon signal 3 min. 52s.26 later than before".
+#
+# Wikipedia says the US declared Manila liberated on March 4, 1945;
+# this doesn't affect clocks, just our time zone abbreviation and DST flag.
# From Paul Goyette (2018-06-15) with URLs updated by Guy Harris (2024-02-15):
# In the Philippines, there is a national law, Republic Act No. 10535
@@ -3697,24 +3746,26 @@ Zone Asia/Hebron 2:20:23 - LMT 1900 Oct
# influence of the sources. There is no current abbreviation for DST,
# so use "PDT", the usual American style.
-# From P Chan (2021-05-10):
-# Here's a fairly comprehensive article in Japanese:
-# https://wiki.suikawiki.org/n/Philippine%20Time
-# From Paul Eggert (2021-05-10):
-# The info in the Japanese table has not been absorbed (yet) below.
-
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
-Rule Phil 1936 only - Nov 1 0:00 1:00 D
-Rule Phil 1937 only - Feb 1 0:00 0 S
-Rule Phil 1954 only - Apr 12 0:00 1:00 D
-Rule Phil 1954 only - Jul 1 0:00 0 S
-Rule Phil 1978 only - Mar 22 0:00 1:00 D
-Rule Phil 1978 only - Sep 21 0:00 0 S
+Rule Phil 1936 only - Oct 31 24:00 1:00 D
+Rule Phil 1937 only - Jan 15 24:00 0 S
+Rule Phil 1941 only - Dec 15 24:00 1:00 D
+# The following three rules were canceled by Japan:
+#Rule Phil 1942 only - Jan 31 24:00 0 S
+#Rule Phil 1942 only - Mar 1 0:00 1:00 D
+#Rule Phil 1942 only - Jun 30 24:00 0 S
+Rule Phil 1945 only - Nov 30 24:00 0 S
+Rule Phil 1954 only - Apr 11 24:00 1:00 D
+Rule Phil 1954 only - Jun 4 24:00 0 S
+Rule Phil 1977 only - Mar 27 24:00 1:00 D
+Rule Phil 1977 only - Sep 21 24:00 0 S
+Rule Phil 1990 only - May 21 0:00 1:00 D
+Rule Phil 1990 only - Jul 28 24:00 0 S
# Zone NAME STDOFF RULES FORMAT [UNTIL]
-Zone Asia/Manila -15:56:00 - LMT 1844 Dec 31
- 8:04:00 - LMT 1899 May 11
- 8:00 Phil P%sT 1942 May
- 9:00 - JST 1944 Nov
+Zone Asia/Manila -15:56:08 - LMT 1844 Dec 31
+ 8:03:52 - LMT 1899 Sep 6 4:00u
+ 8:00 Phil P%sT 1942 Feb 11 24:00
+ 9:00 - JST 1945 Mar 4
8:00 Phil P%sT
# Bahrain
diff --git a/australasia b/australasia
index 359f9c1f..40594453 100644
--- a/australasia
+++ b/australasia
@@ -1239,10 +1239,10 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila
# The 1992 ending date used in the rules is a best guess;
# it matches what was used in the past.
-# The Australian Bureau of Meteorology FAQ
-# http://www.bom.gov.au/faq/faqgen.htm
-# (1999-09-27) writes that Giles Meteorological Station uses
-# South Australian time even though it's located in Western Australia.
+# From Christopher Hunt (2006-11-21), after an advance warning
+# from Jesper Nørgaard Welen (2006-11-01):
+# WA are trialing DST for three years.
+# http://www.parliament.wa.gov.au/parliament/bills.nsf/9A1B183144403DA54825721200088DF1/$File/Bill175-1B.pdf
# From Paul Eggert (2018-04-01):
# The Guardian Express of Perth, Australia reported today that the
@@ -1254,54 +1254,10 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila
# https://www.communitynews.com.au/guardian-express/news/exclusive-daylight-savings-coming-wa-summer-2018/
# [The article ends with "Today's date is April 1."]
-# Queensland
-
-# From Paul Eggert (2018-02-26):
-# I lack access to the following source for Queensland DST:
-# Pearce C. History of daylight saving time in Queensland.
-# Queensland Hist J. 2017 Aug;23(6):389-403
-# https://search.informit.com.au/documentSummary;dn=994682348436426;res=IELHSS
-
-# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
-# # The state of QUEENSLAND.. [ Courtesy Qld. Dept Premier Econ&Trade Devel ]
-# # [ Dec 1990 ]
-# ...
-# Zone Australia/Queensland 10:00 AQ %sST
-# ...
-# Rule AQ 1971 only - Oct lastSun 2:00 1:00 D
-# Rule AQ 1972 only - Feb lastSun 3:00 0 E
-# Rule AQ 1989 max - Oct lastSun 2:00 1:00 D
-# Rule AQ 1990 max - Mar Sun>=1 3:00 0 E
-
-# From Bradley White (1989-12-24):
-# "Australia/Queensland" now observes daylight time (i.e. from
-# October 1989).
-
-# From Bradley White (1991-03-04):
-# A recent excerpt from an Australian newspaper...
-# ...Queensland...[has] agreed to end daylight saving
-# at 3am tomorrow (March 3)...
-
-# From John Mackin (1991-03-06):
-# I can certainly confirm for my part that Daylight Saving in NSW did in fact
-# end on Sunday, 3 March. I don't know at what hour, though. (It surprised
-# me.)
-
-# From Bradley White (1992-03-08):
-# ...there was recently a referendum in Queensland which resulted
-# in the experimental daylight saving system being abandoned. So, ...
-# ...
-# Rule QLD 1989 1991 - Oct lastSun 2:00 1:00 D
-# Rule QLD 1990 1992 - Mar Sun>=1 3:00 0 S
-# ...
-
-# From Arthur David Olson (1992-03-08):
-# The chosen rules the union of the 1971/1972 change and the 1989-1992 changes.
-
-# From Christopher Hunt (2006-11-21), after an advance warning
-# from Jesper Nørgaard Welen (2006-11-01):
-# WA are trialing DST for three years.
-# http://www.parliament.wa.gov.au/parliament/bills.nsf/9A1B183144403DA54825721200088DF1/$File/Bill175-1B.pdf
+# The Australian Bureau of Meteorology FAQ
+# http://www.bom.gov.au/faq/faqgen.htm
+# (1999-09-27) writes that Giles Meteorological Station uses
+# South Australian time even though it's located in Western Australia.
# From Rives McDow (2002-04-09):
# The most interesting region I have found consists of three towns on the
@@ -1359,6 +1315,59 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila
# For lack of better info, assume the tradition dates back to the
# introduction of standard time in 1895.
+# From Stuart Bishop (2024-11-12):
+# An article discussing the in-use but technically unofficial timezones
+# in the Western Australian portion of the Nullarbor Plain.
+# https://www.abc.net.au/news/2024-11-22/outback-wa-properties-strange-time-zones/104542494
+# From Paul Eggert (2024-11-12):
+# As the article says, the Eyre Bird Observatory and nearby sheep stations
+# can use Tokyo time. Other possibilities include Asia/Chita, Asia/Seoul,
+# and Asia/Jayapura.
+
+# Queensland
+
+# From Paul Eggert (2018-02-26):
+# I lack access to the following source for Queensland DST:
+# Pearce C. History of daylight saving time in Queensland.
+# Queensland Hist J. 2017 Aug;23(6):389-403
+# https://search.informit.com.au/documentSummary;dn=994682348436426;res=IELHSS
+
+# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
+# # The state of QUEENSLAND.. [ Courtesy Qld. Dept Premier Econ&Trade Devel ]
+# # [ Dec 1990 ]
+# ...
+# Zone Australia/Queensland 10:00 AQ %sST
+# ...
+# Rule AQ 1971 only - Oct lastSun 2:00 1:00 D
+# Rule AQ 1972 only - Feb lastSun 3:00 0 E
+# Rule AQ 1989 max - Oct lastSun 2:00 1:00 D
+# Rule AQ 1990 max - Mar Sun>=1 3:00 0 E
+
+# From Bradley White (1989-12-24):
+# "Australia/Queensland" now observes daylight time (i.e. from
+# October 1989).
+
+# From Bradley White (1991-03-04):
+# A recent excerpt from an Australian newspaper...
+# ...Queensland...[has] agreed to end daylight saving
+# at 3am tomorrow (March 3)...
+
+# From John Mackin (1991-03-06):
+# I can certainly confirm for my part that Daylight Saving in NSW did in fact
+# end on Sunday, 3 March. I don't know at what hour, though. (It surprised
+# me.)
+
+# From Bradley White (1992-03-08):
+# ...there was recently a referendum in Queensland which resulted
+# in the experimental daylight saving system being abandoned. So, ...
+# ...
+# Rule QLD 1989 1991 - Oct lastSun 2:00 1:00 D
+# Rule QLD 1990 1992 - Mar Sun>=1 3:00 0 S
+# ...
+
+# From Arthur David Olson (1992-03-08):
+# The chosen rules the union of the 1971/1972 change and the 1989-1992 changes.
+
# southeast Australia
#
diff --git a/checknow.awk b/checknow.awk
index 8b7881d2..450490ee 100644
--- a/checknow.awk
+++ b/checknow.awk
@@ -44,7 +44,7 @@ BEGIN {
END {
for (zone in zone_data) {
data = zone_data[zone]
- if (!zonenow[data]) {
+ if (data && !zonenow[data]) {
printf "Zone table should have one of:%s\n", zones[data]
zonenow[data] = zone # This suppresses duplicate diagnostics.
status = 1
diff --git a/checktab.awk b/checktab.awk
index 9a26e465..5fa60556 100644
--- a/checktab.awk
+++ b/checktab.awk
@@ -9,6 +9,19 @@ BEGIN {
if (!zone_table) zone_table = "zone1970.tab"
if (!want_warnings) want_warnings = -1
+ monthabbr["Jan"] = 1
+ monthabbr["Feb"] = 1
+ monthabbr["Mar"] = 1
+ monthabbr["Apr"] = 1
+ monthabbr["May"] = 1
+ monthabbr["Jun"] = 1
+ monthabbr["Jul"] = 1
+ monthabbr["Aug"] = 1
+ monthabbr["Sep"] = 1
+ monthabbr["Oct"] = 1
+ monthabbr["Nov"] = 1
+ monthabbr["Dec"] = 1
+
while (getline >"/dev/stderr"
+ status = 1
+ }
} else {
+ stdoff = $1
ruleUsed[$2] = 1
if ($3 ~ /%/) rulePercentUsed[$2] = 1
}
+
+ if (stdoff && stdoff !~ /^\-?1?[0-9](:[0-5][0-9](:[0-5][0-9])?)?$/) {
+ printf "%s:%d: unlikely STDOFF: %s\n", FILENAME, FNR, stdoff \
+ >>"/dev/stderr"
+ status = 1
+ }
+
if (tz && tz ~ /\// && tz !~ /^Etc\//) {
if (!tztab[tz] && FILENAME != "backward" \
&& zone_table != "zonenow.tab") {
diff --git a/date.1 b/date.1
index 01907bc7..3a02e7c2 100644
--- a/date.1
+++ b/date.1
@@ -6,15 +6,13 @@ date \- show and set date and time
.SH SYNOPSIS
.if n .nh
.if n .na
-.ie \n(.g .ds - \f(CR-\fP
-.el .ds - \-
.B date
[
-.B \*-u
+.B \-u
] [
-.B \*-c
+.B \-c
] [
-.B \*-r
+.B \-r
.I seconds
] [
.BI + format
@@ -35,7 +33,7 @@ command
without arguments writes the date and time to the standard output in
the form
.ce 1
-Wed Mar 8 14:54:40 EST 1989
+Sat Mar 8 14:54:40 EST 2025
.br
with
.B EST
@@ -49,99 +47,24 @@ If a command-line argument starts with a plus sign (\c
.q "\fB+\fP" ),
the rest of the argument is used as a
.I format
-that controls what appears in the output.
-In the format, when a percent sign (\c
-.q "\fB%\fP"
-appears,
-it and the character after it are not output,
-but rather identify part of the date or time
-to be output in a particular way
-(or identify a special character to output):
-.nf
-.sp
-.if t .in +.5i
-.if n .in +2
-.ta \w'%M\0\0'u +\w'Wed Mar 8 14:54:40 EST 1989\0\0'u
- Sample output Explanation
-%a Wed Abbreviated weekday name*
-%A Wednesday Full weekday name*
-%b Mar Abbreviated month name*
-%B March Full month name*
-%c Wed Mar 08 14:54:40 1989 Date and time*
-%C 19 Century
-%d 08 Day of month (always two digits)
-%D 03/08/89 Month/day/year (eight characters)
-%e 8 Day of month (leading zero blanked)
-%h Mar Abbreviated month name*
-%H 14 24-hour-clock hour (two digits)
-%I 02 12-hour-clock hour (two digits)
-%j 067 Julian day number (three digits)
-%k 2 12-hour-clock hour (leading zero blanked)
-%l 14 24-hour-clock hour (leading zero blanked)
-%m 03 Month number (two digits)
-%M 54 Minute (two digits)
-%n \\n newline character
-%p PM AM/PM designation
-%r 02:54:40 PM Hour:minute:second AM/PM designation
-%R 14:54 Hour:minute
-%S 40 Second (two digits)
-%t \\t tab character
-%T 14:54:40 Hour:minute:second
-%U 10 Sunday-based week number (two digits)
-%w 3 Day number (one digit, Sunday is 0)
-%W 10 Monday-based week number (two digits)
-%x 03/08/89 Date*
-%X 14:54:40 Time*
-%y 89 Last two digits of year
-%Y 1989 Year in full
-%z -0500 Numeric time zone
-%Z EST Time zone abbreviation
-%+ Wed Mar 8 14:54:40 EST 1989 Default output format*
-.if t .in -.5i
-.if n .in -2
-* The exact output depends on the locale.
-.sp
-.fi
-If a character other than one of those shown above appears after
-a percent sign in the format,
-that following character is output.
-All other characters in the format are copied unchanged to the output;
-a newline character is always added at the end of the output.
-.PP
-In Sunday-based week numbering,
-the first Sunday of the year begins week 1;
-days preceding it are part of
-.q "week 0" .
-In Monday-based week numbering,
-the first Monday of the year begins week 1.
-.PP
-To set the date, use a command line argument with one of the following forms:
-.nf
-.if t .in +.5i
-.if n .in +2
-.ta \w'198903081454\0'u
-1454 24-hour-clock hours (first two digits) and minutes
-081454 Month day (first two digits), hours, and minutes
-03081454 Month (two digits, January is 01), month day, hours, minutes
-8903081454 Year, month, month day, hours, minutes
-0308145489 Month, month day, hours, minutes, year
- (on System V-compatible systems)
-030814541989 Month, month day, hours, minutes, four-digit year
-198903081454 Four-digit year, month, month day, hours, minutes
-.if t .in -.5i
-.if n .in -2
-.fi
-If the century, year, month, or month day is not given,
-the current value is used.
-Any of the above forms may be followed by a period and two digits that give
-the seconds part of the new time; if no seconds are given, zero is assumed.
+that is processed by
+.BR strftime (3)
+to determine what to output;
+a newline character is appended.
+For example, the shell command:
+.ce 1
+date +"%Y\-%m\-%d %H:%M:%S %z"
+.br
+outputs a line like
+.q "2025\-03\-08 14:54:40 \-0500"
+instead.
.PP
These options are available:
.TP
-.BR \*-u " or " \*-c
+.BR \-u " or " \-c
Use Universal Time when setting and showing the date and time.
.TP
-.BI "\*-r " seconds
+.BI "\-r " seconds
Output the date that corresponds to
.I seconds
past the epoch of 1970-01-01 00:00:00 UTC, where
@@ -149,16 +72,13 @@ past the epoch of 1970-01-01 00:00:00 UTC, where
should be an integer, either decimal, octal (leading 0), or
hexadecimal (leading 0x), preceded by an optional sign.
.SH FILES
-.ta \w'/usr/share/zoneinfo/posixrules\0\0'u
+.ta \w'/usr/share/zoneinfo/Etc/UTC\0\0'u
/etc/localtime local timezone file
.br
/usr/lib/locale/\f2L\fP/LC_TIME description of time locale \f2L\fP
.br
/usr/share/zoneinfo timezone directory
.br
-/usr/share/zoneinfo/posixrules default DST rules (obsolete)
-.br
-/usr/share/zoneinfo/GMT for UTC leap seconds
-.PP
-If /usr/share/zoneinfo/GMT is absent,
-UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present.
+/usr/share/zoneinfo/Etc/UTC for UTC leap seconds
+.SH SEE ALSO
+.BR strftime (3).
diff --git a/etcetera b/etcetera
index a5ecd6de..948531c8 100644
--- a/etcetera
+++ b/etcetera
@@ -51,6 +51,10 @@ Link Etc/GMT GMT
# so we moved the names into the Etc subdirectory.
# Also, the time zone abbreviations are now compatible with %z.
+# There is no "Etc/Unknown" entry, as CLDR says that "Etc/Unknown"
+# corresponds to an unknown or invalid time zone, and things would get
+# confusing if Etc/Unknown were made valid here.
+
Zone Etc/GMT-14 14 - %z
Zone Etc/GMT-13 13 - %z
Zone Etc/GMT-12 12 - %z
diff --git a/europe b/europe
index f9063949..df334fc2 100644
--- a/europe
+++ b/europe
@@ -1147,7 +1147,7 @@ Zone Atlantic/Faroe -0:27:04 - LMT 1908 Jan 11 # Tórshavn
# However, Greenland will change to Daylight Saving Time again in 2024
# and onwards.
-# From a contributor who wishes to remain anonymous for now (2023-10-29):
+# From Jule Dabars (2023-10-29):
# https://www.dr.dk/nyheder/seneste/i-nat-skal-uret-stilles-en-time-tilbage-men-foerste-gang-sker-det-ikke-i-groenland
# with a link to that page:
# https://naalakkersuisut.gl/Nyheder/2023/10/2710_sommertid
diff --git a/factory b/factory
index 9f5fc330..433a6721 100644
--- a/factory
+++ b/factory
@@ -8,5 +8,15 @@
# time zone abbreviation "-00", indicating that the actual time zone
# is unknown.
+# TZ="Factory" was added to TZDB in 1989, and in 2016 its abbreviation
+# was changed to "-00" from a longish English-language error message.
+# Around 2010, CLDR added "Etc/Unknown" for use with TZDB, to stand
+# for an unknown or invalid time zone. These two notions differ:
+# TZ="Factory" is a valid timezone, so tzalloc("Factory") succeeds, whereas
+# TZ="Etc/Unknown" is invalid and tzalloc("Etc/Unknown") fails.
+# Also, a downstream distributor could modify Factory to be a
+# default timezone suitable for the devices it manufactures,
+# whereas that cannot happen for Etc/Unknown.
+
# Zone NAME STDOFF RULES FORMAT
Zone Factory 0 - -00
diff --git a/leap-seconds.list b/leap-seconds.list
index da0efc8c..6f861c88 100644
--- a/leap-seconds.list
+++ b/leap-seconds.list
@@ -60,15 +60,15 @@
#
# The following line shows the last update of this file in NTP timestamp:
#
-#$ 3929093563
+#$ 3945196800
#
# 2) Expiration date of the file given on a semi-annual basis: last June or last December
#
-# File expires on 28 June 2025
+# File expires on 28 December 2025
#
# Expire date in NTP timestamp:
#
-#@ 3960057600
+#@ 3975868800
#
#
# LIST OF LEAP SECONDS
@@ -117,4 +117,4 @@
# please see the readme file in the 'source' directory :
# https://hpiers.obspm.fr/iers/bul/bulc/ntp/sources/README
#
-#h be738595 57b0cf1b b0218343 fb77062f 5a775e7
+#h 848434d5 570f7ea8 d79ba227 a00fc821 f608e2d4
diff --git a/localtime.c b/localtime.c
index 7ae9ce5e..96737ca6 100644
--- a/localtime.c
+++ b/localtime.c
@@ -19,6 +19,14 @@
#include "tzfile.h"
#include
+#if HAVE_SYS_STAT_H
+# include
+#endif
+#if !defined S_ISREG && defined S_IFREG
+/* Ancient UNIX or recent MS-Windows. */
+# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+
#if defined THREAD_SAFE && THREAD_SAFE
# include
static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
@@ -29,6 +37,73 @@ static int lock(void) { return 0; }
static void unlock(void) { }
#endif
+/* Unless intptr_t is missing, pacify gcc -Wcast-qual on char const * exprs.
+ Use this carefully, as the casts disable type checking.
+ This is a macro so that it can be used in static initializers. */
+#ifdef INTPTR_MAX
+# define UNCONST(a) ((char *) (intptr_t) (a))
+#else
+# define UNCONST(a) ((char *) (a))
+#endif
+
+/* A signed type wider than int, so that we can add 1900 + tm_mon/12 to tm_year
+ without overflow. The static_assert checks that it is indeed wider
+ than int; if this fails on your platform please let us know. */
+#if INT_MAX < LONG_MAX
+typedef long iinntt;
+# define IINNTT_MIN LONG_MIN
+# define IINNTT_MAX LONG_MAX
+#elif INT_MAX < LLONG_MAX
+typedef long long iinntt;
+# define IINNTT_MIN LLONG_MIN
+# define IINNTT_MAX LLONG_MAX
+#else
+typedef intmax_t iinntt;
+# define IINNTT_MIN INTMAX_MIN
+# define IINNTT_MAX INTMAX_MAX
+#endif
+static_assert(IINNTT_MIN < INT_MIN && INT_MAX < IINNTT_MAX);
+
+/* On platforms where offtime or mktime might overflow,
+ strftime.c defines USE_TIMEX_T to be true and includes us.
+ This tells us to #define time_t to an internal type timex_t that is
+ wide enough so that strftime %s never suffers from integer overflow,
+ and to #define offtime (if TM_GMTOFF is defined) or mktime (otherwise)
+ to a static function that returns the redefined time_t.
+ It also tells us to define only data and code needed
+ to support the offtime or mktime variant. */
+#ifndef USE_TIMEX_T
+# define USE_TIMEX_T false
+#endif
+#if USE_TIMEX_T
+# undef TIME_T_MIN
+# undef TIME_T_MAX
+# undef time_t
+# define time_t timex_t
+# if MKTIME_FITS_IN(LONG_MIN, LONG_MAX)
+typedef long timex_t;
+# define TIME_T_MIN LONG_MIN
+# define TIME_T_MAX LONG_MAX
+# elif MKTIME_FITS_IN(LLONG_MIN, LLONG_MAX)
+typedef long long timex_t;
+# define TIME_T_MIN LLONG_MIN
+# define TIME_T_MAX LLONG_MAX
+# else
+typedef intmax_t timex_t;
+# define TIME_T_MIN INTMAX_MIN
+# define TIME_T_MAX INTMAX_MAX
+# endif
+
+# ifdef TM_GMTOFF
+# undef timeoff
+# define timeoff timex_timeoff
+# undef EXTERN_TIMEOFF
+# else
+# undef mktime
+# define mktime timex_mktime
+# endif
+#endif
+
#ifndef TZ_ABBR_CHAR_SET
# define TZ_ABBR_CHAR_SET \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
@@ -38,12 +113,23 @@ static void unlock(void) { }
# define TZ_ABBR_ERR_CHAR '_'
#endif /* !defined TZ_ABBR_ERR_CHAR */
-/*
-** Support non-POSIX platforms that distinguish between text and binary files.
-*/
+/* Port to platforms that lack some O_* flags. Unless otherwise
+ specified, the flags are standardized by POSIX. */
#ifndef O_BINARY
-# define O_BINARY 0
+# define O_BINARY 0 /* MS-Windows */
+#endif
+#ifndef O_CLOEXEC
+# define O_CLOEXEC 0
+#endif
+#ifndef O_CLOFORK
+# define O_CLOFORK 0
+#endif
+#ifndef O_IGNORE_CTTY
+# define O_IGNORE_CTTY 0 /* GNU/Hurd */
+#endif
+#ifndef O_NOCTTY
+# define O_NOCTTY 0
#endif
#ifndef WILDABBR
@@ -72,7 +158,10 @@ static void unlock(void) { }
static const char wildabbr[] = WILDABBR;
static char const etc_utc[] = "Etc/UTC";
+
+#if !USE_TIMEX_T || defined TM_ZONE || !defined TM_GMTOFF
static char const *utc = etc_utc + sizeof "Etc/" - 1;
+#endif
/*
** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
@@ -84,10 +173,31 @@ static char const *utc = etc_utc + sizeof "Etc/" - 1;
# define TZDEFRULESTRING ",M3.2.0,M11.1.0"
#endif
+/* Limit to time zone abbreviation length in proleptic TZ strings.
+ This is distinct from TZ_MAX_CHARS, which limits TZif file contents.
+ It defaults to 254, not 255, so that desigidx_type can be an unsigned char.
+ unsigned char suffices for TZif files, so the only reason to increase
+ TZNAME_MAXIMUM is to support TZ strings specifying abbreviations
+ longer than 254 bytes. There is little reason to do that, though,
+ as strings that long are hardly "abbreviations". */
+#ifndef TZNAME_MAXIMUM
+# define TZNAME_MAXIMUM 254
+#endif
+
+#if TZNAME_MAXIMUM < UCHAR_MAX
+typedef unsigned char desigidx_type;
+#elif TZNAME_MAXIMUM < INT_MAX
+typedef int desigidx_type;
+#elif TZNAME_MAXIMUM < PTRDIFF_MAX
+typedef ptrdiff_t desigidx_type;
+#else
+# error "TZNAME_MAXIMUM too large"
+#endif
+
struct ttinfo { /* time type information */
- int_fast32_t tt_utoff; /* UT offset in seconds */
+ int_least32_t tt_utoff; /* UT offset in seconds */
+ desigidx_type tt_desigidx; /* abbreviation list index */
bool tt_isdst; /* used to set tm_isdst */
- int tt_desigidx; /* abbreviation list index */
bool tt_ttisstd; /* transition is std time */
bool tt_ttisut; /* transition is UT */
};
@@ -106,12 +216,6 @@ static char const UNSPEC[] = "-00";
for ttunspecified to work without crashing. */
enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 };
-/* Limit to time zone abbreviation length in proleptic TZ strings.
- This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */
-#ifndef TZNAME_MAXIMUM
-# define TZNAME_MAXIMUM 255
-#endif
-
/* A representation of the contents of a TZif file. Ideally this
would have no size limits; the following sizes should suffice for
practical use. This struct should not be too large, as instances
@@ -151,7 +255,6 @@ static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
static bool increment_overflow(int *, int);
static bool increment_overflow_time(time_t *, int_fast32_t);
static int_fast32_t leapcorr(struct state const *, time_t);
-static bool normalize_overflow32(int_fast32_t *, int *, int);
static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
struct tm *);
static bool tzparse(char const *, struct state *, struct state const *);
@@ -172,8 +275,10 @@ static struct state *const gmtptr = &gmtmem;
# define TZ_STRLEN_MAX 255
#endif /* !defined TZ_STRLEN_MAX */
+#if !USE_TIMEX_T || !defined TM_GMTOFF
static char lcl_TZname[TZ_STRLEN_MAX + 1];
static int lcl_is_set;
+#endif
/*
** Section 4.12.3 of X3.159-1989 requires that
@@ -187,27 +292,29 @@ static int lcl_is_set;
** trigger latent bugs in programs.
*/
-#if SUPPORT_C89
+#if !USE_TIMEX_T
+
+# if SUPPORT_C89
static struct tm tm;
#endif
-#if 2 <= HAVE_TZNAME + TZ_TIME_T
-char * tzname[2] = {
- (char *) wildabbr,
- (char *) wildabbr
-};
-#endif
-#if 2 <= USG_COMPAT + TZ_TIME_T
+# if 2 <= HAVE_TZNAME + TZ_TIME_T
+char *tzname[2] = { UNCONST(wildabbr), UNCONST(wildabbr) };
+# endif
+# if 2 <= USG_COMPAT + TZ_TIME_T
long timezone;
int daylight;
-#endif
-#if 2 <= ALTZONE + TZ_TIME_T
+# endif
+# if 2 <= ALTZONE + TZ_TIME_T
long altzone;
+# endif
+
#endif
/* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */
static void
-init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx)
+init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst,
+ desigidx_type desigidx)
{
s->tt_utoff = utoff;
s->tt_isdst = isdst;
@@ -271,20 +378,22 @@ detzcode64(const char *const codep)
return result;
}
+#if !USE_TIMEX_T || !defined TM_GMTOFF
+
static void
update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
{
-#if HAVE_TZNAME
- tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx];
-#endif
-#if USG_COMPAT
+# if HAVE_TZNAME
+ tzname[ttisp->tt_isdst] = UNCONST(&sp->chars[ttisp->tt_desigidx]);
+# endif
+# if USG_COMPAT
if (!ttisp->tt_isdst)
timezone = - ttisp->tt_utoff;
-#endif
-#if ALTZONE
+# endif
+# if ALTZONE
if (ttisp->tt_isdst)
altzone = - ttisp->tt_utoff;
-#endif
+# endif
}
/* If STDDST_MASK indicates that SP's TYPE provides useful info,
@@ -315,18 +424,18 @@ settzname(void)
When STDDST_MASK becomes zero we can stop looking. */
int stddst_mask = 0;
-#if HAVE_TZNAME
- tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc);
+# if HAVE_TZNAME
+ tzname[0] = tzname[1] = UNCONST(sp ? wildabbr : utc);
stddst_mask = 3;
-#endif
-#if USG_COMPAT
+# endif
+# if USG_COMPAT
timezone = 0;
stddst_mask = 3;
-#endif
-#if ALTZONE
+# endif
+# if ALTZONE
altzone = 0;
stddst_mask |= 2;
-#endif
+# endif
/*
** And to get the latest time zone abbreviations into tzname. . .
*/
@@ -336,9 +445,9 @@ settzname(void)
for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--)
stddst_mask = may_update_tzname_etc(stddst_mask, sp, i);
}
-#if USG_COMPAT
+# if USG_COMPAT
daylight = stddst_mask >> 1 ^ 1;
-#endif
+# endif
}
/* Replace bogus characters in time zone abbreviations.
@@ -365,6 +474,8 @@ scrub_abbrs(struct state *sp)
return 0;
}
+#endif
+
/* Input buffer for data read from a compiled tz file. */
union input_buffer {
/* The first part of the buffer, interpreted as a header. */
@@ -399,11 +510,15 @@ union local_storage {
char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)];
};
-/* Load tz data from the file named NAME into *SP. Read extended
- format if DOEXTEND. Use *LSP for temporary storage. Return 0 on
+/* These tzload flags can be ORed together, and fit into 'char'. */
+enum { TZLOAD_FROMENV = 1 }; /* The TZ string came from the environment. */
+enum { TZLOAD_TZSTRING = 2 }; /* Read any newline-surrounded TZ string. */
+
+/* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS.
+ Use *LSP for temporary storage. Return 0 on
success, an errno value on failure. */
static int
-tzloadbody(char const *name, struct state *sp, bool doextend,
+tzloadbody(char const *name, struct state *sp, char tzloadflags,
union local_storage *lsp)
{
register int i;
@@ -454,9 +569,25 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
name = lsp->fullname;
}
- if (doaccess && access(name, R_OK) != 0)
- return errno;
- fid = open(name, O_RDONLY | O_BINARY);
+ if (doaccess && (tzloadflags & TZLOAD_FROMENV)) {
+ /* Check for security violations and for devices whose mere
+ opening could have unwanted side effects. Although these
+ checks are racy, they're better than nothing and there is
+ no portable way to fix the races. */
+ if (access(name, R_OK) < 0)
+ return errno;
+#ifdef S_ISREG
+ {
+ struct stat st;
+ if (stat(name, &st) < 0)
+ return errno;
+ if (!S_ISREG(st.st_mode))
+ return EINVAL;
+ }
+#endif
+ }
+ fid = open(name, (O_RDONLY | O_BINARY | O_CLOEXEC | O_CLOFORK
+ | O_IGNORE_CTTY | O_NOCTTY));
if (fid < 0)
return errno;
@@ -583,7 +714,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
correction must differ from the previous one's by 1
second or less, except that the first correction can be
any value; these requirements are more generous than
- RFC 8536, to allow future RFC extensions. */
+ RFC 9636, to allow future RFC extensions. */
if (! (i == 0
|| (prevcorr < corr
? corr == prevcorr + 1
@@ -634,7 +765,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
if (!version)
break;
}
- if (doextend && nread > 2 &&
+ if ((tzloadflags & TZLOAD_TZSTRING) && nread > 2 &&
up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
sp->typecnt + 2 <= TZ_MAX_TYPES) {
struct state *ts = &lsp->u.st;
@@ -709,23 +840,23 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
return 0;
}
-/* Load tz data from the file named NAME into *SP. Read extended
- format if DOEXTEND. Return 0 on success, an errno value on failure. */
+/* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS.
+ Return 0 on success, an errno value on failure. */
static int
-tzload(char const *name, struct state *sp, bool doextend)
+tzload(char const *name, struct state *sp, char tzloadflags)
{
#ifdef ALL_STATE
union local_storage *lsp = malloc(sizeof *lsp);
if (!lsp) {
return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
} else {
- int err = tzloadbody(name, sp, doextend, lsp);
+ int err = tzloadbody(name, sp, tzloadflags, lsp);
free(lsp);
return err;
}
#else
union local_storage ls;
- return tzloadbody(name, sp, doextend, &ls);
+ return tzloadbody(name, sp, tzloadflags, &ls);
#endif
}
@@ -1066,7 +1197,7 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
sp->leapcnt = basep->leapcnt;
memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis);
} else {
- load_ok = tzload(TZDEFRULES, sp, false) == 0;
+ load_ok = tzload(TZDEFRULES, sp, 0) == 0;
if (!load_ok)
sp->leapcnt = 0; /* So, we're off a little. */
}
@@ -1303,14 +1434,17 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
static void
gmtload(struct state *const sp)
{
- if (tzload(etc_utc, sp, true) != 0)
+ if (tzload(etc_utc, sp, TZLOAD_TZSTRING) != 0)
tzparse("UTC0", sp, NULL);
}
+#if !USE_TIMEX_T || !defined TM_GMTOFF
+
/* Initialize *SP to a value appropriate for the TZ setting NAME.
+ Respect TZLOADFLAGS.
Return 0 on success, an errno value on failure. */
static int
-zoneinit(struct state *sp, char const *name)
+zoneinit(struct state *sp, char const *name, char tzloadflags)
{
if (name && ! name[0]) {
/*
@@ -1325,7 +1459,7 @@ zoneinit(struct state *sp, char const *name)
strcpy(sp->chars, utc);
return 0;
} else {
- int err = tzload(name, sp, true);
+ int err = tzload(name, sp, tzloadflags);
if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL))
err = 0;
if (err == 0)
@@ -1344,13 +1478,15 @@ tzset_unlocked(void)
? lcl_is_set < 0
: 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
return;
-#ifdef ALL_STATE
+# ifdef ALL_STATE
if (! sp)
lclptr = sp = malloc(sizeof *lclptr);
-#endif /* defined ALL_STATE */
+# endif
if (sp) {
- if (zoneinit(sp, name) != 0)
- zoneinit(sp, "");
+ if (zoneinit(sp, name, TZLOAD_FROMENV | TZLOAD_TZSTRING) != 0) {
+ zoneinit(sp, "", 0);
+ strcpy(sp->chars, UNSPEC);
+ }
if (0 < lcl)
strcpy(lcl_TZname, name);
}
@@ -1358,6 +1494,9 @@ tzset_unlocked(void)
lcl_is_set = lcl;
}
+#endif
+
+#if !USE_TIMEX_T
void
tzset(void)
{
@@ -1366,6 +1505,7 @@ tzset(void)
tzset_unlocked();
unlock();
}
+#endif
static void
gmtcheck(void)
@@ -1384,14 +1524,14 @@ gmtcheck(void)
unlock();
}
-#if NETBSD_INSPIRED
+#if NETBSD_INSPIRED && !USE_TIMEX_T
timezone_t
tzalloc(char const *name)
{
timezone_t sp = malloc(sizeof *sp);
if (sp) {
- int err = zoneinit(sp, name);
+ int err = zoneinit(sp, name, TZLOAD_TZSTRING);
if (err != 0) {
free(sp);
errno = err;
@@ -1420,6 +1560,8 @@ tzfree(timezone_t sp)
#endif
+#if !USE_TIMEX_T || !defined TM_GMTOFF
+
/*
** The easy way to behave "as if no library function calls" localtime
** is to not call it, so we drop its guts into "localsub", which can be
@@ -1474,14 +1616,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 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
+# else
register int_fast64_t newy;
newy = result->tm_year;
@@ -1491,7 +1633,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
+# endif
}
return result;
}
@@ -1520,25 +1662,26 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
result = timesub(&t, ttisp->tt_utoff, sp, tmp);
if (result) {
result->tm_isdst = ttisp->tt_isdst;
-#ifdef TM_ZONE
- result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx];
-#endif /* defined TM_ZONE */
+# ifdef TM_ZONE
+ result->TM_ZONE = UNCONST(&sp->chars[ttisp->tt_desigidx]);
+# endif
if (setname)
update_tzname_etc(sp, ttisp);
}
return result;
}
+#endif
-#if NETBSD_INSPIRED
+#if !USE_TIMEX_T
+# if NETBSD_INSPIRED
struct tm *
localtime_rz(struct state *restrict sp, time_t const *restrict timep,
struct tm *restrict tmp)
{
return localsub(sp, timep, 0, tmp);
}
-
-#endif
+# endif
static struct tm *
localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
@@ -1558,9 +1701,9 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
struct tm *
localtime(const time_t *timep)
{
-#if !SUPPORT_C89
+# if !SUPPORT_C89
static struct tm tm;
-#endif
+# endif
return localtime_tzset(timep, &tm, true);
}
@@ -1569,6 +1712,7 @@ localtime_r(const time_t *restrict timep, struct tm *restrict tmp)
{
return localtime_tzset(timep, tmp, false);
}
+#endif
/*
** gmtsub is to gmtime as localsub is to localtime.
@@ -1587,12 +1731,14 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
** "+xx" or "-xx" if offset is non-zero,
** but this is no time for a treasure hunt.
*/
- tmp->TM_ZONE = ((char *)
- (offset ? wildabbr : gmtptr ? gmtptr->chars : utc));
+ tmp->TM_ZONE = UNCONST(offset ? wildabbr
+ : gmtptr ? gmtptr->chars : utc);
#endif /* defined TM_ZONE */
return result;
}
+#if !USE_TIMEX_T
+
/*
* Re-entrant version of gmtime.
*/
@@ -1607,13 +1753,13 @@ gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
struct tm *
gmtime(const time_t *timep)
{
-#if !SUPPORT_C89
+# if !SUPPORT_C89
static struct tm tm;
-#endif
+# endif
return gmtime_r(timep, &tm);
}
-#if STD_INSPIRED
+# if STD_INSPIRED
/* This function is obsolescent and may disappear in future releases.
Callers can instead use localtime_rz with a fixed-offset zone. */
@@ -1623,12 +1769,13 @@ offtime(const time_t *timep, long offset)
{
gmtcheck();
-#if !SUPPORT_C89
+# if !SUPPORT_C89
static struct tm tm;
-#endif
+# endif
return gmtsub(gmtptr, timep, offset, &tm);
}
+# endif
#endif
/*
@@ -1687,7 +1834,7 @@ timesub(const time_t *timep, int_fast32_t offset,
dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3;
rem %= SECSPERDAY;
/* y = (EPOCH_YEAR
- + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
+ + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
sans overflow. But calculate against 1570 (EPOCH_YEAR -
YEARSPERREPEAT) instead of against 1970 so that things work
for localtime values before 1970 when time_t is unsigned. */
@@ -1804,17 +1951,17 @@ increment_overflow(int *ip, int j)
}
static bool
-increment_overflow32(int_fast32_t *const lp, int const m)
+increment_overflow_time_iinntt(time_t *tp, iinntt j)
{
#ifdef ckd_add
- return ckd_add(lp, *lp, m);
+ return ckd_add(tp, *tp, j);
#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;
+ if (j < 0
+ ? (TYPE_SIGNED(time_t) ? *tp < TIME_T_MIN - j : *tp <= -1 - j)
+ : TIME_T_MAX - j < *tp)
+ return true;
+ *tp += j;
+ return false;
#endif
}
@@ -1838,30 +1985,6 @@ increment_overflow_time(time_t *tp, int_fast32_t j)
#endif
}
-static bool
-normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
-{
- register int tensdelta;
-
- tensdelta = (*unitsptr >= 0) ?
- (*unitsptr / base) :
- (-1 - (-1 - *unitsptr) / base);
- *unitsptr -= tensdelta * base;
- return increment_overflow(tensptr, tensdelta);
-}
-
-static bool
-normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
-{
- register int tensdelta;
-
- tensdelta = (*unitsptr >= 0) ?
- (*unitsptr / base) :
- (-1 - (-1 - *unitsptr) / base);
- *unitsptr -= tensdelta * base;
- return increment_overflow32(tensptr, tensdelta);
-}
-
static int
tmcomp(register const struct tm *const atmp,
register const struct tm *const btmp)
@@ -1906,11 +2029,9 @@ time2sub(struct tm *const tmp,
{
register int dir;
register int i, j;
- register int saved_seconds;
- register int_fast32_t li;
register time_t lo;
register time_t hi;
- int_fast32_t y;
+ iinntt y, mday, hour, min, saved_seconds;
time_t newt;
time_t t;
struct tm yourtm, mytm;
@@ -1918,36 +2039,57 @@ time2sub(struct tm *const tmp,
*okayp = false;
mktmcpy(&yourtm, tmp);
+ min = yourtm.tm_min;
if (do_norm_secs) {
- if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
- SECSPERMIN))
- return WRONG;
+ min += yourtm.tm_sec / SECSPERMIN;
+ yourtm.tm_sec %= SECSPERMIN;
+ if (yourtm.tm_sec < 0) {
+ yourtm.tm_sec += SECSPERMIN;
+ min--;
+ }
}
- if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
- return WRONG;
- if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
- return WRONG;
+
+ hour = yourtm.tm_hour;
+ hour += min / MINSPERHOUR;
+ yourtm.tm_min = min % MINSPERHOUR;
+ if (yourtm.tm_min < 0) {
+ yourtm.tm_min += MINSPERHOUR;
+ hour--;
+ }
+
+ mday = yourtm.tm_mday;
+ mday += hour / HOURSPERDAY;
+ yourtm.tm_hour = hour % HOURSPERDAY;
+ if (yourtm.tm_hour < 0) {
+ yourtm.tm_hour += HOURSPERDAY;
+ mday--;
+ }
+
y = yourtm.tm_year;
- if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
- return WRONG;
+ y += yourtm.tm_mon / MONSPERYEAR;
+ yourtm.tm_mon %= MONSPERYEAR;
+ if (yourtm.tm_mon < 0) {
+ yourtm.tm_mon += MONSPERYEAR;
+ y--;
+ }
+
/*
** Turn y into an actual year number for now.
** It is converted back to an offset from TM_YEAR_BASE later.
*/
- if (increment_overflow32(&y, TM_YEAR_BASE))
- return WRONG;
- while (yourtm.tm_mday <= 0) {
- if (increment_overflow32(&y, -1))
- return WRONG;
- li = y + (1 < yourtm.tm_mon);
- yourtm.tm_mday += year_lengths[isleap(li)];
+ y += TM_YEAR_BASE;
+
+ while (mday <= 0) {
+ iinntt li = y - (yourtm.tm_mon <= 1);
+ mday += year_lengths[isleap(li)];
+ y--;
}
- while (yourtm.tm_mday > DAYSPERLYEAR) {
- li = y + (1 < yourtm.tm_mon);
- yourtm.tm_mday -= year_lengths[isleap(li)];
- if (increment_overflow32(&y, 1))
- return WRONG;
+ while (DAYSPERLYEAR < mday) {
+ iinntt li = y + (1 < yourtm.tm_mon);
+ mday -= year_lengths[isleap(li)];
+ y++;
}
+ yourtm.tm_mday = mday;
for ( ; ; ) {
i = mon_lengths[isleap(y)][yourtm.tm_mon];
if (yourtm.tm_mday <= i)
@@ -1955,16 +2097,14 @@ time2sub(struct tm *const tmp,
yourtm.tm_mday -= i;
if (++yourtm.tm_mon >= MONSPERYEAR) {
yourtm.tm_mon = 0;
- if (increment_overflow32(&y, 1))
- return WRONG;
+ y++;
}
}
#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;
+ y -= TM_YEAR_BASE;
if (! (INT_MIN <= y && y <= INT_MAX))
return WRONG;
yourtm.tm_year = y;
@@ -1980,9 +2120,8 @@ time2sub(struct tm *const tmp,
** not in the same minute that a leap second was deleted from,
** which is a safer assumption than using 58 would be.
*/
- if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
- return WRONG;
saved_seconds = yourtm.tm_sec;
+ saved_seconds -= SECSPERMIN - 1;
yourtm.tm_sec = SECSPERMIN - 1;
} else {
saved_seconds = yourtm.tm_sec;
@@ -2091,10 +2230,8 @@ time2sub(struct tm *const tmp,
return WRONG;
}
label:
- newt = t + saved_seconds;
- if ((newt < t) != (saved_seconds < 0))
+ if (increment_overflow_time_iinntt(&t, saved_seconds))
return WRONG;
- t = newt;
if (funcp(sp, &t, offset, tmp))
*okayp = true;
return t;
@@ -2191,6 +2328,8 @@ time1(struct tm *const tmp,
return WRONG;
}
+#if !defined TM_GMTOFF || !USE_TIMEX_T
+
static time_t
mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
{
@@ -2202,16 +2341,9 @@ mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
}
}
-#if NETBSD_INSPIRED
-
-time_t
-mktime_z(struct state *restrict sp, struct tm *restrict tmp)
-{
- return mktime_tzname(sp, tmp, false);
-}
-
-#endif
-
+# if USE_TIMEX_T
+static
+# endif
time_t
mktime(struct tm *tmp)
{
@@ -2227,7 +2359,17 @@ mktime(struct tm *tmp)
return t;
}
-#if STD_INSPIRED
+#endif
+
+#if NETBSD_INSPIRED && !USE_TIMEX_T
+time_t
+mktime_z(struct state *restrict sp, struct tm *restrict tmp)
+{
+ return mktime_tzname(sp, tmp, false);
+}
+#endif
+
+#if STD_INSPIRED && !USE_TIMEX_T
/* This function is obsolescent and may disappear in future releases.
Callers can instead use mktime. */
time_t
@@ -2239,12 +2381,14 @@ timelocal(struct tm *tmp)
}
#endif
-#ifndef EXTERN_TIMEOFF
-# ifndef timeoff
-# define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 . */
+#if defined TM_GMTOFF || !USE_TIMEX_T
+
+# ifndef EXTERN_TIMEOFF
+# ifndef timeoff
+# define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 . */
+# endif
+# define EXTERN_TIMEOFF static
# endif
-# define EXTERN_TIMEOFF static
-#endif
/* This function is obsolescent and may disappear in future releases.
Callers can instead use mktime_z with a fixed-offset zone. */
@@ -2256,7 +2400,9 @@ timeoff(struct tm *tmp, long offset)
gmtcheck();
return time1(tmp, gmtsub, gmtptr, offset);
}
+#endif
+#if !USE_TIMEX_T
time_t
timegm(struct tm *tmp)
{
@@ -2269,6 +2415,7 @@ timegm(struct tm *tmp)
*tmp = tmcpy;
return t;
}
+#endif
static int_fast32_t
leapcorr(struct state const *sp, time_t t)
@@ -2289,15 +2436,16 @@ leapcorr(struct state const *sp, time_t t)
** XXX--is the below the right way to conditionalize??
*/
-#if STD_INSPIRED
+#if !USE_TIMEX_T
+# if STD_INSPIRED
/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
NETBSD_INSPIRED is defined, and are private otherwise. */
-# if NETBSD_INSPIRED
-# define NETBSD_INSPIRED_EXTERN
-# else
-# define NETBSD_INSPIRED_EXTERN static
-# endif
+# if NETBSD_INSPIRED
+# define NETBSD_INSPIRED_EXTERN
+# else
+# define NETBSD_INSPIRED_EXTERN static
+# endif
/*
** IEEE Std 1003.1 (POSIX) says that 536457599
@@ -2374,17 +2522,13 @@ posix2time(time_t t)
return t;
}
-#endif /* STD_INSPIRED */
+# endif /* STD_INSPIRED */
-#if TZ_TIME_T
+# if TZ_TIME_T
-# if !USG_COMPAT
-# define daylight 0
-# define timezone 0
-# endif
-# if !ALTZONE
-# define altzone 0
-# endif
+# if !USG_COMPAT
+# define timezone 0
+# endif
/* Convert from the underlying system's time_t to the ersatz time_tz,
which is called 'time_t' in this file. Typically, this merely
@@ -2402,9 +2546,9 @@ time(time_t *p)
{
time_t r = sys_time(0);
if (r != (time_t) -1) {
- int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0;
- if (increment_overflow32(&offset, -EPOCH_OFFSET)
- || increment_overflow_time(&r, offset)) {
+ iinntt offset = EPOCH_LOCAL ? timezone : 0;
+ if (offset < IINNTT_MIN + EPOCH_OFFSET
+ || increment_overflow_time_iinntt(&r, offset - EPOCH_OFFSET)) {
errno = EOVERFLOW;
r = -1;
}
@@ -2414,4 +2558,5 @@ time(time_t *p)
return r;
}
+# endif
#endif
diff --git a/newctime.3 b/newctime.3
index d19fd25b..9d09e5a5 100644
--- a/newctime.3
+++ b/newctime.3
@@ -5,43 +5,34 @@
asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
.SH SYNOPSIS
.nf
-.ie \n(.g .ds - \f(CR-\fP
-.el .ds - \-
.B #include
.PP
-.B [[deprecated]] char *ctime(time_t const *clock);
-.PP
-/* Only in POSIX.1-2017 and earlier. */
-.B char *ctime_r(time_t const *clock, char *buf);
-.PP
-.B double difftime(time_t time1, time_t time0);
-.PP
-.B [[deprecated]] char *asctime(struct tm const *tm);
-.PP
-/* Only in POSIX.1-2017 and earlier. */
-.B "char *asctime_r(struct tm const *restrict tm,"
-.B " char *restrict result);"
-.PP
.B struct tm *localtime(time_t const *clock);
-.PP
.B "struct tm *localtime_r(time_t const *restrict clock,"
.B " struct tm *restrict result);"
-.PP
.B "struct tm *localtime_rz(timezone_t restrict zone,"
.B " time_t const *restrict clock,"
.B " struct tm *restrict result);"
.PP
.B struct tm *gmtime(time_t const *clock);
-.PP
.B "struct tm *gmtime_r(time_t const *restrict clock,"
.B " struct tm *restrict result);"
.PP
.B time_t mktime(struct tm *tm);
-.PP
.B "time_t mktime_z(timezone_t restrict zone,"
.B " struct tm *restrict tm);"
.PP
-.B cc ... \*-ltz
+.B double difftime(time_t time1, time_t time0);
+.PP
+.B [[deprecated]] char *asctime(struct tm const *tm);
+.B [[deprecated]] char *ctime(time_t const *clock);
+.PP
+/* Only in POSIX.1-2017 and earlier. */
+.B char *ctime_r(time_t const *clock, char *buf);
+.B "char *asctime_r(struct tm const *restrict tm,"
+.B " char *restrict result);"
+.PP
+.B cc ... \-ltz
.fi
.SH DESCRIPTION
.ie '\(en'' .ds en \-
@@ -54,82 +45,37 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
\\$3\*(lq\\$1\*(rq\\$2
..
The
-.B ctime
-function
-converts a long integer, pointed to by
-.IR clock ,
-and returns a pointer to a
-string of the form
-.br
-.ce
-.eo
-Thu Nov 24 18:22:48 1986\n\0
-.br
-.ec
-Years requiring fewer than four characters are padded with leading zeroes.
-For years longer than four characters, the string is of the form
-.br
-.ce
-.eo
-Thu Nov 24 18:22:48 81986\n\0
-.ec
-.br
-with five spaces before the year.
-These unusual formats are designed to make it less likely that older
-software that expects exactly 26 bytes of output will mistakenly output
-misleading values for out-of-range years.
-.PP
-The
-.BI * clock
-timestamp represents the time in seconds since 1970-01-01 00:00:00
-Coordinated Universal Time (UTC).
-The POSIX standard says that timestamps must be nonnegative
-and must ignore leap seconds.
-Many implementations extend POSIX by allowing negative timestamps,
-and can therefore represent timestamps that predate the
-introduction of UTC and are some other flavor of Universal Time (UT).
-Some implementations support leap seconds, in contradiction to POSIX.
-.PP
-The
-.B ctime
-function is deprecated starting in C23.
-Callers can use
-.B localtime_r
-and
-.B strftime
-instead.
-.PP
-The
.B localtime
and
.B gmtime
functions
+convert an integer, pointed to by
+.IR clock ,
+and
return pointers to
.q "tm"
structures, described below.
+If the integer is out of range for conversion,
+these functions return a null pointer.
The
.B localtime
function
corrects for the time zone and any time zone adjustments
(such as Daylight Saving Time in the United States).
-.PP
The
.B gmtime
-function
-converts to Coordinated Universal Time.
+function converts to Coordinated Universal Time.
.PP
The
-.B asctime
-function
-converts a time value contained in a
-.q "tm"
-structure to a string,
-as shown in the above example,
-and returns a pointer to the string.
-This function is deprecated starting in C23.
-Callers can use
-.B strftime
-instead.
+.BI * clock
+timestamp represents the time in seconds since 1970-01-01 00:00:00
+Coordinated Universal Time (UTC).
+The POSIX standard says that timestamps must be nonnegative
+and must ignore leap seconds.
+Many implementations extend POSIX by allowing negative timestamps,
+and can therefore represent timestamps that predate the
+introduction of UTC and are some other flavor of Universal Time (UT).
+Some implementations support leap seconds, in contradiction to POSIX.
.PP
The
.B mktime
@@ -204,6 +150,52 @@ returns the difference between two calendar times,
expressed in seconds.
.PP
The
+.B asctime
+function
+converts a time value contained in a
+.q "tm"
+structure to a pointer to a
+string of the form
+.br
+.ce
+.eo
+Thu Nov 24 18:22:48 1986\n\0
+.br
+.ec
+Years requiring fewer than four characters are padded with leading zeroes.
+For years longer than four characters, the string is of the form
+.br
+.ce
+.eo
+Thu Nov 24 18:22:48 81986\n\0
+.ec
+.br
+with five spaces before the year.
+This unusual format is designed to make it less likely that older
+software that expects exactly 26 bytes of output will mistakenly output
+misleading values for out-of-range years.
+This function is deprecated starting in C23.
+Callers can use
+.B strftime
+instead.
+.PP
+The
+.B ctime
+function is equivalent to calliing
+.B localtime
+and then calling
+.B asctime
+on the result.
+Like
+.BR asctime ,
+this function is deprecated starting in C23.
+Callers can use
+.B localtime
+and
+.B strftime
+instead.
+.PP
+The
.BR ctime_r ,
.BR localtime_r ,
.BR gmtime_r ,
diff --git a/newstrftime.3 b/newstrftime.3
index a9997a09..e9a38224 100644
--- a/newstrftime.3
+++ b/newstrftime.3
@@ -40,8 +40,6 @@
strftime \- format date and time
.SH SYNOPSIS
.nf
-.ie \n(.g .ds - \f(CR-\fP
-.el .ds - \-
.B #include
.PP
.B "size_t strftime(char *restrict buf, size_t maxsize,"
@@ -93,7 +91,7 @@ If a bracketed member name is followed by
.B strftime
can use the named member even though POSIX.1-2024 does not list it;
if the name is followed by
-.q \*- ,
+.q \- ,
.B strftime
ignores the member even though POSIX.1-2024 lists it
which means portable code should set it.
@@ -139,11 +137,14 @@ is replaced by the locale's appropriate date and time representation.
.IR tm_sec ,
.IR tm_gmtoff ,
.IR tm_zone ,
-.IR tm_isdst \*-].
+.IR tm_isdst \-].
.TP
%D
is equivalent to
.c %m/%d/%y .
+Although used in the United States for current dates,
+this format is ambiguous elsewhere
+and for dates that might involve other centuries.
.RI [ tm_year ,
.IR tm_mon ,
.IR tm_mday ]
@@ -167,6 +168,8 @@ is equivalent to
.TP
%G
is replaced by the ISO 8601 year with century as a decimal number.
+This is the year that includes the greater part of the week.
+(Monday as the first day of a week).
See also the
.c %V
conversion specification.
@@ -176,11 +179,7 @@ conversion specification.
.TP
%g
is replaced by the ISO 8601 year without century as a decimal number [00,99].
-This is the year that includes the greater part of the week.
-(Monday as the first day of a week).
-See also the
-.c %V
-conversion specification.
+Since it omits the century, it is ambiguous for dates.
.RI [ tm_year ,
.IR tm_yday ,
.IR tm_wday ]
@@ -249,9 +248,22 @@ of leap seconds.
is replaced by the number of seconds since the Epoch (see
.BR ctime (3)).
Although %s is reliable in this implementation,
-it can have glitches on other platforms (notably platforms lacking
-.IR tm_gmtoff ),
-so portable code should format a
+it can have glitches on other platforms
+(notably obsolescent platforms lacking
+.I tm_gmtoff
+or where
+.B time_t
+is no wider than int), and POSIX allows
+.B strftime
+to set
+.B errno
+to
+.B EINVAL
+or
+.B EOVERFLOW
+and return 0 if the number of seconds would be negative or out of range for
+.BR time_t .
+Portable code should therefore format a
.B time_t
value directly via something like
.B sprintf
@@ -267,7 +279,7 @@ with "%s".
.IR tm_min ,
.IR tm_sec ,
.IR tm_gmtoff +,
-.IR tm_isdst \*-].
+.IR tm_isdst \-].
.TP
%T
is replaced by the time in the format
@@ -284,7 +296,7 @@ is replaced by the week number of the year (Sunday as the first day of
the week) as a decimal number [00,53].
.RI [ tm_wday ,
.IR tm_yday ,
-.IR tm_year \*-]
+.IR tm_year \-]
.TP
%u
is replaced by the weekday (Monday as the first day of the week)
@@ -318,31 +330,33 @@ as a decimal number [0,6].
.TP
%X
is replaced by the locale's appropriate time representation.
-.RI [ tm_year \*-,
-.IR tm_yday \*-,
-.IR tm_mon \*-,
-.IR tm_mday \*-,
-.IR tm_wday \*-,
+.RI [ tm_year \-,
+.IR tm_yday \-,
+.IR tm_mon \-,
+.IR tm_mday \-,
+.IR tm_wday \-,
.IR tm_hour ,
.IR tm_min ,
.IR tm_sec ,
.IR tm_gmtoff ,
.IR tm_zone ,
-.IR tm_isdst \*-].
+.IR tm_isdst \-].
.TP
%x
is replaced by the locale's appropriate date representation.
+This format can be ambiguous for dates, e.g.,
+it can generate "01/02/03" in the C locale.
.RI [ tm_year ,
.IR tm_yday ,
.IR tm_mon ,
.IR tm_mday ,
.IR tm_wday ,
-.IR tm_hour \*-,
-.IR tm_min \*-,
-.IR tm_sec \*-,
-.IR tm_gmtoff \*-,
-.IR tm_zone \*-,
-.IR tm_isdst \*-].
+.IR tm_hour \-,
+.IR tm_min \-,
+.IR tm_sec \-,
+.IR tm_gmtoff \-,
+.IR tm_zone \-,
+.IR tm_isdst \-].
.TP
%Y
is replaced by the year with century as a decimal number.
@@ -350,28 +364,29 @@ is replaced by the year with century as a decimal number.
.TP
%y
is replaced by the year without century as a decimal number [00,99].
+Since it omits the century, it is ambiguous for dates.
.RI [ tm_year ]
.TP
%Z
is replaced by the time zone abbreviation,
or by the empty string if this is not determinable.
.RI [ tm_zone ,
-.IR tm_isdst \*-]
+.IR tm_isdst \-]
.TP
%z
is replaced by the offset from the Prime Meridian
-in the format +HHMM or \*-HHMM (ISO 8601) as appropriate,
+in the format +HHMM or \-HHMM (ISO 8601) as appropriate,
with positive values representing locations east of Greenwich,
or by the empty string if this is not determinable.
-The numeric time zone abbreviation \*-0000 is used when the time is
+The numeric time zone abbreviation \-0000 is used when the time is
Universal Time
but local time is indeterminate; by convention this is used for
locations while uninhabited, and corresponds to a zero offset when the
time zone abbreviation begins with
-.q "\*-" .
+.q "\-" .
.RI [ tm_gmtoff ,
.IR tm_zone +,
-.IR tm_isdst \*-]
+.IR tm_isdst \-]
.TP
%%
is replaced by a single %.
@@ -418,15 +433,6 @@ This function fails if:
The total number of resulting bytes, including the terminating
NUL character, is more than
.IR maxsize .
-.PP
-This function may fail if:
-.TP
-[EOVERFLOW]
-The format includes an
-.c %s
-conversion and the number of seconds since the Epoch cannot be represented
-in a
-.c time_t .
.SH SEE ALSO
.BR date (1),
.BR getenv (3),
diff --git a/newtzset.3 b/newtzset.3
index 661fb25b..db6bfa7f 100644
--- a/newtzset.3
+++ b/newtzset.3
@@ -5,8 +5,6 @@
tzset \- initialize time conversion information
.SH SYNOPSIS
.nf
-.ie \n(.g .ds - \f(CR-\fP
-.el .ds - \-
.B #include
.PP
.BI "timezone_t tzalloc(char const *" TZ );
@@ -23,7 +21,7 @@ tzset \- initialize time conversion information
.br
.B extern int daylight;
.PP
-.B cc ... \*-ltz
+.B cc ... \-ltz
.fi
.SH DESCRIPTION
.ie '\(en'' .ds en \-
@@ -110,7 +108,7 @@ except a leading colon
digits, comma
.RB ( , ),
ASCII minus
-.RB ( \*- ),
+.RB ( \- ),
ASCII plus
.RB ( + ),
and NUL bytes are allowed.
@@ -150,7 +148,7 @@ daylight saving time is assumed to be one hour ahead of standard time. One or
more digits may be used; the value is always interpreted as a decimal
number. The hour must be between zero and 24, and the minutes (and
seconds) \*(en if present \*(en between zero and 59. If preceded by a
-.q "\*-" ,
+.q "\-" ,
the time zone shall be east of the Prime Meridian; otherwise it shall be
west (which may be indicated by an optional preceding
.q "+" .
@@ -239,7 +237,7 @@ values that directly specify the timezone.
stands for US Eastern Standard
Time (EST), 5 hours behind UT, without daylight saving.
.TP
-.B <+12>\*-12<+13>,M11.1.0,M1.2.1/147
+.B <+12>\-12<+13>,M11.1.0,M1.2.1/147
stands for Fiji time, 12 hours ahead
of UT, springing forward on November's first Sunday at 02:00, and
falling back on January's second Monday at 147:00 (i.e., 03:00 on the
@@ -249,34 +247,34 @@ and daylight saving time are
and
.q "+13".
.TP
-.B IST\*-2IDT,M3.4.4/26,M10.5.0
+.B IST\-2IDT,M3.4.4/26,M10.5.0
stands for Israel Standard Time (IST) and Israel Daylight Time (IDT),
2 hours ahead of UT, springing forward on March's fourth
Thursday at 26:00 (i.e., 02:00 on the first Friday on or after March
23), and falling back on October's last Sunday at 02:00.
.TP
-.B <\*-04>4<\*-03>,J1/0,J365/25
+.B <\-04>4<\-03>,J1/0,J365/25
stands for permanent daylight saving time, 3 hours behind UT with
abbreviation
-.q "\*-03".
+.q "\-03".
There is a dummy fall-back transition on December 31 at 25:00 daylight
saving time (i.e., 24:00 standard time, equivalent to January 1 at
00:00 standard time), and a simultaneous spring-forward transition on
January 1 at 00:00 standard time, so daylight saving time is in effect
all year and the initial
-.B <\*-04>
+.B <\-04>
is a placeholder.
.TP
-.B <\*-03>3<\*-02>,M3.5.0/\*-2,M10.5.0/\*-1
+.B <\-03>3<\-02>,M3.5.0/\-2,M10.5.0/\-1
stands for time in western Greenland, 3 hours behind UT, where clocks
follow the EU rules of
springing forward on March's last Sunday at 01:00 UT (\-02:00 local
time, i.e., 22:00 the previous day) and falling back on October's last
Sunday at 01:00 UT (\-01:00 local time, i.e., 23:00 the previous day).
The abbreviations for standard and daylight saving time are
-.q "\*-03"
+.q "\-03"
and
-.q "\*-02".
+.q "\-02".
.PP
If
.I TZ
diff --git a/northamerica b/northamerica
index 01f392e0..8d356aa0 100644
--- a/northamerica
+++ b/northamerica
@@ -27,9 +27,12 @@
# in New York City (1869-10). His 1870 proposal was based on Washington, DC,
# but in 1872-05 he moved the proposed origin to Greenwich.
-# From Paul Eggert (2018-03-20):
+# From Paul Eggert (2024-11-18):
# Dowd's proposal left many details unresolved, such as where to draw
-# lines between time zones. The key individual who made time zones
+# lines between time zones. Sandford Fleming of the Canadian Pacific Railway
+# argued for Dowd's proposal in 1876, and Cleveland Abbe of the American
+# Meteorology Society published a report in 1879 recommending four US time
+# zones based on GMT. However, the key individual who made time zones
# work in the US was William Frederick Allen - railway engineer,
# managing editor of the Travelers' Guide, and secretary of the
# General Time Convention, a railway standardization group. Allen
@@ -2631,7 +2634,7 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20
# http://puentelibre.mx/noticia/ciudad_juarez_cambio_horario_noviembre_2022/
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
-Rule Mexico 1931 only - April 30 0:00 1:00 D
+Rule Mexico 1931 only - Apr 30 0:00 1:00 D
Rule Mexico 1931 only - Oct 1 0:00 0 S
Rule Mexico 1939 only - Feb 5 0:00 1:00 D
Rule Mexico 1939 only - Jun 25 0:00 0 S
diff --git a/private.h b/private.h
index c3304104..0a546e02 100644
--- a/private.h
+++ b/private.h
@@ -37,6 +37,38 @@
# define SUPPORT_C89 1
#endif
+
+/* The following feature-test macros should be defined before
+ any #include of a system header. */
+
+/* Enable tm_gmtoff, tm_zone, and environ on GNUish systems. */
+#define _GNU_SOURCE 1
+/* Fix asctime_r on Solaris 11. */
+#define _POSIX_PTHREAD_SEMANTICS 1
+/* Enable strtoimax on pre-C99 Solaris 11. */
+#define __EXTENSIONS__ 1
+/* Cause MS-Windows headers to define POSIX names. */
+#define _CRT_DECLARE_NONSTDC_NAMES 1
+/* Prevent MS-Windows headers from defining min and max. */
+#define NOMINMAX 1
+
+/* On GNUish systems where time_t might be 32 or 64 bits, use 64.
+ On these platforms _FILE_OFFSET_BITS must also be 64; otherwise
+ setting _TIME_BITS to 64 does not work. The code does not
+ otherwise rely on _FILE_OFFSET_BITS being 64, since it does not
+ use off_t or functions like 'stat' that depend on off_t. */
+#ifndef _TIME_BITS
+# ifndef _FILE_OFFSET_BITS
+# define _FILE_OFFSET_BITS 64
+# endif
+# if _FILE_OFFSET_BITS == 64
+# define _TIME_BITS 64
+# endif
+#endif
+
+/* End of feature-test macro definitions. */
+
+
#ifndef __STDC_VERSION__
# define __STDC_VERSION__ 0
#endif
@@ -51,6 +83,7 @@
#endif
#if __STDC_VERSION__ < 202311
+# undef static_assert
# define static_assert(cond) extern int static_assert_check[(cond) ? 1 : -1]
#endif
@@ -87,11 +120,11 @@
#if !defined HAVE_GETTEXT && defined __has_include
# if __has_include()
-# define HAVE_GETTEXT true
+# define HAVE_GETTEXT 1
# endif
#endif
#ifndef HAVE_GETTEXT
-# define HAVE_GETTEXT false
+# define HAVE_GETTEXT 0
#endif
#ifndef HAVE_INCOMPATIBLE_CTIME_R
@@ -124,20 +157,20 @@
#if !defined HAVE_SYS_STAT_H && defined __has_include
# if !__has_include()
-# define HAVE_SYS_STAT_H false
+# define HAVE_SYS_STAT_H 0
# endif
#endif
#ifndef HAVE_SYS_STAT_H
-# define HAVE_SYS_STAT_H true
+# define HAVE_SYS_STAT_H 1
#endif
#if !defined HAVE_UNISTD_H && defined __has_include
# if !__has_include()
-# define HAVE_UNISTD_H false
+# define HAVE_UNISTD_H 0
# endif
#endif
#ifndef HAVE_UNISTD_H
-# define HAVE_UNISTD_H true
+# define HAVE_UNISTD_H 1
#endif
#ifndef NETBSD_INSPIRED
@@ -149,25 +182,6 @@
# define ctime_r _incompatible_ctime_r
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
-/* Enable tm_gmtoff, tm_zone, and environ on GNUish systems. */
-#define _GNU_SOURCE 1
-/* Fix asctime_r on Solaris 11. */
-#define _POSIX_PTHREAD_SEMANTICS 1
-/* Enable strtoimax on pre-C99 Solaris 11. */
-#define __EXTENSIONS__ 1
-
-/* On GNUish systems where time_t might be 32 or 64 bits, use 64.
- On these platforms _FILE_OFFSET_BITS must also be 64; otherwise
- setting _TIME_BITS to 64 does not work. The code does not
- otherwise rely on _FILE_OFFSET_BITS being 64, since it does not
- use off_t or functions like 'stat' that depend on off_t. */
-#ifndef _FILE_OFFSET_BITS
-# define _FILE_OFFSET_BITS 64
-#endif
-#if !defined _TIME_BITS && _FILE_OFFSET_BITS == 64
-# define _TIME_BITS 64
-#endif
-
/*
** Nested includes
*/
@@ -260,6 +274,10 @@
# endif
#endif
+#ifndef HAVE_SNPRINTF
+# define HAVE_SNPRINTF (!PORT_TO_C89 || 199901 <= __STDC_VERSION__)
+#endif
+
#ifndef HAVE_STRFTIME_L
# if _POSIX_VERSION < 200809
# define HAVE_STRFTIME_L 0
@@ -305,7 +323,7 @@
** stdint.h, even with pre-C99 compilers.
*/
#if !defined HAVE_STDINT_H && defined __has_include
-# define HAVE_STDINT_H true /* C23 __has_include implies C99 stdint.h. */
+# define HAVE_STDINT_H 1 /* C23 __has_include implies C99 stdint.h. */
#endif
#ifndef HAVE_STDINT_H
# define HAVE_STDINT_H \
@@ -375,11 +393,15 @@ typedef int int_fast32_t;
# endif
#endif
+#ifndef INT_LEAST32_MAX
+typedef int_fast32_t int_least32_t;
+#endif
+
#ifndef INTMAX_MAX
# ifdef LLONG_MAX
typedef long long intmax_t;
# ifndef HAVE_STRTOLL
-# define HAVE_STRTOLL true
+# define HAVE_STRTOLL 1
# endif
# if HAVE_STRTOLL
# define strtoimax strtoll
@@ -459,7 +481,7 @@ typedef unsigned long uintmax_t;
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
+# define HAVE_STDCKDINT_H 1
# endif
#endif
#ifdef HAVE_STDCKDINT_H
@@ -554,13 +576,26 @@ typedef unsigned long uintmax_t;
# define ATTRIBUTE_REPRODUCIBLE /* empty */
#endif
+#if HAVE___HAS_C_ATTRIBUTE
+# if __has_c_attribute(unsequenced)
+# define ATTRIBUTE_UNSEQUENCED [[unsequenced]]
+# endif
+#endif
+#ifndef ATTRIBUTE_UNSEQUENCED
+# define ATTRIBUTE_UNSEQUENCED /* empty */
+#endif
+
/* GCC attributes that are useful in tzcode.
+ __attribute__((const)) is stricter than [[unsequenced]],
+ so the latter is an adequate substitute in non-GCC C23 platforms.
__attribute__((pure)) is stricter than [[reproducible]],
so the latter is an adequate substitute in non-GCC C23 platforms. */
#if __GNUC__ < 3
+# define ATTRIBUTE_CONST ATTRIBUTE_UNSEQUENCED
# define ATTRIBUTE_FORMAT(spec) /* empty */
# define ATTRIBUTE_PURE ATTRIBUTE_REPRODUCIBLE
#else
+# define ATTRIBUTE_CONST __attribute__((const))
# define ATTRIBUTE_FORMAT(spec) __attribute__((format spec))
# define ATTRIBUTE_PURE __attribute__((pure))
#endif
@@ -593,6 +628,12 @@ typedef unsigned long uintmax_t;
# define RESERVE_STD_EXT_IDS 0
#endif
+#ifdef time_tz
+# define defined_time_tz true
+#else
+# define defined_time_tz false
+#endif
+
/* If standard C identifiers with external linkage (e.g., localtime)
are reserved and are not already being renamed anyway, rename them
as if compiling with '-Dtime_tz=time_t'. */
@@ -608,9 +649,9 @@ typedef unsigned long uintmax_t;
** typical platforms.
*/
#if defined time_tz || EPOCH_LOCAL || EPOCH_OFFSET != 0
-# define TZ_TIME_T 1
+# define TZ_TIME_T true
#else
-# define TZ_TIME_T 0
+# define TZ_TIME_T false
#endif
#if defined LOCALTIME_IMPLEMENTATION && TZ_TIME_T
@@ -705,7 +746,7 @@ DEPRECATED_IN_C23 char *ctime(time_t const *);
char *asctime_r(struct tm const *restrict, char *restrict);
char *ctime_r(time_t const *, char *);
#endif
-double difftime(time_t, time_t);
+ATTRIBUTE_CONST double difftime(time_t, time_t);
size_t strftime(char *restrict, size_t, char const *restrict,
struct tm const *restrict);
# if HAVE_STRFTIME_L
@@ -727,9 +768,9 @@ void tzset(void);
|| defined __GLIBC__ || defined __tm_zone /* musl */ \
|| defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
|| (defined __APPLE__ && defined __MACH__))
-# define HAVE_DECL_TIMEGM true
+# define HAVE_DECL_TIMEGM 1
# else
-# define HAVE_DECL_TIMEGM false
+# define HAVE_DECL_TIMEGM 0
# endif
#endif
#if !HAVE_DECL_TIMEGM && !defined timegm
@@ -769,7 +810,11 @@ extern long altzone;
*/
#ifndef STD_INSPIRED
-# define STD_INSPIRED 0
+# ifdef __NetBSD__
+# define STD_INSPIRED 1
+# else
+# define STD_INSPIRED 0
+# endif
#endif
#if STD_INSPIRED
# if TZ_TIME_T || !defined offtime
@@ -875,7 +920,7 @@ ATTRIBUTE_PURE time_t time2posix_z(timezone_t, time_t);
default: TIME_T_MAX_NO_PADDING) \
: (time_t) -1)
enum { SIGNED_PADDING_CHECK_NEEDED
- = _Generic((time_t) 0,
+ = _Generic((time_t) 0,
signed char: false, short: false,
int: false, long: false, long long: false,
default: true) };
@@ -922,8 +967,8 @@ static_assert(! TYPE_SIGNED(time_t) || ! SIGNED_PADDING_CHECK_NEEDED
# define UNINIT_TRAP 0
#endif
-/* localtime.c sometimes needs access to timeoff if it is not already public.
- tz_private_timeoff should be used only by localtime.c. */
+/* strftime.c sometimes needs access to timeoff if it is not already public.
+ tz_private_timeoff should be used only by localtime.c and strftime.c. */
#if (!defined EXTERN_TIMEOFF \
&& defined TM_GMTOFF && (200809 < _POSIX_VERSION || ! UNINIT_TRAP))
# ifndef timeoff
diff --git a/southamerica b/southamerica
index c8d9097a..1fcf6514 100644
--- a/southamerica
+++ b/southamerica
@@ -1687,7 +1687,7 @@ Rule Para 2005 2009 - Mar Sun>=8 0:00 0 -
# and that on the first Sunday of the month of October, it is to be set
# forward 60 minutes, in all the territory of the Paraguayan Republic.
# ...
-Rule Para 2010 max - Oct Sun>=1 0:00 1:00 -
+Rule Para 2010 2024 - Oct Sun>=1 0:00 1:00 -
Rule Para 2010 2012 - Apr Sun>=8 0:00 0 -
#
# From Steffen Thorsen (2013-03-07):
@@ -1706,14 +1706,35 @@ Rule Para 2010 2012 - Apr Sun>=8 0:00 0 -
# https://www.abc.com.py/politica/2023/07/12/promulgacion-el-cambio-de-hora-sera-por-ley/
# From Carlos Raúl Perasso (2023-07-27):
# http://silpy.congreso.gov.py/descarga/ley-144138
-Rule Para 2013 max - Mar Sun>=22 0:00 0 -
+Rule Para 2013 2024 - Mar Sun>=22 0:00 0 -
+#
+# From Heitor David Pinto (2024-09-24):
+# Today the Congress of Paraguay passed a bill to observe UTC-3 permanently....
+# The text of the bill says that it would enter into force on the first
+# Sunday in October 2024, the same date currently scheduled to start DST....
+# https://silpy.congreso.gov.py/web/expediente/132531
+# (2024-10-14):
+# The president approved the law on 11 October 2024,
+# and it was officially published on 14 October 2024.
+# https://www.gacetaoficial.gov.py/index/detalle_publicacion/89723
+# The text of the law says that it enters into force on the first
+# Sunday in October 2024 (6 October 2024). But the constitution
+# prohibits retroactive effect, and the civil code says that laws
+# enter into force on the day after their publication or on the day
+# that they specify, and it also says that they don't have retroactive
+# effect. So I think that the time change on 6 October 2024 should
+# still be considered as DST according to the previous law, and
+# permanently UTC-3 from 15 October 2024 according to the new law....
+# https://www.constituteproject.org/constitution/Paraguay_2011
+# https://www.oas.org/dil/esp/codigo_civil_paraguay.pdf
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Asuncion -3:50:40 - LMT 1890
-3:50:40 - AMT 1931 Oct 10 # Asunción Mean Time
-4:00 - %z 1972 Oct
-3:00 - %z 1974 Apr
- -4:00 Para %z
+ -4:00 Para %z 2024 Oct 15
+ -3:00 - %z
# Peru
#
diff --git a/strftime.c b/strftime.c
index 755d341f..487a5234 100644
--- a/strftime.c
+++ b/strftime.c
@@ -39,8 +39,63 @@
#include
#include
+/* If true, the value returned by an idealized unlimited-range mktime
+ always fits into an integer type with bounds MIN and MAX.
+ If false, the value might not fit.
+ This macro is usable in #if if its arguments are.
+ Add or subtract 2**31 - 1 for the maximum UT offset allowed in a TZif file,
+ divide by the maximum number of non-leap seconds in a year,
+ divide again by two just to be safe,
+ and account for the tm_year origin (1900) and time_t origin (1970). */
+#define MKTIME_FITS_IN(min, max) \
+ ((min) < 0 \
+ && ((min) + 0x7fffffff) / 366 / 24 / 60 / 60 / 2 + 1970 - 1900 < INT_MIN \
+ && INT_MAX < ((max) - 0x7fffffff) / 366 / 24 / 60 / 60 / 2 + 1970 - 1900)
+
+/* MKTIME_MIGHT_OVERFLOW is true if mktime can fail due to time_t overflow
+ or if it is not known whether mktime can fail,
+ and is false if mktime definitely cannot fail.
+ This macro is usable in #if, and so does not use TIME_T_MAX or sizeof.
+ If the builder has not configured this macro, guess based on what
+ known platforms do. When in doubt, guess true. */
+#ifndef MKTIME_MIGHT_OVERFLOW
+# if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
+# include
+# endif
+# if ((/* The following heuristics assume native time_t. */ \
+ defined_time_tz) \
+ || ((/* Traditional time_t is 'long', so if 'long' is not wide enough \
+ assume overflow unless we're on a known-safe host. */ \
+ !MKTIME_FITS_IN(LONG_MIN, LONG_MAX)) \
+ && (/* GNU C Library 2.29 (2019-02-01) and later has 64-bit time_t \
+ if __TIMESIZE is 64. */ \
+ !defined __TIMESIZE || __TIMESIZE < 64) \
+ && (/* FreeBSD 12 r320347 (__FreeBSD_version 1200036; 2017-06-26), \
+ and later has 64-bit time_t on all platforms but i386 which \
+ is currently scheduled for end-of-life on 2028-11-30. */ \
+ !defined __FreeBSD_version || __FreeBSD_version < 1200036 \
+ || defined __i386) \
+ && (/* NetBSD 6.0 (2012-10-17) and later has 64-bit time_t. */ \
+ !defined __NetBSD_Version__ || __NetBSD_Version__ < 600000000) \
+ && (/* OpenBSD 5.5 (2014-05-01) and later has 64-bit time_t. */ \
+ !defined OpenBSD || OpenBSD < 201405)))
+# define MKTIME_MIGHT_OVERFLOW 1
+# else
+# define MKTIME_MIGHT_OVERFLOW 0
+# endif
+#endif
+/* Check that MKTIME_MIGHT_OVERFLOW is consistent with time_t's range. */
+static_assert(MKTIME_MIGHT_OVERFLOW
+ || MKTIME_FITS_IN(TIME_T_MIN, TIME_T_MAX));
+
+#if MKTIME_MIGHT_OVERFLOW
+/* Do this after system includes as it redefines time_t, mktime, timeoff. */
+# define USE_TIMEX_T true
+# include "localtime.c"
+#endif
+
#ifndef DEPRECATE_TWO_DIGIT_YEARS
-# define DEPRECATE_TWO_DIGIT_YEARS false
+# define DEPRECATE_TWO_DIGIT_YEARS 0
#endif
struct lc_time_T {
@@ -135,10 +190,6 @@ strftime(char *restrict s, size_t maxsize, char const *restrict format,
tzset();
p = _fmt(format, t, s, s + maxsize, &warn);
- if (!p) {
- errno = EOVERFLOW;
- return 0;
- }
if (DEPRECATE_TWO_DIGIT_YEARS
&& warn != IN_NONE && getenv(YEAR_2000_NAME)) {
fprintf(stderr, "\n");
@@ -170,7 +221,12 @@ _fmt(const char *format, const struct tm *t, char *pt,
if (*format == '%') {
label:
switch (*++format) {
- case '\0':
+ default:
+ /* Output unknown conversion specifiers as-is,
+ to aid debugging. This includes '%' at
+ format end. This conforms to C23 section
+ 7.29.3.5 paragraph 6, which says behavior
+ is undefined here. */
--format;
break;
case 'A':
@@ -327,16 +383,17 @@ _fmt(const char *format, const struct tm *t, char *pt,
tm.tm_mday = t->tm_mday;
tm.tm_mon = t->tm_mon;
tm.tm_year = t->tm_year;
+
+ /* Get the time_t value for TM.
+ Native time_t, or its redefinition
+ by localtime.c above, is wide enough
+ so that this cannot overflow. */
#ifdef TM_GMTOFF
mkt = timeoff(&tm, t->TM_GMTOFF);
#else
tm.tm_isdst = t->tm_isdst;
mkt = mktime(&tm);
#endif
- /* 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);
@@ -590,12 +647,6 @@ _fmt(const char *format, const struct tm *t, char *pt,
warnp);
continue;
case '%':
- /*
- ** X311J/88-090 (4.12.3.5): if conversion char is
- ** undefined, behavior is undefined. Print out the
- ** character itself as printf(3) also does.
- */
- default:
break;
}
}
diff --git a/theory.html b/theory.html
index d3573ede..352a3d87 100644
--- a/theory.html
+++ b/theory.html
@@ -123,8 +123,9 @@ Timezone identifiers
locate the user on a timezone map or prioritize names that are
geographically close. For an example selection interface, see the
tzselect
program in the tz
code.
-The Unicode Common Locale Data
-Repository contains data that may be useful for other selection
+Unicode's Common Locale Data
+Repository (CLDR)
+contains data that may be useful for other selection
interfaces; it maps timezone names like Europe/Prague
to
locale-dependent strings like "Prague", "Praha", "Прага", and "布拉格".
@@ -200,6 +201,8 @@ Timezone identifiers
A name must not be empty, or contain '//
', or
start or end with '/
'.
+ Also, a name must not be 'Etc/Unknown
', as
+ CLDR uses that string for an unknown or invalid timezone.
Do not use names that differ only in case.
@@ -220,10 +223,18 @@ Timezone identifiers
do not need locations, since local time is not defined there.
- If all the clocks in a timezone have agreed since 1970,
- do not bother to include more than one timezone
- even if some of the clocks disagreed before 1970.
+ If all clocks in a region have agreed since 1970,
+ give them just one name even if some of the clocks disagreed before 1970,
+ or reside in different countries or in notable or faraway locations.
Otherwise these tables would become annoyingly large.
+ For example, do not create a name Indian/Crozet
+ as a near-duplicate or alias of Asia/Dubai
+ merely because they are different countries or territories,
+ or their clocks disagreed before 1970, or the
+ Crozet Islands
+ are notable in their own right,
+ or the Crozet Islands are not adjacent to other locations
+ that use Asia/Dubai
.
If boundaries between regions are fluid, such as during a war or
@@ -579,10 +590,10 @@ Time zone abbreviations
locations while uninhabited.
The leading '-
' is a flag that the UT offset is in
some sense undefined; this notation is derived
- from Internet
+ from Internet
RFC 3339.
(The abbreviation 'Z' that
- Internet
+ Internet
RFC 9557 uses for this concept
would violate the POSIX requirement
of at least three characters in an abbreviation.)
@@ -1115,8 +1126,8 @@ Extensions to POSIX in the
the name of a file from which time-related information is read.
The file's format is TZif,
a timezone information format that contains binary data; see
- Internet
- RFC 8536.
+ Internet
+ RFC 9636.
The daylight saving time rules to be used for a
particular timezone are encoded in the
TZif file; the format of the file allows US,
@@ -1201,12 +1212,15 @@ POSIX features no longer needed
The tm_isdst
member is almost never needed and most of
its uses should be discouraged in favor of the abovementioned
APIs.
+ It was intended as an index into the tzname
variable,
+ but as mentioned previously that usage is obsolete.
Although it can still be used in arguments to
mktime
to disambiguate timestamps near
a DST transition when the clock jumps back on
platforms lacking tm_gmtoff
, this
- disambiguation does not work when standard time itself jumps back,
- which can occur when a location changes to a time zone with a
+ disambiguation works only for proleptic TZ
strings;
+ it does not work in general for geographical timezones,
+ such as when a location changes to a time zone with a
lesser UT offset.
@@ -1223,8 +1237,8 @@ Other portability notes
Programs that in the past used the timezone
function
may now examine localtime(&clock)->tm_zone
(if TM_ZONE
is defined) or
- tzname[localtime(&clock)->tm_isdst]
- (if HAVE_TZNAME
is nonzero) to learn the correct time
+ use strftime
with a %Z
conversion specification
+ to learn the correct time
zone abbreviation to use.
diff --git a/time2posix.3 b/time2posix.3
index 6644060a..4a6969ed 100644
--- a/time2posix.3
+++ b/time2posix.3
@@ -5,15 +5,13 @@
time2posix, posix2time \- convert seconds since the Epoch
.SH SYNOPSIS
.nf
-.ie \n(.g .ds - \f(CR-\fP
-.el .ds - \-
.B #include
.PP
.B time_t time2posix(time_t t);
.PP
.B time_t posix2time(time_t t);
.PP
-.B cc ... \*-ltz
+.B cc ... \-ltz
.fi
.SH DESCRIPTION
.ie '\(en'' .ds en \-
diff --git a/tz-link.html b/tz-link.html
index be2aae54..f4f76fdd 100644
--- a/tz-link.html
+++ b/tz-link.html
@@ -194,9 +194,9 @@ Downloading the tz
database
The code lets you compile the tz
source files into
machine-readable binary files, one for each location. The binary files
are in a special format specified by
-The
+The
Time Zone Information Format (TZif)
-(Internet RFC 8536).
+(Internet RFC 9636).
The code also lets
you read a TZif file and interpret timestamps for that
location.
@@ -260,7 +260,7 @@ Changes to the tz
database
For further information about updates, please see
-Procedures for
+Procedures for
Maintaining the Time Zone Database (Internet RFC 6557).
More detail can be
found in Theory and pragmatics of the
@@ -379,26 +379,26 @@ Network protocols for tz
data
The Internet Engineering Task Force's
Time Zone Data
Distribution Service (tzdist) working group defined TZDIST
+href="https://www.rfc-editor.org/rfc/rfc7808">TZDIST
(Internet RFC 7808), a time zone data distribution service,
-along with CalDAV
+along with CalDAV
(Internet RFC 7809), a calendar access protocol for
transferring time zone data by reference.
TZDIST
implementations are available.
The tzdist-bis
mailing list discusses possible extensions.
-The
+The
Internet Calendaring and Scheduling Core Object Specification
(iCalendar) (Internet RFC 5445)
covers time zone
data; see its VTIMEZONE calendar component.
The iCalendar format requires specialized parsers and generators; a
-variant xCal
+variant xCal
(Internet RFC 6321) uses
XML format, and a variant
-jCal
+jCal
(Internet RFC 7265)
uses JSON format.
@@ -935,7 +935,13 @@ National histories of legal time
United States
The Department of Transportation's Recent
-Time Zone Proceedings lists changes to time zone boundaries.
+Time Zone Proceedings lists changes to
+official written time zone boundaries, and its Time
+Zones dataset maps current boundaries.
+These boundaries are only for standard time, so the current map puts
+all of Arizona in one time zone even though part of Arizona
+observes DST and part does not.
Uruguay
The Oceanography, Hydrography, and Meteorology Service of the Uruguayan
Navy (SOHMA) publishes an annual Costs and benefits of time shifts
J Biol Rhythms. 2019;34(3):227–230.
doi:10.1177/0748730419854197.
The Society for Research on Biological Rhythms
-opposes DST changes and permanent DST, and advocates that governments adopt
+opposes DST changes and permanent DST,
+and advocates that governments adopt
"permanent Standard Time for the health and safety of their citizens".
@@ -1023,7 +1030,7 @@ Precision timekeeping
can achieve submicrosecond clock accuracy on a local area network
with special-purpose hardware.
Timezone
+href="https://www.rfc-editor.org/rfc/rfc4833">Timezone
Options for DHCP
(Internet RFC 4833)
specifies a Precision timekeeping
href="https://github.com/google/unsmear">supports conversion between
UTC and smeared POSIX timestamps, and is used by major
cloud service providers. However, according to
-§3.7.1 of
+§3.7.1 of
Network Time Protocol Best Current Practices
(Internet RFC 8633), leap smearing is not suitable for
applications requiring accurate UTC or civil time,
@@ -1165,16 +1172,16 @@ Time notation
XML
Schema: Datatypes – dateTime specifies a format inspired by
ISO 8601 that is in common use in XML data.
-§3.3 of
+§3.3 of
Internet Message Format (Internet RFC 5322)
specifies the time notation used in email and HTTP
headers.
-Date and Time
+Date and Time
on the Internet: Timestamps (Internet RFC 3339)
specifies an ISO 8601 profile for use in new Internet protocols.
-An extension, Date
+An extension, Date
and Time on the Internet: Timestamps with Additional Information
(Internet RFC 9557) extends this profile
to let you specify the tzdb
timezone of a timestamp
diff --git a/tzfile.5 b/tzfile.5
index 6e2fd70b..a021859d 100644
--- a/tzfile.5
+++ b/tzfile.5
@@ -11,13 +11,11 @@ tzfile \- timezone information
.de q
\\$3\*(lq\\$1\*(rq\\$2
..
-.ie \n(.g .ds - \f(CR-\fP
-.el .ds - \-
The timezone information files used by
.BR tzset (3)
are typically found under a directory with a name like
.IR /usr/share/zoneinfo .
-These files use the format described in Internet RFC 8536.
+These files use the format described in Internet RFC 9636.
Each file is a sequence of 8-bit bytes.
In a file, a binary integer is represented by a sequence of one or
more bytes in network order (bigendian, or high-order byte first),
@@ -123,7 +121,7 @@ and
serves as an index into the array of time zone abbreviation bytes
that follow the
.B ttinfo
-entries in the file; if the designated string is "\*-00", the
+entries in the file; if the designated string is "\-00", the
.B ttinfo
entry is a placeholder indicating that local time is unspecified.
The
@@ -146,7 +144,7 @@ The encoding of these strings is not specified.
.IP \(bu
.B tzh_leapcnt
pairs of four-byte values, written in network byte order;
-the first value of each pair gives the nonnegative time
+the first value of each pair gives the non-negative time
(as returned by
.BR time (2))
at which a leap second occurs or at which the leap second table expires;
@@ -159,7 +157,7 @@ Each pair denotes one leap second, either positive or negative,
except that if the last pair has the same correction as the previous one,
the last pair denotes the leap second table's expiration time.
Each leap second is at the end of a UTC calendar month.
-The first leap second has a nonnegative occurrence time,
+The first leap second has a non-negative occurrence time,
and is a positive leap second if and only if its correction is positive;
the correction for each leap second after the first differs
from the previous leap second by either 1 for a positive leap second,
@@ -188,7 +186,7 @@ The standard/wall and UT/local indicators were designed for
transforming a TZif file's transition times into transitions appropriate
for another time zone specified via
a proleptic TZ string that lacks rules.
-For example, when TZ="EET\*-2EEST" and there is no TZif file "EET\*-2EEST",
+For example, when TZ="EET\-2EEST" and there is no TZif file "EET\-2EEST",
the idea was to adapt the transition times from a TZif file with the
well-known name "posixrules" that is present only for this purpose and
is a copy of the file "Europe/Brussels", a file with a different UT offset.
@@ -197,7 +195,7 @@ the default rules are installation-dependent, and no implementation
is known to support this feature for timestamps past 2037,
so users desiring (say) Greek time should instead specify
TZ="Europe/Athens" for better historical coverage, falling back on
-TZ="EET\*-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required
+TZ="EET\-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required
and older timestamps need not be handled accurately.
.PP
The
@@ -223,7 +221,7 @@ after the last transition time stored in the file
or for all instants if the file has no transitions.
The TZ string is empty (i.e., nothing between the newlines)
if there is no proleptic representation for such instants.
-If nonempty, the TZ string must agree with the local time
+If non-empty, the TZ string must agree with the local time
type after the last transition time if present in the eight-byte data;
for example, given the string
.q "WET0WEST,M3.5.0/1,M10.5.0"
@@ -238,7 +236,7 @@ the earliest transition time.
For version-3-format timezone files, a TZ string (see
.BR newtzset (3))
may use the following POSIX.1-2024 extensions to POSIX.1-2017:
-First, as in TZ="<\*-02>2<\*-01>,M3.5.0/\*-1,M10.5.0/0",
+First, as in TZ="<\-02>2<\-01>,M3.5.0/\-1,M10.5.0/0",
the hours part of its transition times may be signed and range from
\-167 through 167 instead of being limited to unsigned values
from 0 through 24.
@@ -294,7 +292,7 @@ time did not exist (possibly with an error indication).
Time zone designations should consist of at least three (3)
and no more than six (6) ASCII characters from the set of
alphanumerics,
-.q "\*-",
+.q "\-",
and
.q "+".
This is for compatibility with POSIX requirements for
@@ -318,16 +316,16 @@ through 60 instead of the usual 59; the UTC offset is unaffected.
This section documents common problems in reading or writing TZif files.
Most of these are problems in generating TZif files for use by
older readers.
-The goals of this section are:
+The goals of this section are to help:
.RS "\w' 'u"
.IP \(bu "\w'\(bu 'u"
-to help TZif writers output files that avoid common
+TZif writers output files that avoid common
pitfalls in older or buggy TZif readers,
.IP \(bu
-to help TZif readers avoid common pitfalls when reading
+TZif readers avoid common pitfalls when reading
files generated by future TZif writers, and
.IP \(bu
-to help any future specification authors see what sort of
+any future specification authors see what sort of
problems arise when the TZif format is changed.
.RE
.PP
@@ -338,9 +336,9 @@ reader was designed for.
When complete compatibility was not achieved, an attempt was
made to limit glitches to rarely used timestamps and allow
simple partial workarounds in writers designed to generate
-new-version data useful even for older-version readers.
+newer-version data useful even for older-version readers.
This section attempts to document these compatibility issues and
-workarounds, as well as to document other common bugs in
+workarounds as well as documenting other common bugs in
readers.
.PP
Interoperability problems with TZif include the following:
@@ -373,15 +371,15 @@ for two time zones east, e.g.,
for a time zone with a never-used standard time (XXX, \-03)
and negative daylight saving time (EDT, \-04) all year.
Alternatively,
-as a partial workaround a writer can substitute standard time
+as a partial workaround, a writer can substitute standard time
for the next time zone east \(en e.g.,
.q "AST4"
for permanent
Atlantic Standard Time (\-04).
.IP \(bu
-Some readers designed for version 2 or 3, and that require strict
-conformance to RFC 8536, reject version 4 files whose leap second
-tables are truncated at the start or that end in expiration times.
+Some readers designed for version 2 or 3 and that require strict
+conformance to RFC 9636 reject version 4 files whose leap second
+tables are truncated at the start or end in expiration times.
.IP \(bu
Some readers ignore the footer, and instead predict future
timestamps from the time type of the last transition.
@@ -396,7 +394,7 @@ and even for current timestamps it can fail for settings like
TZ="Africa/Casablanca". This corresponds to a TZif file
containing explicit transitions through the year 2087,
followed by a footer containing the TZ string
-.q <+01>\*-1 ,
+.q <+01>\-1 ,
which should be used only for timestamps after the last
explicit transition.
.IP \(bu
@@ -407,7 +405,7 @@ As a partial workaround, a writer can output a dummy (no-op)
first transition at an early time.
.IP \(bu
Some readers mishandle timestamps before the first
-transition that has a timestamp not less than \-2**31.
+transition that has a timestamp that is not less than \-2**31.
Readers that support only 32-bit timestamps are likely to be
more prone to this problem, for example, when they process
64-bit transitions only some of which are representable in 32
@@ -419,7 +417,7 @@ Some readers mishandle a transition if its timestamp has
the minimum possible signed 64-bit value.
Timestamps less than \-2**59 are not recommended.
.IP \(bu
-Some readers mishandle TZ strings that
+Some readers mishandle proleptic TZ strings that
contain
.q "<"
or
@@ -436,9 +434,9 @@ non-ASCII characters.
These characters are not recommended.
.IP \(bu
Some readers may mishandle time zone abbreviations that
-contain fewer than 3 or more than 6 characters, or that
+contain fewer than 3 or more than 6 characters or that
contain ASCII characters other than alphanumerics,
-.q "\*-",
+.q "\-",
and
.q "+".
These abbreviations are not recommended.
@@ -448,7 +446,7 @@ daylight-saving time UT offsets that are less than the UT
offsets for the corresponding standard time.
These readers do not support locations like Ireland, which
uses the equivalent of the TZ string
-.q "IST\*-1GMT0,M10.5.0,M3.5.0/1",
+.q "IST\-1GMT0,M10.5.0,M3.5.0/1",
observing standard time
(IST, +01) in summer and daylight saving time (GMT, +00) in winter.
As a partial workaround, a writer can output data for the
@@ -461,7 +459,7 @@ abbreviations correctly.
.IP \(bu
Some readers generate ambiguous timestamps for positive leap seconds
that occur when the UTC offset is not a multiple of 60 seconds.
-For example, in a timezone with UTC offset +01:23:45 and with
+For example, with UTC offset +01:23:45 and
a positive leap second 78796801 (1972-06-30 23:59:60 UTC), some readers will
map both 78796800 and 78796801 to 01:23:45 local time the next day
instead of mapping the latter to 01:23:46, and they will map 78796815 to
@@ -480,15 +478,15 @@ Developers of distributed applications should keep this
in mind if they need to deal with pre-1970 data.
.IP \(bu
Some readers mishandle timestamps before the first
-transition that has a nonnegative timestamp.
+transition that has a non-negative timestamp.
Readers that do not support negative timestamps are likely to
be more prone to this problem.
.IP \(bu
Some readers mishandle time zone abbreviations like
-.q "\*-08"
+.q "\-08"
that contain
.q "+",
-.q "\*-",
+.q "\-",
or digits.
.IP \(bu
Some readers mishandle UT offsets that are out of the
@@ -497,7 +495,7 @@ support locations like Kiritimati that are outside this
range.
.IP \(bu
Some readers mishandle UT offsets in the range [\-3599, \-1]
-seconds from UT, because they integer-divide the offset by
+seconds from UT because they integer-divide the offset by
3600 to get 0 and then display the hour part as
.q "+00".
.IP \(bu
@@ -513,10 +511,10 @@ of one hour, or of 15 minutes, or of 1 minute.
.BR zic (8).
.PP
Olson A, Eggert P, Murchison K. The Time Zone Information Format (TZif).
-2019 Feb.
-.UR https://\:datatracker.ietf.org/\:doc/\:html/\:rfc8536
-Internet RFC 8536
+October 2024.
+.UR https://\:www.rfc-editor.org/\:rfc/\:rfc9636
+Internet RFC 9636
.UE
-.UR https://\:doi.org/\:10.17487/\:RFC8536
-doi:10.17487/RFC8536
+.UR https://\:doi.org/\:10.17487/\:RFC9636
+doi:10.17487/RFC9636
.UE .
diff --git a/tzfile.h b/tzfile.h
index b1541466..f8c6c8c5 100644
--- a/tzfile.h
+++ b/tzfile.h
@@ -26,7 +26,7 @@
#endif /* !defined TZDEFRULES */
-/* See Internet RFC 8536 for more details about the following format. */
+/* See Internet RFC 9636 for more details about the following format. */
/*
** Each file begins with. . .
diff --git a/tzselect.8 b/tzselect.8
index ee031614..b83f702d 100644
--- a/tzselect.8
+++ b/tzselect.8
@@ -4,8 +4,6 @@
.SH NAME
tzselect \- select a timezone
.SH SYNOPSIS
-.ie \n(.g .ds - \f(CR-\fP
-.el .ds - \-
.ds d " degrees
.ds m " minutes
.ds s " seconds
@@ -20,15 +18,15 @@ tzselect \- select a timezone
.\}
.B tzselect
[
-.B \*-c
+.B \-c
.I coord
] [
-.B \*-n
+.B \-n
.I limit
] [
-.B \*-\*-help
+.B \-\-help
] [
-.B \*-\*-version
+.B \-\-version
]
.SH DESCRIPTION
The
@@ -40,7 +38,7 @@ The output is suitable as a value for the TZ environment variable.
All interaction with the user is done via standard input and standard error.
.SH OPTIONS
.TP
-.BI "\*-c " coord
+.BI "\-c " coord
Instead of asking for continent and then country and then city,
ask for selection from time zones whose largest cities
are closest to the location with geographical coordinates
@@ -70,27 +68,27 @@ seconds, with any trailing fractions represent fractional minutes or
.I SS
is present) seconds. The decimal point is that of the current locale.
For example, in the (default) C locale,
-.B "\*-c\ +40.689\*-074.045"
+.B "\-c\ +40.689\-074.045"
specifies 40.689\*d\*_N, 74.045\*d\*_W,
-.B "\*-c\ +4041.4\*-07402.7"
+.B "\-c\ +4041.4\-07402.7"
specifies 40\*d\*_41.4\*m\*_N, 74\*d\*_2.7\*m\*_W, and
-.B "\*-c\ +404121\*-0740240"
+.B "\-c\ +404121\-0740240"
specifies 40\*d\*_41\*m\*_21\*s\*_N, 74\*d\*_2\*m\*_40\*s\*_W.
If
.I coord
is not one of the documented forms, the resulting behavior is unspecified.
.TP
-.BI "\*-n " limit
+.BI "\-n " limit
When
-.B \*-c
+.B \-c
is used, display the closest
.I limit
locations (default 10).
.TP
-.B "\*-\*-help"
+.B "\-\-help"
Output help information and exit.
.TP
-.B "\*-\*-version"
+.B "\-\-version"
Output version information and exit.
.SH "ENVIRONMENT VARIABLES"
.TP
diff --git a/zdump.8 b/zdump.8
index 38dd8614..9996039e 100644
--- a/zdump.8
+++ b/zdump.8
@@ -18,22 +18,27 @@ zdump \- timezone dumper
.de q
\\$3\*(lq\\$1\*(rq\\$2
..
-.ie \n(.g .ds - \f(CR-\fP
-.el .ds - \-
The
.B zdump
program prints the current time in each
.I timezone
named on the command line.
+A
+.I timezone
+of
+.B \-
+is treated as if it were /dev/stdin;
+this can be used to pipe TZif data into
+.BR zdump .
.SH OPTIONS
.TP
-.B \*-\*-version
+.B \-\-version
Output version information and exit.
.TP
-.B \*-\*-help
+.B \-\-help
Output short usage message and exit.
.TP
-.B \*-i
+.B \-i
Output a description of time intervals. For each
.I timezone
on the command line, output an interval-format description of the
@@ -41,7 +46,7 @@ timezone. See
.q "INTERVAL FORMAT"
below.
.TP
-.B \*-v
+.B \-v
Output a verbose description of time intervals.
For each
.I timezone
@@ -67,26 +72,26 @@ if the given local time is known to be
.I N
seconds east of Greenwich.
.TP
-.B \*-V
+.B \-V
Like
-.BR \*-v ,
+.BR \-v ,
except omit output concerning extreme time and year values.
This generates output that is easier to compare to that of
implementations with different time representations.
.TP
-.BI "\*-c " \fR[\fIloyear , \fR]\fIhiyear
+.BI "\-c " \fR[\fIloyear , \fR]\fIhiyear
Cut off interval output at the given year(s).
Cutoff times are computed using the proleptic Gregorian calendar with year 0
and with Universal Time (UT) ignoring leap seconds.
Cutoffs are at the start of each year, where the lower-bound
timestamp is inclusive and the upper is exclusive; for example,
-.B "\*-c 1970,2070"
+.B "\-c 1970,2070"
selects transitions on or after 1970-01-01 00:00:00 UTC
and before 2070-01-01 00:00:00 UTC.
The default cutoff is
-.BR \*-500,2500 .
+.BR \-500,2500 .
.TP
-.BI "\*-t " \fR[\fIlotime , \fR]\fIhitime
+.BI "\-t " \fR[\fIlotime , \fR]\fIhitime
Cut off interval output at the given time(s),
given in decimal seconds since 1970-01-01 00:00:00
Coordinated Universal Time (UTC).
@@ -94,7 +99,7 @@ The
.I timezone
determines whether the count includes leap seconds.
As with
-.BR \*-c ,
+.BR \-c ,
the cutoff's lower bound is inclusive and its upper bound is exclusive.
.SH "INTERVAL FORMAT"
The interval format is a compact text representation that is intended
@@ -104,7 +109,7 @@ then a line
where
.I string
is a double-quoted string giving the timezone, a second line
-.q "\*- \*- \fIinterval\fP"
+.q "\- \- \fIinterval\fP"
describing the time interval before the first transition if any, and
zero or more following lines
.q "\fIdate time interval\fP",
@@ -130,11 +135,11 @@ daylight saving time and negative for unknown.
In times and in UT offsets with absolute value less than 100 hours,
the seconds are omitted if they are zero, and
the minutes are also omitted if they are also zero. Positive UT
-offsets are east of Greenwich. The UT offset \*-00 denotes a UT
+offsets are east of Greenwich. The UT offset \-00 denotes a UT
placeholder in areas where the actual offset is unspecified; by
convention, this occurs when the UT offset is zero and the time zone
abbreviation begins with
-.q "\*-"
+.q "\-"
or is
.q "zzz".
.PP
@@ -211,9 +216,9 @@ This works in all real-world cases;
one can construct artificial time zones for which this fails.
.PP
In the
-.B \*-v
+.B \-v
and
-.B \*-V
+.B \-V
output,
.q "UT"
denotes the value returned by
diff --git a/zdump.c b/zdump.c
index e8178733..8e836e60 100644
--- a/zdump.c
+++ b/zdump.c
@@ -14,10 +14,6 @@
#include "private.h"
#include
-#ifndef HAVE_SNPRINTF
-# define HAVE_SNPRINTF (!PORT_TO_C89 || 199901 <= __STDC_VERSION__)
-#endif
-
#ifndef HAVE_LOCALTIME_R
# define HAVE_LOCALTIME_R 1
#endif
@@ -148,17 +144,6 @@ sumsize(ptrdiff_t a, ptrdiff_t b)
size_overflow();
}
-/* Return the size of of the string STR, including its trailing NUL.
- Report an error and exit if this would exceed INDEX_MAX which means
- pointer subtraction wouldn't work. */
-static ptrdiff_t
-xstrsize(char const *str)
-{
- size_t len = strlen(str);
- if (len < INDEX_MAX)
- return len + 1;
- size_overflow();
-}
/* Return a pointer to a newly allocated buffer of size SIZE, exiting
on failure. SIZE should be positive. */
@@ -266,7 +251,7 @@ tzalloc(char const *val)
static ptrdiff_t fakeenv0size;
void *freeable = NULL;
char **env = fakeenv, **initial_environ;
- ptrdiff_t valsize = xstrsize(val);
+ ptrdiff_t valsize = strlen(val) + 1;
if (fakeenv0size < valsize) {
char **e = environ, **to;
ptrdiff_t initial_nenvptrs = 1; /* Counting the trailing NULL pointer. */
@@ -425,7 +410,7 @@ saveabbr(char **buf, ptrdiff_t *bufalloc, struct tm const *tmp)
if (HAVE_LOCALTIME_RZ)
return ab;
else {
- ptrdiff_t absize = xstrsize(ab);
+ ptrdiff_t absize = strlen(ab) + 1;
if (*bufalloc < absize) {
free(*buf);
@@ -487,6 +472,7 @@ main(int argc, char *argv[])
register time_t cuthitime;
time_t now;
bool iflag = false;
+ size_t arglenmax = 0;
cutlotime = absolute_min_time;
cuthitime = absolute_max_time;
@@ -586,15 +572,21 @@ main(int argc, char *argv[])
now = time(NULL);
now |= !now;
}
- longest = 0;
for (i = optind; i < argc; i++) {
size_t arglen = strlen(argv[i]);
- if (longest < arglen)
- longest = min(arglen, INT_MAX);
+ if (arglenmax < arglen)
+ arglenmax = arglen;
}
+ if (!HAVE_SETENV && INDEX_MAX <= arglenmax)
+ size_overflow();
+ longest = min(arglenmax, INT_MAX - 2);
for (i = optind; i < argc; ++i) {
- timezone_t tz = tzalloc(argv[i]);
+ /* Treat "-" as standard input on platforms with /dev/stdin.
+ It's not worth the bother of supporting "-" on other
+ platforms, as that would need temp files. */
+ timezone_t tz = tzalloc(strcmp(argv[i], "-") == 0
+ ? "/dev/stdin" : argv[i]);
char const *ab;
time_t t;
struct tm tm, newtm;
@@ -695,7 +687,7 @@ yeartot(intmax_t y)
return absolute_max_time;
seconds = diff400 * SECSPER400YEARS;
years = diff400 * 400;
- } else {
+ } else {
seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
years = 1;
}
@@ -926,13 +918,10 @@ showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi)
}
}
-#if HAVE_SNPRINTF
-# define my_snprintf snprintf
-#else
+/* On pre-C99 platforms, a snprintf substitute good enough for us. */
+#if !HAVE_SNPRINTF
# include
-
-/* A substitute for snprintf that is good enough for zdump. */
-static int
+ATTRIBUTE_FORMAT((printf, 3, 4)) static int
my_snprintf(char *s, size_t size, char const *format, ...)
{
int n;
@@ -960,6 +949,7 @@ my_snprintf(char *s, size_t size, char const *format, ...)
va_end(args);
return n;
}
+# define snprintf my_snprintf
#endif
/* Store into BUF, of size SIZE, a formatted local time taken from *TM.
@@ -974,10 +964,10 @@ 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
- ? my_snprintf(buf, size, "%02d:%02d:%02d", hh, mm, ss)
+ ? snprintf(buf, size, "%02d:%02d:%02d", hh, mm, ss)
: mm
- ? my_snprintf(buf, size, "%02d:%02d", hh, mm)
- : my_snprintf(buf, size, "%02d", hh));
+ ? snprintf(buf, size, "%02d:%02d", hh, mm)
+ : snprintf(buf, size, "%02d", hh));
}
/* Store into BUF, of size SIZE, a formatted UT offset for the
@@ -1012,10 +1002,10 @@ format_utc_offset(char *buf, ptrdiff_t size, struct tm const *tm, time_t t)
mm = off / 60 % 60;
hh = off / 60 / 60;
return (ss || 100 <= hh
- ? my_snprintf(buf, size, "%c%02ld%02d%02d", sign, hh, mm, ss)
+ ? snprintf(buf, size, "%c%02ld%02d%02d", sign, hh, mm, ss)
: mm
- ? my_snprintf(buf, size, "%c%02ld%02d", sign, hh, mm)
- : my_snprintf(buf, size, "%c%02ld", sign, hh));
+ ? snprintf(buf, size, "%c%02ld%02d", sign, hh, mm)
+ : snprintf(buf, size, "%c%02ld", sign, hh));
}
/* Store into BUF (of size SIZE) a quoted string representation of P.
@@ -1118,7 +1108,7 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt,
for (abp = ab; is_alpha(*abp); abp++)
continue;
len = (!*abp && *ab
- ? my_snprintf(b, s, "%s", ab)
+ ? snprintf(b, s, "%s", ab)
: format_quoted_string(b, s, ab));
if (s <= len)
return false;
@@ -1126,7 +1116,7 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt,
}
formatted_len
= (tm->tm_isdst
- ? my_snprintf(b, s, &"\t\t%d"[show_abbr], tm->tm_isdst)
+ ? snprintf(b, s, &"\t\t%d"[show_abbr], tm->tm_isdst)
: 0);
}
break;
diff --git a/zic.8 b/zic.8
index 00e2536b..4eeb7a46 100644
--- a/zic.8
+++ b/zic.8
@@ -22,14 +22,8 @@ zic \- timezone compiler
.el .ds < \(la
.ie '\(ra'' .ds > >
.el .ds > \(ra
-.ie \n(.g \{\
-. ds : \:
-. ds - \f(CR-\fP
-.\}
-.el \{\
-. ds :
-. ds - \-
-.\}
+.ie \n(.g .ds : \:
+.el .ds : .
.ds d " degrees
.ds m " minutes
.ds s " seconds
@@ -50,17 +44,17 @@ specified in this input.
If a
.I filename
is
-.q "\*-" ,
+.q "\-" ,
standard input is read.
.SH OPTIONS
.TP
-.B "\*-\*-version"
+.B "\-\-version"
Output version information and exit.
.TP
-.B \*-\*-help
+.B \-\-help
Output short usage message and exit.
.TP
-.BI "\*-b " bloat
+.BI "\-b " bloat
Output backward-compatibility data as specified by
.IR bloat .
If
@@ -81,14 +75,14 @@ The default is
as software that mishandles 64-bit data typically
mishandles timestamps after the year 2038 anyway.
Also see the
-.B \*-r
+.B \-r
option for another way to alter output size.
.TP
-.BI "\*-d " directory
+.BI "\-d " directory
Create time conversion information files in the named directory rather than
in the standard directory named below.
.TP
-.BI "\*-l " timezone
+.BI "\-l " timezone
Use
.I timezone
as local time.
@@ -102,19 +96,19 @@ Link \fItimezone\fP localtime
If
.I timezone
is
-.BR \*- ,
+.BR \- ,
any already-existing link is removed.
.TP
-.BI "\*-L " leapsecondfilename
+.BI "\-L " leapsecondfilename
Read leap second information from the file with the given name.
If this option is not used,
no leap second information appears in output files.
.TP
-.BI "\*-p " timezone
+.BI "\-p " timezone
Use
.IR timezone 's
rules when handling nonstandard
-TZ strings like "EET\*-2EEST" that lack transition rules.
+TZ strings like "EET\-2EEST" that lack transition rules.
.B zic
will act as if the input contained a link line of the form
.sp
@@ -124,21 +118,21 @@ Link \fItimezone\fP posixrules
If
.I timezone
is
-.q "\*-"
+.q "\-"
(the default), any already-existing link is removed.
.sp
Unless
.I timezone is
-.q "\*-" ,
+.q "\-" ,
this option is obsolete and poorly supported.
Among other things it should not be used for timestamps after the year 2037,
and it should not be combined with
-.B "\*-b slim"
+.B "\-b slim"
if
.IR timezone 's
transitions are at standard time or Universal Time (UT) instead of local time.
.TP
-.BR "\*-r " "[\fB@\fP\fIlo\fP][\fB/@\fP\fIhi\fP]"
+.BR "\-r " "[\fB@\fP\fIlo\fP][\fB/@\fP\fIhi\fP]"
Limit the applicability of output files
to timestamps in the range from
.I lo
@@ -152,17 +146,17 @@ are possibly signed decimal counts of seconds since the Epoch
(1970-01-01 00:00:00 UTC).
Omitted counts default to extreme values.
The output files use UT offset 0 and abbreviation
-.q "\*-00"
+.q "\-00"
in place of the omitted timestamp data.
For example,
-.q "zic \*-r @0"
+.q "zic \-r @0"
omits data intended for negative timestamps (i.e., before the Epoch), and
-.q "zic \*-r @0/@2147483648"
+.q "zic \-r @0/@2147483648"
outputs data intended only for nonnegative timestamps that fit into
31-bit signed integers.
On platforms with GNU
.BR date ,
-.q "zic \*-r @$(date +%s)"
+.q "zic \-r @$(date +%s)"
omits data intended for past timestamps.
Although this option typically reduces the output file's size,
the size can increase due to the need to represent the timestamp range
@@ -173,10 +167,10 @@ causes a TZif file to contain explicit entries for
transitions rather than concisely representing them
with a proleptic TZ string.
Also see the
-.B "\*-b slim"
+.B "\-b slim"
option for another way to shrink output size.
.TP
-.BI "\*-R @" hi
+.BI "\-R @" hi
Generate redundant trailing explicit transitions for timestamps
that occur less than
.I hi
@@ -187,11 +181,11 @@ Although it accommodates nonstandard TZif readers
that ignore the proleptic TZ string,
it increases the size of the altered output files.
.TP
-.BI "\*-t " file
+.BI "\-t " file
When creating local time information, put the configuration link in
the named file rather than in the standard location.
.TP
-.B \*-v
+.B \-v
Be more verbose, and complain about the following situations:
.RS
.PP
@@ -259,10 +253,10 @@ before 1970 or after the start of 2038.
The output contains a truncated leap second table,
which can cause some older TZif readers to misbehave.
This can occur if the
-.B "\*-L"
+.B "\-L"
option is used, and either an Expires line is present or
the
-.B "\*-r"
+.B "\-r"
option is also used.
.PP
The output file contains more than 1200 transitions,
@@ -276,13 +270,13 @@ POSIX requires at least 3, and requires implementations to support
at least 6.
.PP
An output file name contains a byte that is not an ASCII letter,
-.q "\*-" ,
+.q "\-" ,
.q "/" ,
or
.q "_" ;
or it contains a file name component that contains more than 14 bytes
or that starts with
-.q "\*-" .
+.q "\-" .
.RE
.SH FILES
Input files use the format described in this section; output files use
@@ -301,7 +295,7 @@ non-PPCS bytes. Non-PPCS characters typically occur only in comments:
although output file names and time zone abbreviations can contain
nearly any character, other software will work better if these are
limited to the restricted syntax described under the
-.B \*-v
+.B \-v
option.
.PP
Input lines are made up of fields.
@@ -331,14 +325,14 @@ abbreviation must be unambiguous in context.
A rule line has the form
.nf
.ti +2
-.ta \w'Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'1973\0\0'u +\w'\*-\0\0'u +\w'Apr\0\0'u +\w'lastSun\0\0'u +\w'2:00w\0\0'u +\w'1:00d\0\0'u
+.ta \w'Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'1973\0\0'u +\w'\-\0\0'u +\w'Apr\0\0'u +\w'lastSun\0\0'u +\w'2:00w\0\0'u +\w'1:00d\0\0'u
.sp
-Rule NAME FROM TO \*- IN ON AT SAVE LETTER/S
+Rule NAME FROM TO \- IN ON AT SAVE LETTER/S
.sp
For example:
.ti +2
.sp
-Rule US 1967 1973 \*- Apr lastSun 2:00w 1:00d D
+Rule US 1967 1973 \- Apr lastSun 2:00w 1:00d D
.sp
.fi
The fields that make up a rule line are:
@@ -347,7 +341,7 @@ The fields that make up a rule line are:
Gives the name of the rule set that contains this line.
The name must start with a character that is neither
an ASCII digit nor
-.q \*-
+.q \-
nor
.q + .
To allow for future extensions,
@@ -375,9 +369,9 @@ may be used to repeat the value of the
.B FROM
field.
.TP
-.B \*-
+.B \-
Is a reserved field and should always contain
-.q \*-
+.q \-
for compatibility with older versions of
.BR zic .
It was previously known as the
@@ -389,7 +383,15 @@ of years the rule would apply.
.TP
.B IN
Names the month in which the rule takes effect.
-Month names may be abbreviated.
+Month names may be abbreviated as mentioned previously;
+for example, January can appear as
+.q January ,
+.q JANU
+or
+.q Ja ,
+but not as
+.q j
+which would be ambiguous with both June and July.
.TP
.B ON
Gives the day on which the rule takes effect.
@@ -412,7 +414,12 @@ or a weekday name preceded by
.q "last"
(e.g.,
.BR "lastSunday" )
-may be abbreviated or spelled out in full.
+may be abbreviated as mentioned previously,
+e.g.,
+.q Su
+for Sunday and
+.q lastsa
+for the last Saturday.
There must be no white space characters within the
.B ON
field.
@@ -442,8 +449,8 @@ Recognized forms include:
15:00 3 PM, 15 hours after 00:00
24:00 end of day, 24 hours after 00:00
260:00 260 hours after 00:00
-\*-2:30 2.5 hours before 00:00
-\*- equivalent to 0
+\-2:30 2.5 hours before 00:00
+\- equivalent to 0
.fi
.in
.sp
@@ -517,7 +524,7 @@ or
.q "EDT" )
of time zone abbreviations to be used when this rule is in effect.
If this field is
-.q \*- ,
+.q \- ,
the variable part is null.
.PP
A zone line has the form
@@ -564,7 +571,7 @@ field,
giving the amount of time to be added to local standard time
and whether the resulting time is standard or daylight saving.
Standard time applies if this field is
-.B \*-
+.B \-
or for timestamps occurring before any rule takes effect.
When an amount of time is given, only the sum of standard time and
this amount matters.
@@ -600,9 +607,9 @@ To conform to POSIX, a time zone abbreviation should contain only
alphanumeric ASCII characters,
.q "+"
and
-.q "\*-".
+.q "\-".
By convention, the time zone abbreviation
-.q "\*-00"
+.q "\-00"
is a placeholder that means local time is unspecified.
.TP
.B UNTIL
@@ -661,25 +668,25 @@ For example:
.ne 7
.nf
.in +2
-.ta \w'# Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'2006\0\0'u +\w'\*-\0\0'u +\w'Oct\0\0'u +\w'lastSun\0\0'u +\w'2:00\0\0'u +\w'SAVE\0\0'u
+.ta \w'# Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'2006\0\0'u +\w'\-\0\0'u +\w'Oct\0\0'u +\w'lastSun\0\0'u +\w'2:00\0\0'u +\w'SAVE\0\0'u
.sp
-# Rule NAME FROM TO \*- IN ON AT SAVE LETTER/S
+# Rule NAME FROM TO \- IN ON AT SAVE LETTER/S
Rule US 1967 2006 - Oct lastSun 2:00 0 S
Rule US 1967 1973 - Apr lastSun 2:00 1:00 D
.ta \w'# Zone\0\0'u +\w'America/Menominee\0\0'u +\w'STDOFF\0\0'u +\w'RULES\0\0'u +\w'FORMAT\0\0'u
# Zone NAME STDOFF RULES FORMAT [UNTIL]
-Zone America/Menominee \*-5:00 \*- EST 1973 Apr 29 2:00
- \*-6:00 US C%sT
+Zone America/Menominee \-5:00 \- EST 1973 Apr 29 2:00
+ \-6:00 US C%sT
.sp
.in
.fi
Here, an incorrect reading would be there were two clock changes on 1973-04-29,
-the first from 02:00 EST (\*-05) to 01:00 CST (\*-06),
-and the second an hour later from 02:00 CST (\*-06) to 03:00 CDT (\*-05).
+the first from 02:00 EST (\-05) to 01:00 CST (\-06),
+and the second an hour later from 02:00 CST (\-06) to 03:00 CDT (\-05).
However,
.B zic
-interprets this more sensibly as a single transition from 02:00 CST (\*-05) to
-02:00 CDT (\*-05).
+interprets this more sensibly as a single transition from 02:00 CST (\-05) to
+02:00 CDT (\-05).
.PP
A link line has the form
.sp
@@ -718,7 +725,7 @@ For example:
.ta \w'Zone\0\0'u +\w'Greenwich\0\0'u
Link Greenwich G_M_T
Link Etc/GMT Greenwich
-Zone Etc/GMT\0\00\0\0\*-\0\0GMT
+Zone Etc/GMT\0\00\0\0\-\0\0GMT
.sp
.in
.fi
@@ -759,7 +766,7 @@ should be
.q "+"
if a second was added
or
-.q "\*-"
+.q "\-"
if a second was skipped.
The
.B R/S
@@ -783,7 +790,7 @@ rolling leap seconds can be useful in specialized applications
like SMPTE timecodes that may prefer to put leap second
discontinuities at the end of a local broadcast day.
However, rolling leap seconds are not supported if the
-.B \*-r
+.B \-r
option is used.
.PP
The expiration line, if present, has the form:
@@ -814,23 +821,23 @@ Here is an extended example of
input, intended to illustrate many of its features.
.nf
.in +2
-.ta \w'# Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'1973\0\0'u +\w'\*-\0\0'u +\w'Apr\0\0'u +\w'lastSun\0\0'u +\w'2:00\0\0'u +\w'SAVE\0\0'u
+.ta \w'# Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'1973\0\0'u +\w'\-\0\0'u +\w'Apr\0\0'u +\w'lastSun\0\0'u +\w'2:00\0\0'u +\w'SAVE\0\0'u
.sp
-# Rule NAME FROM TO \*- IN ON AT SAVE LETTER/S
-Rule Swiss 1941 1942 \*- May Mon>=1 1:00 1:00 S
-Rule Swiss 1941 1942 \*- Oct Mon>=1 2:00 0 \*-
+# Rule NAME FROM TO \- IN ON AT SAVE LETTER/S
+Rule Swiss 1941 1942 \- May Mon>=1 1:00 1:00 S
+Rule Swiss 1941 1942 \- Oct Mon>=1 2:00 0 \-
.sp .5
-Rule EU 1977 1980 \*- Apr Sun>=1 1:00u 1:00 S
-Rule EU 1977 only \*- Sep lastSun 1:00u 0 \*-
-Rule EU 1978 only \*- Oct 1 1:00u 0 \*-
-Rule EU 1979 1995 \*- Sep lastSun 1:00u 0 \*-
-Rule EU 1981 max \*- Mar lastSun 1:00u 1:00 S
-Rule EU 1996 max \*- Oct lastSun 1:00u 0 \*-
+Rule EU 1977 1980 \- Apr Sun>=1 1:00u 1:00 S
+Rule EU 1977 only \- Sep lastSun 1:00u 0 \-
+Rule EU 1978 only \- Oct 1 1:00u 0 \-
+Rule EU 1979 1995 \- Sep lastSun 1:00u 0 \-
+Rule EU 1981 max \- Mar lastSun 1:00u 1:00 S
+Rule EU 1996 max \- Oct lastSun 1:00u 0 \-
.sp
.ta \w'# Zone\0\0'u +\w'Europe/Zurich\0\0'u +\w'0:29:45.50\0\0'u +\w'RULES\0\0'u +\w'FORMAT\0\0'u
# Zone NAME STDOFF RULES FORMAT [UNTIL]
-Zone Europe/Zurich 0:34:08 \*- LMT 1853 Jul 16
- 0:29:45.50 \*- BMT 1894 Jun
+Zone Europe/Zurich 0:34:08 \- LMT 1853 Jul 16
+ 0:29:45.50 \- BMT 1894 Jun
1:00 Swiss CE%sT 1981
1:00 EU CE%sT
.sp
diff --git a/zic.c b/zic.c
index cf8e79df..8a7f83db 100644
--- a/zic.c
+++ b/zic.c
@@ -524,19 +524,19 @@ memcheck(void *ptr)
}
static void *
-emalloc(size_t size)
+xmalloc(size_t size)
{
return memcheck(malloc(size));
}
static void *
-erealloc(void *ptr, size_t size)
+xrealloc(void *ptr, size_t size)
{
return memcheck(realloc(ptr, size));
}
static char *
-estrdup(char const *str)
+xstrdup(char const *str)
{
return memcheck(strdup(str));
}
@@ -565,7 +565,7 @@ growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems,
{
return (nitems < *nitems_alloc
? ptr
- : erealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize)));
+ : xrealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize)));
}
/*
@@ -1321,7 +1321,7 @@ random_dirent(char const **name, char **namealloc)
uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6);
if (!dst) {
- dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
+ dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
memcpy(dst, src, dirlen);
memcpy(dst + dirlen, prefix, prefixlen);
dst[dirlen + prefixlen + suffixlen] = '\0';
@@ -1410,7 +1410,7 @@ relname(char const *target, char const *linkname)
size_t lenslash = len + (len && directory[len - 1] != '/');
size_t targetsize = strlen(target) + 1;
linksize = size_sum(lenslash, targetsize);
- f = result = emalloc(linksize);
+ f = result = xmalloc(linksize);
memcpy(result, directory, len);
result[len] = '/';
memcpy(result + lenslash, target, targetsize);
@@ -1424,7 +1424,7 @@ relname(char const *target, char const *linkname)
dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1);
if (dotdotetcsize <= linksize) {
if (!result)
- result = emalloc(dotdotetcsize);
+ result = xmalloc(dotdotetcsize);
for (i = 0; i < dotdots; i++)
memcpy(result + 3 * i, "../", 3);
memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
@@ -1866,8 +1866,8 @@ inrule(char **fields, int nfields)
fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
fields[RF_TOD]))
return;
- r.r_name = estrdup(fields[RF_NAME]);
- r.r_abbrvar = estrdup(fields[RF_ABBRVAR]);
+ r.r_name = xstrdup(fields[RF_NAME]);
+ r.r_abbrvar = xstrdup(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);
@@ -1950,7 +1950,8 @@ inzsub(char **fields, int nfields, bool iscont)
z.z_filenum = filenum;
z.z_linenum = linenum;
z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
- if ((cp = strchr(fields[i_format], '%')) != 0) {
+ cp = strchr(fields[i_format], '%');
+ if (cp) {
if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
|| strchr(fields[i_format], '/')) {
error(_("invalid abbreviation format"));
@@ -1988,9 +1989,9 @@ inzsub(char **fields, int nfields, bool iscont)
return false;
}
}
- z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]);
- z.z_rule = estrdup(fields[i_rule]);
- z.z_format = cp1 = estrdup(fields[i_format]);
+ z.z_name = iscont ? NULL : xstrdup(fields[ZF_NAME]);
+ z.z_rule = xstrdup(fields[i_rule]);
+ z.z_format = cp1 = xstrdup(fields[i_format]);
if (z.z_format_specifier == 'z') {
cp1[cp - fields[i_format]] = 's';
if (noise)
@@ -2133,8 +2134,8 @@ inlink(char **fields, int nfields)
return;
l.l_filenum = filenum;
l.l_linenum = linenum;
- l.l_target = estrdup(fields[LF_TARGET]);
- l.l_linkname = estrdup(fields[LF_LINKNAME]);
+ l.l_target = xstrdup(fields[LF_TARGET]);
+ l.l_linkname = xstrdup(fields[LF_LINKNAME]);
links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
links[nlinks++] = l;
}
@@ -2157,7 +2158,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 = estrdup(timep);
+ dp = xstrdup(timep);
if (*dp != '\0') {
ep = dp + strlen(dp) - 1;
switch (lowerit(*ep)) {
@@ -2232,19 +2233,23 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
** Sun<=20
** Sun>=7
*/
- dp = estrdup(dayp);
+ dp = xstrdup(dayp);
if ((lp = byword(dp, lasts)) != NULL) {
rp->r_dycode = DC_DOWLEQ;
rp->r_wday = lp->l_value;
rp->r_dayofmonth = len_months[1][rp->r_month];
} else {
- if ((ep = strchr(dp, '<')) != 0)
- rp->r_dycode = DC_DOWLEQ;
- else if ((ep = strchr(dp, '>')) != 0)
- rp->r_dycode = DC_DOWGEQ;
+ ep = strchr(dp, '<');
+ if (ep)
+ rp->r_dycode = DC_DOWLEQ;
else {
+ ep = strchr(dp, '>');
+ if (ep)
+ rp->r_dycode = DC_DOWGEQ;
+ else {
ep = dp;
rp->r_dycode = DC_DOM;
+ }
}
if (rp->r_dycode != DC_DOM) {
*ep++ = 0;
@@ -2386,7 +2391,7 @@ writezone(const char *const name, const char *const string, char version,
/* Allocate the ATS and TYPES arrays via a single malloc,
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,
+ zic_t *ats = xmalloc(align_to(size_product(timecnt + !timecnt,
sizeof *ats + 1),
alignof(zic_t)));
void *typesptr = ats + timecnt;
@@ -2761,7 +2766,7 @@ writezone(const char *const name, const char *const string, char version,
if (thisleapexpiry) {
/* Append a no-op leap correction indicating when the leap
second table expires. Although this does not conform to
- Internet RFC 8536, most clients seem to accept this and
+ Internet RFC 9636, most clients seem to accept this and
the plan is to amend the RFC to allow this in version 4
TZif files. */
puttzcodepass(leapexpires, fp, pass);
@@ -3007,7 +3012,7 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
result[0] = '\0';
- /* Internet RFC 8536 section 5.1 says to use an empty TZ string if
+ /* Internet RFC 9636 section 6.1 says to use an empty TZ string if
future timestamps are truncated. */
if (hi_time < max_time)
return -1;
@@ -3135,9 +3140,9 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
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);
+ startbuf = xmalloc(max_abbr_len + 1);
+ ab = xmalloc(max_abbr_len + 1);
+ envvar = xmalloc(max_envvar_len + 1);
INITIALIZE(untiltime);
INITIALIZE(starttime);
/*
@@ -3912,7 +3917,7 @@ mp = _("time zone abbreviation differs from POSIX standard");
static void
mkdirs(char const *argname, bool ancestors)
{
- char *name = estrdup(argname);
+ char *name = xstrdup(argname);
char *cp = name;
/* On MS-Windows systems, do not worry about drive letters or
diff --git a/zone.tab b/zone.tab
index bfc0b593..d2be6635 100644
--- a/zone.tab
+++ b/zone.tab
@@ -310,7 +310,7 @@ PF -0900-13930 Pacific/Marquesas Marquesas Islands
PF -2308-13457 Pacific/Gambier Gambier Islands
PG -0930+14710 Pacific/Port_Moresby most of Papua New Guinea
PG -0613+15534 Pacific/Bougainville Bougainville
-PH +1435+12100 Asia/Manila
+PH +143512+1205804 Asia/Manila
PK +2452+06703 Asia/Karachi
PL +5215+02100 Europe/Warsaw
PM +4703-05620 America/Miquelon
diff --git a/zone1970.tab b/zone1970.tab
index 7726f39a..5ded0565 100644
--- a/zone1970.tab
+++ b/zone1970.tab
@@ -183,7 +183,7 @@ IR +3540+05126 Asia/Tehran
IT,SM,VA +4154+01229 Europe/Rome
JM +175805-0764736 America/Jamaica
JO +3157+03556 Asia/Amman
-JP +353916+1394441 Asia/Tokyo
+JP,AU +353916+1394441 Asia/Tokyo Eyre Bird Observatory
KE,DJ,ER,ET,KM,MG,SO,TZ,UG,YT -0117+03649 Africa/Nairobi
KG +4254+07436 Asia/Bishkek
KI,MH,TV,UM,WF +0125+17300 Pacific/Tarawa Gilberts, Marshalls, Wake
@@ -246,7 +246,7 @@ PF -0900-13930 Pacific/Marquesas Marquesas Islands
PF -2308-13457 Pacific/Gambier Gambier Islands
PG,AQ,FM -0930+14710 Pacific/Port_Moresby Papua New Guinea (most areas), Chuuk, Yap, Dumont d'Urville
PG -0613+15534 Pacific/Bougainville Bougainville
-PH +1435+12100 Asia/Manila
+PH +143512+1205804 Asia/Manila
PK +2452+06703 Asia/Karachi
PL +5215+02100 Europe/Warsaw
PM +4703-05620 America/Miquelon
@@ -293,7 +293,7 @@ RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea
SA,AQ,KW,YE +2438+04643 Asia/Riyadh Syowa
SB,FM -0932+16012 Pacific/Guadalcanal Pohnpei
SD +1536+03232 Africa/Khartoum
-SG,MY +0117+10351 Asia/Singapore peninsular Malaysia
+SG,AQ,MY +0117+10351 Asia/Singapore peninsular Malaysia, Concordia
SR +0550-05510 America/Paramaribo
SS +0451+03137 Africa/Juba
ST +0020+00644 Africa/Sao_Tome
diff --git a/zonenow.tab b/zonenow.tab
index 01f536b3..d2c1e485 100644
--- a/zonenow.tab
+++ b/zonenow.tab
@@ -97,9 +97,6 @@ XX +1828-06954 America/Santo_Domingo Atlantic Standard ("AST") - eastern Caribbe
# -04/-03 (Chile DST)
XX -3327-07040 America/Santiago most of Chile
#
-# -04/-03 (Paraguay DST)
-XX -2516-05740 America/Asuncion Paraguay
-#
# -04/-03 - AST/ADT (North America DST)
XX +4439-06336 America/Halifax Atlantic ("AST/ADT") - Canada; Bermuda
#
@@ -224,7 +221,7 @@ XX +1345+10031 Asia/Bangkok Russia; Indochina; Christmas Island
XX -0610+10648 Asia/Jakarta Indonesia ("WIB")
#
# +08
-XX +0117+10351 Asia/Singapore Russia; Brunei; Malaysia; Singapore
+XX +0117+10351 Asia/Singapore Russia; Brunei; Malaysia; Singapore; Concordia
#
# +08 - AWST
XX -3157+11551 Australia/Perth Western Australia ("AWST")
@@ -236,7 +233,7 @@ XX +3114+12128 Asia/Shanghai China ("CST")
XX +2217+11409 Asia/Hong_Kong Hong Kong ("HKT")
#
# +08 - PHT
-XX +1435+12100 Asia/Manila Philippines ("PHT")
+XX +143512+1205804 Asia/Manila Philippines ("PHT")
#
# +08 - WITA
XX -0507+11924 Asia/Makassar Indonesia ("WITA")
@@ -248,7 +245,7 @@ XX -3143+12852 Australia/Eucla Eucla
XX +5203+11328 Asia/Chita Russia; Palau; East Timor
#
# +09 - JST
-XX +353916+1394441 Asia/Tokyo Japan ("JST")
+XX +353916+1394441 Asia/Tokyo Japan ("JST"); Eyre Bird Observatory
#
# +09 - KST
XX +3733+12658 Asia/Seoul Korea ("KST")