Skip to content

Commit 3ce1e61

Browse files
authored
Use standard library timezone instead of FixedOffsetTimezone (#1203)
1 parent 2e56a2a commit 3ce1e61

File tree

4 files changed

+38
-9
lines changed

4 files changed

+38
-9
lines changed

babel/messages/catalog.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from babel.core import Locale, UnknownLocaleError
2424
from babel.dates import format_datetime
2525
from babel.messages.plurals import get_plural
26-
from babel.util import LOCALTZ, FixedOffsetTimezone, _cmp, distinct
26+
from babel.util import LOCALTZ, _cmp, distinct
2727

2828
if TYPE_CHECKING:
2929
from typing_extensions import TypeAlias
@@ -118,7 +118,10 @@ def _parse_datetime_header(value: str) -> datetime.datetime:
118118
net_mins_offset *= plus_minus
119119

120120
# Create an offset object
121-
tzoffset = FixedOffsetTimezone(net_mins_offset)
121+
tzoffset = datetime.timezone(
122+
offset=datetime.timedelta(minutes=net_mins_offset),
123+
name=f'Etc/GMT{net_mins_offset:+d}',
124+
)
122125

123126
# Store the offset in a datetime object
124127
dt = dt.replace(tzinfo=tzoffset)

babel/util.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,20 @@ def wraptext(text: str, width: int = 70, initial_indent: str = '', subsequent_in
255255

256256

257257
class FixedOffsetTimezone(datetime.tzinfo):
258-
"""Fixed offset in minutes east from UTC."""
258+
"""
259+
Fixed offset in minutes east from UTC.
259260
260-
def __init__(self, offset: float, name: str | None = None) -> None:
261+
DEPRECATED: Use the standard library `datetime.timezone` instead.
262+
"""
263+
# TODO (Babel 3.x): Remove this class
261264

265+
def __init__(self, offset: float, name: str | None = None) -> None:
266+
warnings.warn(
267+
"`FixedOffsetTimezone` is deprecated and will be removed in a future version of Babel. "
268+
"Use the standard library `datetime.timezone` class.",
269+
DeprecationWarning,
270+
stacklevel=2,
271+
)
262272
self._offset = datetime.timedelta(minutes=offset)
263273
if name is None:
264274
name = 'Etc/GMT%+d' % offset

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,7 @@ markers = [
5050
]
5151
filterwarnings = [
5252
# The doctest for format_number would raise this, but we don't really want to see it.
53-
"ignore:babel.numbers.format_decimal:DeprecationWarning"
53+
"ignore:babel.numbers.format_decimal:DeprecationWarning",
54+
# FixedOffsetTimezone is still being tested, but we don't want to see the deprecation warning.
55+
"ignore:.*FixedOffsetTimezone:DeprecationWarning",
5456
]

tests/messages/test_catalog.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import copy
1414
import datetime
15+
import pickle
1516
import unittest
1617
from io import StringIO
1718

@@ -524,10 +525,10 @@ def test_catalog_update():
524525

525526
def test_datetime_parsing():
526527
val1 = catalog._parse_datetime_header('2006-06-28 23:24+0200')
527-
assert val1.year == 2006
528-
assert val1.month == 6
529-
assert val1.day == 28
530-
assert val1.tzinfo.zone == 'Etc/GMT+120'
528+
assert val1.timetuple()[:5] == (2006, 6, 28, 23, 24)
529+
assert val1.utctimetuple()[:5] == (2006, 6, 28, 21, 24)
530+
assert val1.tzinfo.tzname(None) == 'Etc/GMT+120'
531+
assert val1 == datetime.datetime(2006, 6, 28, 21, 24, tzinfo=UTC)
531532

532533
val2 = catalog._parse_datetime_header('2006-06-28 23:24')
533534
assert val2.year == 2006
@@ -562,3 +563,16 @@ def test_update_catalog_comments():
562563

563564
# Auto comments will be obliterated here
564565
assert all(message.user_comments for message in catalog if message.id)
566+
567+
568+
def test_catalog_tz_pickleable():
569+
"""
570+
Test that catalogs with timezoned times are pickleable.
571+
This would previously fail with `FixedOffsetTimezone.__init__() missing 1 required positional argument: 'offset'`
572+
when trying to load the pickled data.
573+
"""
574+
pickle.loads(pickle.dumps(pofile.read_po(StringIO(r"""
575+
msgid ""
576+
msgstr ""
577+
"POT-Creation-Date: 2007-04-01 15:30+0200\n"
578+
"""))))

0 commit comments

Comments
 (0)