]> git.ipfire.org Git - thirdparty/babel.git/commitdiff
Handle ZoneInfo objects in get_timezone_location, get_timezone_name (#741)
authorAlessio Bogon <youtux@users.noreply.github.com>
Tue, 10 Nov 2020 09:34:57 +0000 (10:34 +0100)
committerGitHub <noreply@github.com>
Tue, 10 Nov 2020 09:34:57 +0000 (11:34 +0200)
Fixes #740

.travis.yml
babel/dates.py
tests/test_dates.py
tox.ini

index 0aebbf982a45d974fdc6b9837de77a55411f5938..e7401cc4fd626bbb2bcd656ef6bb02467d4c0360 100644 (file)
@@ -37,7 +37,7 @@ matrix:
 install:
   - bash .ci/deps.${TRAVIS_OS_NAME}.sh
   - pip install --upgrade pip
-  - pip install --upgrade $CDECIMAL pytest==4.3.1 pytest-cov==2.6.1 freezegun==0.3.12
+  - pip install --upgrade $CDECIMAL pytest==4.3.1 pytest-cov==2.6.1 freezegun==0.3.12 'backports.zoneinfo;python_version>="3.6" and python_version<"3.9"'
   - pip install --editable .
 
 script:
index f1bd66faff33e2ba08e5fed2bd91688f7eef638d..1775029faf8036ea627dcb14f2def3f6336f64e1 100644 (file)
@@ -76,6 +76,21 @@ def _get_dt_and_tzinfo(dt_or_tzinfo):
     return dt, tzinfo
 
 
+def _get_tz_name(dt_or_tzinfo):
+    """
+    Get the timezone name out of a time, datetime, or tzinfo object.
+
+    :rtype: str
+    """
+    dt, tzinfo = _get_dt_and_tzinfo(dt_or_tzinfo)
+    if hasattr(tzinfo, 'zone'):  # pytz object
+        return tzinfo.zone
+    elif hasattr(tzinfo, 'key') and tzinfo.key is not None:  # ZoneInfo object
+        return tzinfo.key
+    else:
+        return tzinfo.tzname(dt or datetime.utcnow())
+
+
 def _get_datetime(instant):
     """
     Get a datetime out of an "instant" (date, time, datetime, number).
@@ -500,13 +515,9 @@ def get_timezone_location(dt_or_tzinfo=None, locale=LC_TIME, return_city=False):
     :return: the localized timezone name using location format
 
     """
-    dt, tzinfo = _get_dt_and_tzinfo(dt_or_tzinfo)
     locale = Locale.parse(locale)
 
-    if hasattr(tzinfo, 'zone'):
-        zone = tzinfo.zone
-    else:
-        zone = tzinfo.tzname(dt or datetime.utcnow())
+    zone = _get_tz_name(dt_or_tzinfo)
 
     # Get the canonical time-zone code
     zone = get_global('zone_aliases').get(zone, zone)
@@ -619,10 +630,7 @@ def get_timezone_name(dt_or_tzinfo=None, width='long', uncommon=False,
     dt, tzinfo = _get_dt_and_tzinfo(dt_or_tzinfo)
     locale = Locale.parse(locale)
 
-    if hasattr(tzinfo, 'zone'):
-        zone = tzinfo.zone
-    else:
-        zone = tzinfo.tzname(dt)
+    zone = _get_tz_name(dt_or_tzinfo)
 
     if zone_variant is None:
         if dt is None:
index 5be0d16a1a47ed470c45f7f780e0990faa6d8464..423f737ded2a194dbc457606d4a14dce0f9a1b40 100644 (file)
@@ -24,6 +24,23 @@ from babel.dates import NO_INHERITANCE_MARKER
 from babel.util import FixedOffsetTimezone
 
 
+@pytest.fixture(params=["pytz.timezone", "zoneinfo.ZoneInfo"])
+def timezone_getter(request):
+    if request.param == "pytz.timezone":
+        return timezone
+    elif request.param == "zoneinfo.ZoneInfo":
+        try:
+            import zoneinfo
+        except ImportError:
+            try:
+                from backports import zoneinfo
+            except ImportError:
+                pytest.skip("zoneinfo not available")
+        return zoneinfo.ZoneInfo
+    else:
+        raise NotImplementedError
+
+
 class DateTimeFormatTestCase(unittest.TestCase):
 
     def test_quarter_format(self):
@@ -583,8 +600,8 @@ def test_get_timezone_gmt():
     assert dates.get_timezone_gmt(dt, 'long', locale='fr_FR') == u'UTC-07:00'
 
 
-def test_get_timezone_location():
-    tz = timezone('America/St_Johns')
+def test_get_timezone_location(timezone_getter):
+    tz = timezone_getter('America/St_Johns')
     assert (dates.get_timezone_location(tz, locale='de_DE') ==
             u"Kanada (St. John\u2019s) Zeit")
     assert (dates.get_timezone_location(tz, locale='en') ==
@@ -592,51 +609,83 @@ def test_get_timezone_location():
     assert (dates.get_timezone_location(tz, locale='en', return_city=True) ==
             u'St. John’s')
 
-    tz = timezone('America/Mexico_City')
+    tz = timezone_getter('America/Mexico_City')
     assert (dates.get_timezone_location(tz, locale='de_DE') ==
             u'Mexiko (Mexiko-Stadt) Zeit')
 
-    tz = timezone('Europe/Berlin')
+    tz = timezone_getter('Europe/Berlin')
     assert (dates.get_timezone_location(tz, locale='de_DE') ==
             u'Deutschland (Berlin) Zeit')
 
 
-def test_get_timezone_name():
-    dt = time(15, 30, tzinfo=timezone('America/Los_Angeles'))
-    assert (dates.get_timezone_name(dt, locale='en_US') ==
-            u'Pacific Standard Time')
-    assert (dates.get_timezone_name(dt, locale='en_US', return_zone=True) ==
-            u'America/Los_Angeles')
-    assert dates.get_timezone_name(dt, width='short', locale='en_US') == u'PST'
-
-    tz = timezone('America/Los_Angeles')
-    assert dates.get_timezone_name(tz, locale='en_US') == u'Pacific Time'
-    assert dates.get_timezone_name(tz, 'short', locale='en_US') == u'PT'
-
-    tz = timezone('Europe/Berlin')
-    assert (dates.get_timezone_name(tz, locale='de_DE') ==
-            u'Mitteleurop\xe4ische Zeit')
-    assert (dates.get_timezone_name(tz, locale='pt_BR') ==
-            u'Hor\xe1rio da Europa Central')
-
-    tz = timezone('America/St_Johns')
-    assert dates.get_timezone_name(tz, locale='de_DE') == u'Neufundland-Zeit'
-
-    tz = timezone('America/Los_Angeles')
-    assert dates.get_timezone_name(tz, locale='en', width='short',
-                                   zone_variant='generic') == u'PT'
-    assert dates.get_timezone_name(tz, locale='en', width='short',
-                                   zone_variant='standard') == u'PST'
-    assert dates.get_timezone_name(tz, locale='en', width='short',
-                                   zone_variant='daylight') == u'PDT'
-    assert dates.get_timezone_name(tz, locale='en', width='long',
-                                   zone_variant='generic') == u'Pacific Time'
-    assert dates.get_timezone_name(tz, locale='en', width='long',
-                                   zone_variant='standard') == u'Pacific Standard Time'
-    assert dates.get_timezone_name(tz, locale='en', width='long',
-                                   zone_variant='daylight') == u'Pacific Daylight Time'
-
-    localnow = datetime.utcnow().replace(tzinfo=timezone('UTC')).astimezone(dates.LOCALTZ)
+@pytest.mark.parametrize(
+    "tzname, params, expected",
+    [
+        ("America/Los_Angeles", {"locale": "en_US"}, u"Pacific Time"),
+        ("America/Los_Angeles", {"width": "short", "locale": "en_US"}, u"PT"),
+        ("Europe/Berlin", {"locale": "de_DE"}, u"Mitteleurop\xe4ische Zeit"),
+        ("Europe/Berlin", {"locale": "pt_BR"}, u"Hor\xe1rio da Europa Central"),
+        ("America/St_Johns", {"locale": "de_DE"}, u"Neufundland-Zeit"),
+        (
+            "America/Los_Angeles",
+            {"locale": "en", "width": "short", "zone_variant": "generic"},
+            u"PT",
+        ),
+        (
+            "America/Los_Angeles",
+            {"locale": "en", "width": "short", "zone_variant": "standard"},
+            u"PST",
+        ),
+        (
+            "America/Los_Angeles",
+            {"locale": "en", "width": "short", "zone_variant": "daylight"},
+            u"PDT",
+        ),
+        (
+            "America/Los_Angeles",
+            {"locale": "en", "width": "long", "zone_variant": "generic"},
+            u"Pacific Time",
+        ),
+        (
+            "America/Los_Angeles",
+            {"locale": "en", "width": "long", "zone_variant": "standard"},
+            u"Pacific Standard Time",
+        ),
+        (
+            "America/Los_Angeles",
+            {"locale": "en", "width": "long", "zone_variant": "daylight"},
+            u"Pacific Daylight Time",
+        ),
+        ("Europe/Berlin", {"locale": "en_US"}, u"Central European Time"),
+    ],
+)
+def test_get_timezone_name_tzinfo(timezone_getter, tzname, params, expected):
+    tz = timezone_getter(tzname)
+    assert dates.get_timezone_name(tz, **params) == expected
+
+
+@pytest.mark.parametrize("timezone_getter", ["pytz.timezone"], indirect=True)
+@pytest.mark.parametrize(
+    "tzname, params, expected",
+    [
+        ("America/Los_Angeles", {"locale": "en_US"}, u"Pacific Standard Time"),
+        (
+            "America/Los_Angeles",
+            {"locale": "en_US", "return_zone": True},
+            u"America/Los_Angeles",
+        ),
+        ("America/Los_Angeles", {"width": "short", "locale": "en_US"}, u"PST"),
+    ],
+)
+def test_get_timezone_name_time_pytz(timezone_getter, tzname, params, expected):
+    """pytz (by design) can't determine if the time is in DST or not,
+    so it will always return Standard time"""
+    dt = time(15, 30, tzinfo=timezone_getter(tzname))
+    assert dates.get_timezone_name(dt, **params) == expected
+
+
+def test_get_timezone_name_misc(timezone_getter):
+    localnow = datetime.utcnow().replace(tzinfo=timezone_getter('UTC')).astimezone(dates.LOCALTZ)
     assert (dates.get_timezone_name(None, locale='en_US') ==
             dates.get_timezone_name(localnow, locale='en_US'))
 
diff --git a/tox.ini b/tox.ini
index eccffea9476756b4a94391c027cace8817e2c128..c069c5942f7ad32903530c592c34111e7fd08e47 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -7,6 +7,7 @@ deps =
     pytest-cov==2.6.1
     cdecimal: m3-cdecimal
     freezegun==0.3.12
+    backports.zoneinfo;python_version>"3.6" and python_version<"3.9"
 whitelist_externals = make
 commands = make clean-cldr test
 passenv = PYTHON_TEST_FLAGS