You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
locale.nl_langinfo(): decode LC_TIME items from glibc wide locale data #152905
locale.nl_langinfo() returns the LC_TIME text items — month and day names, the date/time formats, AM/PM strings, alternative digits — decoded with the current LC_CTYPE encoding (PyUnicode_DecodeLocale). This has two drawbacks.
First, it only works if the LC_TIME encoding has a matching Python codec. If a locale's data is in an encoding Python cannot decode, the call fails or returns mojibake, even though the information is available from the C library.
Second, to make the decoding correct when LC_TIME and LC_CTYPE differ, the implementation temporarily switches the global LC_CTYPE locale (see the change_locale() path, added in gh-133740). That global change affects other threads and is the kind of thread-unsafe setlocale() use tracked in gh-127081.
glibc already stores every LC_TIME text item a second time in wide form, exposed through the _NL_W* constants (_NL_WMON_1, _NL_WDAY_1, _NL_WD_T_FMT, _NL_WALT_DIGITS, …). nl_langinfo() returns these as a wchar_t*, i.e. as Unicode code points independent of the locale byte encoding. Reading them needs neither a Python codec nor a temporary LC_CTYPE change.
Proposal: on glibc, map each narrow LC_TIME constant to its wide counterpart and decode the result with PyUnicode_FromWideChar(). The observable result is unchanged for locales that already round-trip today; it becomes correct (and thread-safe) for the cases above.
Scope / notes:
glibc-only. The _NL_W* symbols are glibc-internal (reserved-underscore enum values, no #define, absent in musl / *BSD / macOS), so they can't be feature-detected with #ifdef and are gated on __GLIBC__ — matching the existing glibc-specific code in _localemodule.c.
ERA is excluded: it has no bare wide counterpart (_NL_WERA does not exist, only sub-fields like _NL_WERA_D_FMT), so it keeps the narrow path.
ALT_DIGITS is a NUL-separated multi-string item and is decoded with a wide analogue of the existing decode_strings() helper.
This also unblocks using nl_langinfo() from _strptime for locale-aware parsing without the encoding fragility.
Activity
pythongh-152905: Skip the new nl_langinfo test on non-glibc
pythongh-152905: Address review of nl_langinfo wide LC_TIME decoding
Merge branch 'main' into pythongh-152905-nl-langinfo-wide
pythongh-152905: Tolerate equivalent-space substitution in the encodi…
gh-152905: Decode LC_TIME items in nl_langinfo() from glibc wide data (…