From 12c84da6bbc2c48b6dceee7fdca281d53de92769 Mon Sep 17 00:00:00 2001 From: simpleqt <89645338+simpleqt@users.noreply.github.com> Date: Sat, 24 Oct 2026 23:17:06 +0800 Subject: [PATCH] dates: return a location without a region when the locale has no name for it get_timezone_location() falls back to the CLDR region 'ZZ' ('unknown region') when the zone's territory has no name in the locale, but it then looked that name up with [] instead of .get(), so every locale that does not translate 'ZZ' -- 347 of the 1,121 locales -- raised KeyError: 'ZZ' for a perfectly valid zone. get_timezone_name() reaches the same code when no zone variant is given, so the crash surfaced through the public name lookup too. Leave the region out of the result in that case, which is what the location format degenerates to when the locale cannot name the region. --- babel/dates.py | 8 ++++++-- tests/test_dates.py | 11 +++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/babel/dates.py b/babel/dates.py index 7b626aa11..a58a180a8 100644 --- a/babel/dates.py +++ b/babel/dates.py @@ -528,10 +528,10 @@ def get_timezone_location( territory = get_global('zone_territories').get(zone) if territory not in locale.territories: territory = 'ZZ' # invalid/unknown - territory_name = locale.territories[territory] + territory_name = locale.territories.get(territory) if ( not return_city - and territory + and territory_name and len(get_global('territory_zones').get(territory, [])) == 1 ): return region_format % territory_name @@ -552,6 +552,10 @@ def get_timezone_location( if return_city: return city_name + if territory_name is None: + # The locale has no name for the zone's region, not even for the + # "unknown region" fallback, so the region is left out. + return region_format % city_name return region_format % ( fallback_format % { diff --git a/tests/test_dates.py b/tests/test_dates.py index 4f8c73907..2297db18c 100644 --- a/tests/test_dates.py +++ b/tests/test_dates.py @@ -284,6 +284,17 @@ def test_get_timezone_location(timezone_getter): 'Deutschland (Berlin) (Ortszeit)') +def test_get_timezone_location_without_a_region_name(timezone_getter): + # Locales without a name for the "unknown region" (CLDR "ZZ") used to + # raise a KeyError instead of falling back to the location without region. + tz = timezone_getter('America/St_Johns') + assert dates.get_timezone_location(tz, locale='aa') == 'St. John’s' + assert dates.get_timezone_location(tz, locale='aa', return_city=True) == 'St. John’s' + assert dates.get_timezone_name(tz, locale='aa') == 'St. John’s' + # Locales that do have a name for it are unchanged. + assert dates.get_timezone_location(tz, locale='en') == 'Canada (St. John’s) Time' + + @pytest.mark.parametrize( ('tzname', 'params', 'expected'), [