[tz] [PROPOSED] Support timegm by default, as per C23
Paul Eggert
eggert at cs.ucla.edu
Thu Nov 10 19:32:18 UTC 2022
Also, fix a bug in timegm; it sometimes modified its input even on
failure.
* Makefile, NEWS: Mention this.
* localtime.c (mktmcpy): New static function.
(time2sub): Use it.
(timegm, timeoff): Define even if !STD_INSPIRED.
(timeoff): Make it static if !STD_INSPIRED.
(timegm): Do not modify *TMP on failure, even if only to change
TMP->is_isdst.
* private.h (HAVE_DECL_TIMEGM): Specify reasonable default value.
(timegm): Always declare one way or another.
---
Makefile | 8 +++-----
NEWS | 5 +++++
localtime.c | 53 +++++++++++++++++++++++++++++++++--------------------
private.h | 18 +++++++++++++++---
4 files changed, 56 insertions(+), 28 deletions(-)
diff --git a/Makefile b/Makefile
index 9ee15607..5ec0d4ab 100644
--- a/Makefile
+++ b/Makefile
@@ -209,6 +209,7 @@ LDLIBS=
# For example, N is 252460800 on AmigaOS.
# -DHAVE_DECL_ASCTIME_R=0 if <time.h> does not declare asctime_r
# -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ'
+# -DHAVE_DECL_TIMEGM=0 if <time.h> does not declare timegm
# -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows)
# -DHAVE_GENERIC=0 if _Generic does not work*
# -DHAVE_GETRANDOM if getrandom works (e.g., GNU/Linux),
@@ -344,14 +345,11 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
# If you want functions that were inspired by early versions of X3J11's work,
# add
# -DSTD_INSPIRED
-# to the end of the "CFLAGS=" line. This arranges for the functions
-# "offtime", "timelocal", "timegm", "timeoff",
-# "posix2time", and "time2posix" to be added to the time conversion library.
+# to the end of the "CFLAGS=" line. This arranges for the following
+# functions to be added to the time conversion library.
# "offtime" is like "gmtime" except that it accepts a second (long) argument
# that gives an offset to add to the time_t when converting it.
# "timelocal" is equivalent to "mktime".
-# "timegm" is like "timelocal" except that it turns a struct tm into
-# a time_t using UT (rather than local time as "timelocal" does).
# "timeoff" is like "timegm" except that it accepts a second (long) argument
# that gives an offset to use when converting to a time_t.
# "posix2time" and "time2posix" are described in an included manual page.
diff --git a/NEWS b/NEWS
index 4a053077..23f1f7f1 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ News for the tz database
Briefly:
Fix some pre-1996 timestamps in northern Canada
+ C23 timegm now supported by default
Unreleased, experimental changes
@@ -22,6 +23,10 @@ Unreleased, experimental changes
Changes to code
+ timegm, which tzcode implemented in 1989, will finally be
+ standardized 34 years later as part of C23, so timegm is now
+ supported even if STD_INSPIRED is not defined.
+
Fix bug in zdump's tzalloc emulation on hosts that lack tm_zone.
(Problem reported by Đoàn Trần Công Danh.)
diff --git a/localtime.c b/localtime.c
index 712be135..9935b5d3 100644
--- a/localtime.c
+++ b/localtime.c
@@ -1951,6 +1951,23 @@ tmcomp(register const struct tm *const atmp,
return result;
}
+/* Copy to *DEST from *SRC. Copy only the members needed for mktime,
+ as other members might not be initialized. */
+static void
+mktmcpy(struct tm *dest, struct tm *const src)
+{
+ dest->tm_sec = src->tm_sec;
+ dest->tm_min = src->tm_min;
+ dest->tm_hour = src->tm_hour;
+ dest->tm_mday = src->tm_mday;
+ dest->tm_mon = src->tm_mon;
+ dest->tm_year = src->tm_year;
+ dest->tm_isdst = src->tm_isdst;
+#if defined TM_GMTOFF && ! UNINIT_TRAP
+ dest->TM_GMTOFF = src->TM_GMTOFF;
+#endif
+}
+
static time_t
time2sub(struct tm *const tmp,
struct tm *(*funcp)(struct state const *, time_t const *,
@@ -1972,17 +1989,7 @@ time2sub(struct tm *const tmp,
struct tm yourtm, mytm;
*okayp = false;
-
- yourtm.tm_sec = tmp->tm_sec;
- yourtm.tm_min = tmp->tm_min;
- yourtm.tm_hour = tmp->tm_hour;
- yourtm.tm_mday = tmp->tm_mday;
- yourtm.tm_mon = tmp->tm_mon;
- yourtm.tm_year = tmp->tm_year;
- yourtm.tm_isdst = tmp->tm_isdst;
-#if defined TM_GMTOFF && ! UNINIT_TRAP
- yourtm.TM_GMTOFF = tmp->TM_GMTOFF;
-#endif
+ mktmcpy(&yourtm, tmp);
if (do_norm_secs) {
if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
@@ -2289,7 +2296,6 @@ mktime(struct tm *tmp)
}
#ifdef STD_INSPIRED
-
time_t
timelocal(struct tm *tmp)
{
@@ -2297,13 +2303,9 @@ timelocal(struct tm *tmp)
tmp->tm_isdst = -1; /* in case it wasn't initialized */
return mktime(tmp);
}
-
-time_t
-timegm(struct tm *tmp)
-{
- return timeoff(tmp, 0);
-}
-
+#else
+static
+#endif
time_t
timeoff(struct tm *tmp, long offset)
{
@@ -2313,7 +2315,18 @@ timeoff(struct tm *tmp, long offset)
return time1(tmp, gmtsub, gmtptr, offset);
}
-#endif /* defined STD_INSPIRED */
+time_t
+timegm(struct tm *tmp)
+{
+ time_t t;
+ struct tm tmcpy;
+ mktmcpy(&tmcpy, tmp);
+ tmcpy.tm_wday = -1;
+ t = timeoff(&tmcpy, 0);
+ if (0 <= tmcpy.tm_wday)
+ *tmp = tmcpy;
+ return t;
+}
static int_fast32_t
leapcorr(struct state const *sp, time_t t)
diff --git a/private.h b/private.h
index 7cbd56d2..7320173f 100644
--- a/private.h
+++ b/private.h
@@ -543,9 +543,24 @@ struct tm *localtime(time_t const *);
struct tm *localtime_r(time_t const *restrict, struct tm *restrict);
time_t mktime(struct tm *);
time_t time(time_t *);
+time_t timegm(struct tm *);
void tzset(void);
#endif
+#ifndef HAVE_DECL_TIMEGM
+# if (202311 <= __STDC_VERSION__ \
+ || defined __GLIBC__ || defined __tm_zone /* musl */ \
+ || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
+ || (defined __APPLE__ && defined __MACH__))
+# define HAVE_DECL_TIMEGM true
+# else
+# define HAVE_DECL_TIMEGM false
+# endif
+#endif
+#if !HAVE_DECL_TIMEGM && !defined timegm
+time_t timegm(struct tm *);
+#endif
+
#if !HAVE_DECL_ASCTIME_R && !defined asctime_r
extern char *asctime_r(struct tm const *restrict, char *restrict);
#endif
@@ -582,9 +597,6 @@ extern long altzone;
# if TZ_TIME_T || !defined offtime
struct tm *offtime(time_t const *, long);
# endif
-# if TZ_TIME_T || !defined timegm
-time_t timegm(struct tm *);
-# endif
# if TZ_TIME_T || !defined timelocal
time_t timelocal(struct tm *);
# endif
--
2.37.2
More information about the tz
mailing list