Here are two proposed patches, regarding non-Gregorian calendars in 'date' (cf. <https://lists.gnu.org/archive/html/bug-gnulib/2025-07/msg00091.html>).
>From 3a7298ccd4c8676f30522745c3cd36d8b1d938cf Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Thu, 17 Jul 2025 16:29:05 +0200 Subject: [PATCH 1/2] date: Force a Gregorian calendar for options --iso-8601 and --rfc-3339 * src/date.c (show_date_helper): Add a use_c_locale parameter. (batch_convert): Add a format_in_c_locale parameter. (main): Set format_in_c_locale to true if any of the options --rfc-3339, --iso-8601, -R is seen. --- src/date.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/date.c b/src/date.c index b55aba757..953962820 100644 --- a/src/date.c +++ b/src/date.c @@ -37,7 +37,7 @@ #define AUTHORS proper_name ("David MacKenzie") -static bool show_date_helper (char const *, struct timespec, timezone_t); +static bool show_date_helper (char const *, bool, struct timespec, timezone_t); enum Time_spec { @@ -336,7 +336,8 @@ adjust_resolution (char const *format) Return true if successful. */ static bool -batch_convert (char const *input_filename, char const *format, +batch_convert (char const *input_filename, + char const *format, bool format_in_c_locale, timezone_t tz, char const *tzstring) { bool ok; @@ -381,7 +382,7 @@ batch_convert (char const *input_filename, char const *format, } else { - ok &= show_date_helper (format, when, tz); + ok &= show_date_helper (format, format_in_c_locale, when, tz); } } @@ -402,6 +403,7 @@ main (int argc, char **argv) struct timespec when; bool set_date = false; char const *format = nullptr; + bool format_in_c_locale = false; bool get_resolution = false; char *batch_file = nullptr; char *reference = nullptr; @@ -451,6 +453,7 @@ main (int argc, char **argv) XARGMATCH ("--rfc-3339", optarg, time_spec_string + 2, time_spec + 2); new_format = rfc_3339_format[i]; + format_in_c_locale = true; break; } case 'I': @@ -468,6 +471,7 @@ main (int argc, char **argv) ? XARGMATCH ("--iso-8601", optarg, time_spec_string, time_spec) : TIME_SPEC_DATE); new_format = iso_8601_format[i]; + format_in_c_locale = true; break; } case 'r': @@ -475,6 +479,7 @@ main (int argc, char **argv) break; case 'R': new_format = rfc_email_format; + format_in_c_locale = true; break; case 's': if (set_datestr) @@ -578,7 +583,8 @@ main (int argc, char **argv) timezone_t tz = tzalloc (tzstring); if (batch_file != nullptr) - ok = batch_convert (batch_file, format_res, tz, tzstring); + ok = batch_convert (batch_file, format_res, format_in_c_locale, + tz, tzstring); else { bool valid_date = true; @@ -643,24 +649,25 @@ main (int argc, char **argv) } } - ok &= show_date_helper (format_res, when, tz); + ok &= show_date_helper (format_res, format_in_c_locale, when, tz); } main_exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); } static bool -show_date_helper (char const *format, struct timespec when, timezone_t tz) +show_date_helper (char const *format, bool use_c_locale, + struct timespec when, timezone_t tz) { if (parse_datetime_flags & PARSE_DATETIME_DEBUG) error (0, 0, _("output format: %s"), quote (format)); - if (format == rfc_email_format) + if (use_c_locale) setlocale (LC_TIME, "C"); bool ok = show_date (format, when, tz); - if (format == rfc_email_format) + if (use_c_locale) setlocale (LC_TIME, ""); putchar ('\n'); -- 2.43.0
>From c9220920335a45c6fdbd9bf0ff2469ddfeb68b96 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Thu, 17 Jul 2025 16:30:57 +0200 Subject: [PATCH 2/2] date: Update documentation regarding non-Gregorian calendars * doc/coreutils.texi (Calendars): New section. --- doc/coreutils.texi | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 7fc2db571..0aad90f22 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -16517,6 +16517,7 @@ is not set. @xref{TZ Variable,, Specifying the Time Zone with @menu * Date format specifiers:: Used in @samp{date '+...'} +* Calendars:: Different concepts of year and month. * Setting the time:: Changing the system clock. * Options for date:: Instead of the current time. @detailmenu @@ -16839,6 +16840,91 @@ width is also present. Other combinations of flags, field widths and modifiers are GNU extensions. +@node Calendars +@subsection Calendars + +@cindex calendar +A calendar is a system that groups some sequences of days into ``months'', +and some sequences of months into ``years''. +In most countries, the calendar in use is the Gregorian calendar, +with months ranging from January (the first month) to December (the 12th month). + +@cindex calendars, non-Gregorian +In some specific countries, other calendars are in effect, and +GNU @command{date} supports them in its output. +The calendar depends on the @code{LC_TIME} category of the current locale: +@itemize +@item +In the locale of Thailand (@code{th_TH.UTF-8}), +the Thai solar calendar is used. +@item +In the locale of Iran (@code{fa_IR}), +the Persian solar Hijri calendar is used. +@item +In the locale of Ethiopia (@code{am_ET}), +the Ethiopian / Ge'ez calendar is used. +@end itemize + +The dates in these calendars look different. +For example, the day the GNU project was announced: +@example +$ LC_ALL=en_US.UTF-8 date +%Y-%m-%d -d 1983-09-27 +1983-09-27 +$ LC_ALL=th_TH.UTF-8 date +%Y-%m-%d -d 1983-09-27 +2526-09-27 +$ LC_ALL=fa_IR date +%Y-%m-%d -d 1983-09-27 +1362-07-05 +$ LC_ALL=am_ET date +%Y-%m-%d -d 1983-09-27 +1976-01-16 +@end example + +In these locales, when a non-Gregorian calendar is in use, +a few date conversion specifiers should not be used, +because they don't apply in the expected way: +@itemize +@item +@samp{%C} for the century, +@item +@samp{%y} for a two-digit year, +@item +@samp{%G} and @samp{%g} for a week-based year, +@item +@samp{%U}, @samp{%W}, and @samp{%V} for the week in the year, +@item +@samp{%j} for the day in the year, +@item +and @samp{%D} for the date in U.S.@: formatting convention. +@end itemize + +If you are using one of these locales +and want to see Gregorian dates nevertheless, +you can achieve that by +@enumerate +@item +making sure that you use the @code{LANG} environment variable, +not the @code{LC_ALL} environment variable, +for specifiying your general locale, and +@item +setting the @code{LC_TIME} environment variable to a locale +that uses the Gregorian calendar. +@end enumerate +@noindent +For example: +@example +$ unset LC_ALL +$ LANG=fa_IR LC_TIME=en_US.UTF-8 date +%Y-%m-%d -d 1983-09-27 +1983-09-27 +@end example + +For more information on how to set your locale, see the GNU gettext manual at +@ifinfo +@ref{Users,,The User's View,gettext}. +@end ifinfo +@ifnotinfo +@url{https://www.gnu.org/software/gettext/manual/html_node/Users.html}. +@end ifnotinfo + + @node Setting the time @subsection Setting the time -- 2.43.0