[PROPOSED] Support timegm by default, as per C23
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
participants (1)
-
Paul Eggert