Collin Funk wrote in https://lists.gnu.org/archive/html/bug-gnulib/2025-07/msg00214.html:
> This part of the function body of > gl_locale_name_environ should make it clear: > > /* Setting of LC_ALL overrides all other. */ > retval = getenv ("LC_ALL"); > if (retval != NULL && retval[0] != '\0') > return retval; > /* Next comes the name of the desired category. */ > retval = getenv (categoryname); > if (retval != NULL && retval[0] != '\0') > return retval; > > So, despite setting 'setlocale (LC_TIME, "C")' when doing > 'LC_ALL=am_ET.UTF-8 date --iso-8601=hours' we will receive the value > from LC_ALL in the environment. There are basically two ways to fix this: (a) set the appropriate environment variables (instead of setlocale calls), (b) add an nstrftime_l and fprintftime_l variant and pass a locale that has "C" for the LC_TIME category. (b) is more hairy, when it comes to the "underlying strftime" delegation in gnulib/lib/strftime.c. Therefore here is a proposed fix according to (a). It fixes the test failures on macOS and OpenBSD. It also passes "make syntax-check".
>From 781de8e4b032a710e524ae488204502724956701 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Thu, 31 Jul 2025 18:42:02 +0200 Subject: [PATCH] date: Fix calendar-related test failures on macOS and OpenBSD Reported at <https://bugs.gnu.org/79118>. * bootstrap.conf (gnulib_modules): Add xsetenv. * src/date.c: Include xsetenv.h. (set_LC_TIME): New function. (show_date_helper): Call set_LC_TIME instead of setlocale. * po/POTFILES.in: Add lib/xsetenv.c. --- bootstrap.conf | 1 + gnulib | 2 +- po/POTFILES.in | 1 + src/date.c | 59 +++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/bootstrap.conf b/bootstrap.conf index 72aafddaf..7577cffd5 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -309,6 +309,7 @@ gnulib_modules=" xprintf xprintf-posix xreadlink + xsetenv xstrtod xstrtoimax xstrtol diff --git a/gnulib b/gnulib index 84ddfc7bd..caf768863 160000 --- a/gnulib +++ b/gnulib @@ -1 +1 @@ -Subproject commit 84ddfc7bd29853ed91cdd65c7ce818072959f974 +Subproject commit caf768863e2a411ede373164e861b0bf6b707bcc diff --git a/po/POTFILES.in b/po/POTFILES.in index 95e325336..8e8fb056c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -29,6 +29,7 @@ lib/xalloc-die.c lib/xbinary-io.c lib/xmemcoll.c lib/xprintf.c +lib/xsetenv.c lib/xstrtol-error.c # Package source files diff --git a/src/date.c b/src/date.c index 6979399c3..4a8dabc2e 100644 --- a/src/date.c +++ b/src/date.c @@ -31,6 +31,7 @@ #include "quote.h" #include "show-date.h" #include "stat-time.h" +#include "xsetenv.h" /* The official name of this program (e.g., no 'g' prefix). */ #define PROGRAM_NAME "date" @@ -330,6 +331,48 @@ adjust_resolution (char const *format) return copy; } +/* Set the LC_TIME category of the current locale. + Return the previous value of the LC_TIME category, as a freshly allocated + string or null. */ + +static char * +set_LC_TIME (char const *locale) +{ + /* It is not sufficient to do + setlocale (LC_TIME, locale); + because show_date relies on fprintftime, that uses the Gnulib module + 'localename-unsafe', that looks at the values of the environment variables + (in order to distinguish the default locale from the C locale on platforms + like macOS). */ + char const *all = getenv ("LC_ALL"); + if (all != nullptr && *all != '\0') + { + /* Setting LC_TIME when LC_ALL is set would have no effect. Therefore we + have to unset LC_ALL and sets its value to all locale categories that + are relevant for this program. */ + xsetenv ("LC_CTYPE", all, 1); /* definitely needed */ + xsetenv ("LC_TIME", all, 1); /* definitely needed */ + xsetenv ("LC_MESSAGES", all, 1); /* definitely needed */ + xsetenv ("LC_NUMERIC", all, 1); /* possibly needed */ + /* xsetenv ("LC_COLLATE", all, 1); */ /* not needed */ + /* xsetenv ("LC_MONETARY", all, 1); */ /* not needed */ + unsetenv ("LC_ALL"); + } + + /* Set LC_TIME as an environment variable. */ + char const *value = getenv ("LC_TIME"); + char *ret = (value == nullptr || *value == '\0' ? nullptr : xstrdup (value)); + if (locale != nullptr) + xsetenv ("LC_TIME", locale, 1); + else + unsetenv ("LC_TIME"); + + /* Update the current locale accordingly. */ + setlocale (LC_TIME, ""); + + return ret; +} + /* Parse each line in INPUT_FILENAME as with --date and display each resulting time and date. If the file cannot be opened, tell why then exit. Issue a diagnostic for any lines that cannot be parsed. @@ -662,13 +705,17 @@ show_date_helper (char const *format, bool use_c_locale, if (parse_datetime_flags & PARSE_DATETIME_DEBUG) error (0, 0, _("output format: %s"), quote (format)); + bool ok; if (use_c_locale) - setlocale (LC_TIME, "C"); - - bool ok = show_date (format, when, tz); - - if (use_c_locale) - setlocale (LC_TIME, ""); + { + char *old_locale_category = set_LC_TIME ("C"); + ok = show_date (format, when, tz); + char *new_locale_category = set_LC_TIME (old_locale_category); + free (new_locale_category); + free (old_locale_category); + } + else + ok = show_date (format, when, tz); putchar ('\n'); return ok; -- 2.50.1