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 <[email protected]>
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