summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAarni Koskela <akx@iki.fi>2023-01-18 11:01:11 +0200
committerGitHub <noreply@github.com>2023-01-18 09:01:11 +0000
commit27380daecb325d39ab62deffde7fba8e494cfefd (patch)
treeab2115343e0e73add4d056c2cbd2bfc8898d9985
parent14216ed8f90832eed9c8ea24442d5b63da4389eb (diff)
downloadbabel-27380daecb325d39ab62deffde7fba8e494cfefd.tar.gz
Unify datetime imports (#945)
Co-authored-by: Jonah Lawrence <jonah@freshidea.com>
-rw-r--r--babel/dates.py247
-rw-r--r--babel/localtime/__init__.py20
-rw-r--r--babel/localtime/_unix.py6
-rw-r--r--babel/localtime/_win32.py4
-rw-r--r--babel/messages/catalog.py21
-rw-r--r--babel/messages/frontend.py6
-rw-r--r--babel/numbers.py24
-rw-r--r--babel/support.py33
-rw-r--r--babel/util.py12
9 files changed, 223 insertions, 150 deletions
diff --git a/babel/dates.py b/babel/dates.py
index f728961..05cfa25 100644
--- a/babel/dates.py
+++ b/babel/dates.py
@@ -29,7 +29,7 @@ except ModuleNotFoundError:
from bisect import bisect_right
from collections.abc import Iterable
-from datetime import date, datetime, time, timedelta, tzinfo
+import datetime
from babel import localtime
from babel.core import Locale, default_locale, get_global
@@ -37,10 +37,10 @@ from babel.localedata import LocaleDataDict
if TYPE_CHECKING:
from typing_extensions import Literal, TypeAlias
- _Instant: TypeAlias = date | time | float | None
+ _Instant: TypeAlias = datetime.date | datetime.time | float | None
_PredefinedTimeFormat: TypeAlias = Literal['full', 'long', 'medium', 'short']
_Context: TypeAlias = Literal['format', 'stand-alone']
- _DtOrTzinfo: TypeAlias = datetime | tzinfo | str | int | time | None
+ _DtOrTzinfo: TypeAlias = datetime.datetime | datetime.tzinfo | str | int | datetime.time | None
# "If a given short metazone form is known NOT to be understood in a given
# locale and the parent locale has this value such that it would normally
@@ -60,13 +60,8 @@ LOCALTZ = localtime.LOCALTZ
LC_TIME = default_locale('LC_TIME')
-# Aliases for use in scopes where the modules are shadowed by local variables
-date_ = date
-datetime_ = datetime
-time_ = time
-
-def _localize(tz: tzinfo, dt: datetime) -> datetime:
+def _localize(tz: datetime.tzinfo, dt: datetime.datetime) -> datetime.datetime:
# Support localizing with both pytz and zoneinfo tzinfos
# nothing to do
if dt.tzinfo is tz:
@@ -83,8 +78,7 @@ def _localize(tz: tzinfo, dt: datetime) -> datetime:
return dt.astimezone(tz)
-
-def _get_dt_and_tzinfo(dt_or_tzinfo: _DtOrTzinfo) -> tuple[datetime_ | None, tzinfo]:
+def _get_dt_and_tzinfo(dt_or_tzinfo: _DtOrTzinfo) -> tuple[datetime.datetime | None, datetime.tzinfo]:
"""
Parse a `dt_or_tzinfo` value into a datetime and a tzinfo.
@@ -93,7 +87,7 @@ def _get_dt_and_tzinfo(dt_or_tzinfo: _DtOrTzinfo) -> tuple[datetime_ | None, tzi
:rtype: tuple[datetime, tzinfo]
"""
if dt_or_tzinfo is None:
- dt = datetime.now()
+ dt = datetime.datetime.now()
tzinfo = LOCALTZ
elif isinstance(dt_or_tzinfo, str):
dt = None
@@ -101,7 +95,7 @@ def _get_dt_and_tzinfo(dt_or_tzinfo: _DtOrTzinfo) -> tuple[datetime_ | None, tzi
elif isinstance(dt_or_tzinfo, int):
dt = None
tzinfo = UTC
- elif isinstance(dt_or_tzinfo, (datetime, time)):
+ elif isinstance(dt_or_tzinfo, (datetime.datetime, datetime.time)):
dt = _get_datetime(dt_or_tzinfo)
if dt.tzinfo is not None:
tzinfo = dt.tzinfo
@@ -125,10 +119,10 @@ def _get_tz_name(dt_or_tzinfo: _DtOrTzinfo) -> str:
elif hasattr(tzinfo, 'key') and tzinfo.key is not None: # ZoneInfo object
return tzinfo.key
else:
- return tzinfo.tzname(dt or datetime.utcnow())
+ return tzinfo.tzname(dt or datetime.datetime.utcnow())
-def _get_datetime(instant: _Instant) -> datetime_:
+def _get_datetime(instant: _Instant) -> datetime.datetime:
"""
Get a datetime out of an "instant" (date, time, datetime, number).
@@ -139,6 +133,7 @@ def _get_datetime(instant: _Instant) -> datetime_:
Dates are converted to naive datetimes with midnight as the time component.
+ >>> from datetime import date, datetime
>>> _get_datetime(date(2015, 1, 1))
datetime.datetime(2015, 1, 1, 0, 0)
@@ -159,18 +154,18 @@ def _get_datetime(instant: _Instant) -> datetime_:
:rtype: datetime
"""
if instant is None:
- return datetime_.utcnow()
+ return datetime.datetime.utcnow()
elif isinstance(instant, int) or isinstance(instant, float):
- return datetime_.utcfromtimestamp(instant)
- elif isinstance(instant, time):
- return datetime_.combine(date.today(), instant)
- elif isinstance(instant, date) and not isinstance(instant, datetime):
- return datetime_.combine(instant, time())
+ return datetime.datetime.utcfromtimestamp(instant)
+ elif isinstance(instant, datetime.time):
+ return datetime.datetime.combine(datetime.date.today(), instant)
+ elif isinstance(instant, datetime.date) and not isinstance(instant, datetime.datetime):
+ return datetime.datetime.combine(instant, datetime.time())
# TODO (3.x): Add an assertion/type check for this fallthrough branch:
return instant
-def _ensure_datetime_tzinfo(datetime: datetime_, tzinfo: tzinfo | None = None) -> datetime_:
+def _ensure_datetime_tzinfo(dt: datetime.datetime, tzinfo: datetime.tzinfo | None = None) -> datetime.datetime:
"""
Ensure the datetime passed has an attached tzinfo.
@@ -178,6 +173,7 @@ def _ensure_datetime_tzinfo(datetime: datetime_, tzinfo: tzinfo | None = None) -
If a tzinfo is passed in, the datetime is normalized to that timezone.
+ >>> from datetime import datetime
>>> _get_tz_name(_ensure_datetime_tzinfo(datetime(2015, 1, 1)))
'UTC'
@@ -190,16 +186,19 @@ def _ensure_datetime_tzinfo(datetime: datetime_, tzinfo: tzinfo | None = None) -
:return: datetime with tzinfo
:rtype: datetime
"""
- if datetime.tzinfo is None:
- datetime = datetime.replace(tzinfo=UTC)
+ if dt.tzinfo is None:
+ dt = dt.replace(tzinfo=UTC)
if tzinfo is not None:
- datetime = datetime.astimezone(get_timezone(tzinfo))
+ dt = dt.astimezone(get_timezone(tzinfo))
if hasattr(tzinfo, 'normalize'): # pytz
- datetime = tzinfo.normalize(datetime)
- return datetime
+ dt = tzinfo.normalize(dt)
+ return dt
-def _get_time(time: time | datetime | None, tzinfo: tzinfo | None = None) -> time:
+def _get_time(
+ time: datetime.time | datetime.datetime | None,
+ tzinfo: datetime.tzinfo | None = None,
+) -> datetime.time:
"""
Get a timezoned time from a given instant.
@@ -209,14 +208,14 @@ def _get_time(time: time | datetime | None, tzinfo: tzinfo | None = None) -> tim
:rtype: time
"""
if time is None:
- time = datetime.utcnow()
+ time = datetime.datetime.utcnow()
elif isinstance(time, (int, float)):
- time = datetime.utcfromtimestamp(time)
+ time = datetime.datetime.utcfromtimestamp(time)
if time.tzinfo is None:
time = time.replace(tzinfo=UTC)
- if isinstance(time, datetime):
+ if isinstance(time, datetime.datetime):
if tzinfo is not None:
time = time.astimezone(tzinfo)
if hasattr(tzinfo, 'normalize'): # pytz
@@ -227,7 +226,7 @@ def _get_time(time: time | datetime | None, tzinfo: tzinfo | None = None) -> tim
return time
-def get_timezone(zone: str | tzinfo | None = None) -> tzinfo:
+def get_timezone(zone: str | datetime.tzinfo | None = None) -> datetime.tzinfo:
"""Looks up a timezone by name and returns it. The timezone object
returned comes from ``pytz`` or ``zoneinfo``, whichever is available.
It corresponds to the `tzinfo` interface and can be used with all of
@@ -260,7 +259,7 @@ def get_timezone(zone: str | tzinfo | None = None) -> tzinfo:
raise LookupError(f"Unknown timezone {zone}") from exc
-def get_next_timezone_transition(zone: tzinfo | None = None, dt: _Instant = None) -> TimezoneTransition:
+def get_next_timezone_transition(zone: datetime.tzinfo | None = None, dt: _Instant = None) -> TimezoneTransition:
"""Given a timezone it will return a :class:`TimezoneTransition` object
that holds the information about the next timezone transition that's going
to happen. For instance this can be used to detect when the next DST
@@ -332,7 +331,13 @@ class TimezoneTransition:
to the :func:`get_next_timezone_transition`.
"""
- def __init__(self, activates: datetime_, from_tzinfo: tzinfo, to_tzinfo: tzinfo, reference_date: datetime_ | None = None):
+ def __init__(
+ self,
+ activates: datetime.datetime,
+ from_tzinfo: datetime.tzinfo,
+ to_tzinfo: datetime.tzinfo,
+ reference_date: datetime.datetime | None = None,
+ ) -> None:
warnings.warn(
"TimezoneTransition is deprecated and will be "
"removed in the next version of Babel. "
@@ -503,11 +508,16 @@ def get_time_format(format: _PredefinedTimeFormat = 'medium', locale: Locale | s
return Locale.parse(locale).time_formats[format]
-def get_timezone_gmt(datetime: _Instant = None, width: Literal['long', 'short', 'iso8601', 'iso8601_short'] = 'long',
- locale: Locale | str | None = LC_TIME, return_z: bool = False) -> str:
+def get_timezone_gmt(
+ datetime: _Instant = None,
+ width: Literal['long', 'short', 'iso8601', 'iso8601_short'] = 'long',
+ locale: Locale | str | None = LC_TIME,
+ return_z: bool = False,
+) -> str:
"""Return the timezone associated with the given `datetime` object formatted
as string indicating the offset from GMT.
+ >>> from datetime import datetime
>>> dt = datetime(2007, 4, 1, 15, 30)
>>> get_timezone_gmt(dt, locale='en')
u'GMT+00:00'
@@ -558,9 +568,12 @@ def get_timezone_gmt(datetime: _Instant = None, width: Literal['long', 'short',
return pattern % (hours, seconds // 60)
-def get_timezone_location(dt_or_tzinfo: _DtOrTzinfo = None, locale: Locale | str | None = LC_TIME,
- return_city: bool = False) -> str:
- u"""Return a representation of the given timezone using "location format".
+def get_timezone_location(
+ dt_or_tzinfo: _DtOrTzinfo = None,
+ locale: Locale | str | None = LC_TIME,
+ return_city: bool = False,
+) -> str:
+ """Return a representation of the given timezone using "location format".
The result depends on both the local display name of the country and the
city associated with the time zone:
@@ -635,12 +648,18 @@ def get_timezone_location(dt_or_tzinfo: _DtOrTzinfo = None, locale: Locale | str
})
-def get_timezone_name(dt_or_tzinfo: _DtOrTzinfo = None, width: Literal['long', 'short'] = 'long', uncommon: bool = False,
- locale: Locale | str | None = LC_TIME, zone_variant: Literal['generic', 'daylight', 'standard'] | None = None,
- return_zone: bool = False) -> str:
+def get_timezone_name(
+ dt_or_tzinfo: _DtOrTzinfo = None,
+ width: Literal['long', 'short'] = 'long',
+ uncommon: bool = False,
+ locale: Locale | str | None = LC_TIME,
+ zone_variant: Literal['generic', 'daylight', 'standard'] | None = None,
+ return_zone: bool = False,
+) -> str:
r"""Return the localized display name for the given timezone. The timezone
may be specified using a ``datetime`` or `tzinfo` object.
+ >>> from datetime import time
>>> dt = time(15, 30, tzinfo=get_timezone('America/Los_Angeles'))
>>> get_timezone_name(dt, locale='en_US')
u'Pacific Standard Time'
@@ -755,10 +774,14 @@ def get_timezone_name(dt_or_tzinfo: _DtOrTzinfo = None, width: Literal['long', '
return get_timezone_location(dt_or_tzinfo, locale=locale)
-def format_date(date: date | None = None, format: _PredefinedTimeFormat | str = 'medium',
- locale: Locale | str | None = LC_TIME) -> str:
+def format_date(
+ date: datetime.date | None = None,
+ format: _PredefinedTimeFormat | str = 'medium',
+ locale: Locale | str | None = LC_TIME,
+) -> str:
"""Return a date formatted according to the given pattern.
+ >>> from datetime import date
>>> d = date(2007, 4, 1)
>>> format_date(d, locale='en_US')
u'Apr 1, 2007'
@@ -778,8 +801,8 @@ def format_date(date: date | None = None, format: _PredefinedTimeFormat | str =
:param locale: a `Locale` object or a locale identifier
"""
if date is None:
- date = date_.today()
- elif isinstance(date, datetime):
+ date = datetime.date.today()
+ elif isinstance(date, datetime.datetime):
date = date.date()
locale = Locale.parse(locale)
@@ -789,10 +812,15 @@ def format_date(date: date | None = None, format: _PredefinedTimeFormat | str =
return pattern.apply(date, locale)
-def format_datetime(datetime: _Instant = None, format: _PredefinedTimeFormat | str = 'medium', tzinfo: tzinfo | None = None,
- locale: Locale | str | None = LC_TIME) -> str:
+def format_datetime(
+ datetime: _Instant = None,
+ format: _PredefinedTimeFormat | str = 'medium',
+ tzinfo: datetime.tzinfo | None = None,
+ locale: Locale | str | None = LC_TIME,
+) -> str:
r"""Return a date formatted according to the given pattern.
+ >>> from datetime import datetime
>>> dt = datetime(2007, 4, 1, 15, 30)
>>> format_datetime(dt, locale='en_US')
u'Apr 1, 2007, 3:30:00 PM'
@@ -826,10 +854,14 @@ def format_datetime(datetime: _Instant = None, format: _PredefinedTimeFormat | s
return parse_pattern(format).apply(datetime, locale)
-def format_time(time: time | datetime | float | None = None, format: _PredefinedTimeFormat | str = 'medium',
- tzinfo: tzinfo | None = None, locale: Locale | str | None = LC_TIME) -> str:
+def format_time(
+ time: datetime.time | datetime.datetime | float | None = None,
+ format: _PredefinedTimeFormat | str = 'medium',
+ tzinfo: datetime.tzinfo | None = None, locale: Locale | str | None = LC_TIME,
+) -> str:
r"""Return a time formatted according to the given pattern.
+ >>> from datetime import datetime, time
>>> t = time(15, 30)
>>> format_time(t, locale='en_US')
u'3:30:00 PM'
@@ -885,7 +917,7 @@ def format_time(time: time | datetime | float | None = None, format: _Predefined
# get reference date for if we need to find the right timezone variant
# in the pattern
- ref_date = time.date() if isinstance(time, datetime) else None
+ ref_date = time.date() if isinstance(time, datetime.datetime) else None
time = _get_time(time, tzinfo)
@@ -895,8 +927,13 @@ def format_time(time: time | datetime | float | None = None, format: _Predefined
return parse_pattern(format).apply(time, locale, reference_date=ref_date)
-def format_skeleton(skeleton: str, datetime: _Instant = None, tzinfo: tzinfo | None = None,
- fuzzy: bool = True, locale: Locale | str | None = LC_TIME) -> str:
+def format_skeleton(
+ skeleton: str,
+ datetime: _Instant = None,
+ tzinfo: datetime.tzinfo | None = None,
+ fuzzy: bool = True,
+ locale: Locale | str | None = LC_TIME,
+) -> str:
r"""Return a time and/or date formatted according to the given pattern.
The skeletons are defined in the CLDR data and provide more flexibility
@@ -904,6 +941,7 @@ def format_skeleton(skeleton: str, datetime: _Instant = None, tzinfo: tzinfo | N
The are defined using the date/time symbols without order or punctuation
and map to a suitable format for the given locale.
+ >>> from datetime import datetime
>>> t = datetime(2007, 4, 1, 15, 30)
>>> format_skeleton('MMMEd', t, locale='fr')
u'dim. 1 avr.'
@@ -945,12 +983,17 @@ TIMEDELTA_UNITS: tuple[tuple[str, int], ...] = (
)
-def format_timedelta(delta: timedelta | int,
- granularity: Literal['year', 'month', 'week', 'day', 'hour', 'minute', 'second'] = 'second',
- threshold: float = .85, add_direction: bool = False, format: Literal['narrow', 'short', 'medium', 'long'] = 'long',
- locale: Locale | str | None = LC_TIME) -> str:
+def format_timedelta(
+ delta: datetime.timedelta | int,
+ granularity: Literal['year', 'month', 'week', 'day', 'hour', 'minute', 'second'] = 'second',
+ threshold: float = .85,
+ add_direction: bool = False,
+ format: Literal['narrow', 'short', 'medium', 'long'] = 'long',
+ locale: Locale | str | None = LC_TIME,
+) -> str:
"""Return a time delta according to the rules of the given locale.
+ >>> from datetime import timedelta
>>> format_timedelta(timedelta(weeks=12), locale='en_US')
u'3 months'
>>> format_timedelta(timedelta(seconds=1), locale='es')
@@ -959,8 +1002,7 @@ def format_timedelta(delta: timedelta | int,
The granularity parameter can be provided to alter the lowest unit
presented, which defaults to a second.
- >>> format_timedelta(timedelta(hours=3), granularity='day',
- ... locale='en_US')
+ >>> format_timedelta(timedelta(hours=3), granularity='day', locale='en_US')
u'1 day'
The threshold parameter can be used to determine at which value the
@@ -1011,7 +1053,7 @@ def format_timedelta(delta: timedelta | int,
' is deprecated. Use "long" instead',
category=DeprecationWarning)
format = 'long'
- if isinstance(delta, timedelta):
+ if isinstance(delta, datetime.timedelta):
seconds = int((delta.days * 86400) + delta.seconds)
else:
seconds = delta
@@ -1047,13 +1089,18 @@ def format_timedelta(delta: timedelta | int,
return u''
-def _format_fallback_interval(start: _Instant, end: _Instant, skeleton: str | None, tzinfo: tzinfo | None,
- locale: Locale | str | None = LC_TIME) -> str:
+def _format_fallback_interval(
+ start: _Instant,
+ end: _Instant,
+ skeleton: str | None,
+ tzinfo: datetime.tzinfo | None,
+ locale: Locale | str | None = LC_TIME,
+) -> str:
if skeleton in locale.datetime_skeletons: # Use the given skeleton
format = lambda dt: format_skeleton(skeleton, dt, tzinfo, locale=locale)
- elif all((isinstance(d, date) and not isinstance(d, datetime)) for d in (start, end)): # Both are just dates
+ elif all((isinstance(d, datetime.date) and not isinstance(d, datetime.datetime)) for d in (start, end)): # Both are just dates
format = lambda dt: format_date(dt, locale=locale)
- elif all((isinstance(d, time) and not isinstance(d, date)) for d in (start, end)): # Both are times
+ elif all((isinstance(d, datetime.time) and not isinstance(d, datetime.date)) for d in (start, end)): # Both are times
format = lambda dt: format_time(dt, tzinfo=tzinfo, locale=locale)
else:
format = lambda dt: format_datetime(dt, tzinfo=tzinfo, locale=locale)
@@ -1071,11 +1118,18 @@ def _format_fallback_interval(start: _Instant, end: _Instant, skeleton: str | No
)
-def format_interval(start: _Instant, end: _Instant, skeleton: str | None = None, tzinfo: tzinfo | None = None,
- fuzzy: bool = True, locale: Locale | str | None = LC_TIME) -> str:
+def format_interval(
+ start: _Instant,
+ end: _Instant,
+ skeleton: str | None = None,
+ tzinfo: datetime.tzinfo | None = None,
+ fuzzy: bool = True,
+ locale: Locale | str | None = LC_TIME,
+) -> str:
"""
Format an interval between two instants according to the locale's rules.
+ >>> from datetime import date, time
>>> format_interval(date(2016, 1, 15), date(2016, 1, 17), "yMd", locale="fi")
u'15.\u201317.1.2016'
@@ -1170,13 +1224,18 @@ def format_interval(start: _Instant, end: _Instant, skeleton: str | None = None,
return _format_fallback_interval(start, end, skeleton, tzinfo, locale)
-def get_period_id(time: _Instant, tzinfo: tzinfo | None = None, type: Literal['selection'] | None = None,
- locale: Locale | str | None = LC_TIME) -> str:
+def get_period_id(
+ time: _Instant,
+ tzinfo: datetime.tzinfo | None = None,
+ type: Literal['selection'] | None = None,
+ locale: Locale | str | None = LC_TIME,
+) -> str:
"""
Get the day period ID for a given time.
This ID can be used as a key for the period name dictionary.
+ >>> from datetime import time
>>> get_period_names(locale="de")[get_period_id(time(7, 42), locale="de")]
u'Morgen'
@@ -1245,7 +1304,11 @@ class ParseError(ValueError):
pass
-def parse_date(string: str, locale: Locale | str | None = LC_TIME, format: _PredefinedTimeFormat = 'medium') -> date:
+def parse_date(
+ string: str,
+ locale: Locale | str | None = LC_TIME,
+ format: _PredefinedTimeFormat = 'medium',
+) -> datetime.date:
"""Parse a date from a string.
This function first tries to interpret the string as ISO-8601
@@ -1275,7 +1338,7 @@ def parse_date(string: str, locale: Locale | str | None = LC_TIME, format: _Pred
string, flags=re.ASCII) # allow only ASCII digits
if iso_alike:
try:
- return date(*map(int, iso_alike.groups()))
+ return datetime.date(*map(int, iso_alike.groups()))
except ValueError:
pass # a locale format might fit better, so let's continue
@@ -1302,10 +1365,14 @@ def parse_date(string: str, locale: Locale | str | None = LC_TIME, format: _Pred
day = int(numbers[indexes['D']])
if month > 12:
month, day = day, month
- return date(year, month, day)
+ return datetime.date(year, month, day)
-def parse_time(string: str, locale: Locale | str | None = LC_TIME, format: _PredefinedTimeFormat = 'medium') -> time:
+def parse_time(
+ string: str,
+ locale: Locale | str | None = LC_TIME,
+ format: _PredefinedTimeFormat = 'medium',
+) -> datetime.time:
"""Parse a time from a string.
This function uses the time format for the locale as a hint to determine
@@ -1352,7 +1419,7 @@ def parse_time(string: str, locale: Locale | str | None = LC_TIME, format: _Pred
minute = int(numbers[indexes['M']])
if len(numbers) > 2:
second = int(numbers[indexes['S']])
- return time(hour, minute, second)
+ return datetime.time(hour, minute, second)
class DateTimePattern:
@@ -1375,9 +1442,9 @@ class DateTimePattern:
def apply(
self,
- datetime: date | time,
+ datetime: datetime.date | datetime.time,
locale: Locale | str | None,
- reference_date: date | None = None
+ reference_date: datetime.date | None = None,
) -> str:
return self % DateTimeFormat(datetime, locale, reference_date)
@@ -1386,12 +1453,12 @@ class DateTimeFormat:
def __init__(
self,
- value: date | time,
+ value: datetime.date | datetime.time,
locale: Locale | str,
- reference_date: date | None = None
- ):
- assert isinstance(value, (date, datetime, time))
- if isinstance(value, (datetime, time)) and value.tzinfo is None:
+ reference_date: datetime.date | None = None
+ ) -> None:
+ assert isinstance(value, (datetime.date, datetime.datetime, datetime.time))
+ if isinstance(value, (datetime.datetime, datetime.time)) and value.tzinfo is None:
value = value.replace(tzinfo=UTC)
self.value = value
self.locale = Locale.parse(locale)
@@ -1500,14 +1567,14 @@ class DateTimeFormat:
day_of_year = self.get_day_of_year()
week = self.get_week_number(day_of_year)
if week == 0:
- date = self.value - timedelta(days=day_of_year)
+ date = self.value - datetime.timedelta(days=day_of_year)
week = self.get_week_number(self.get_day_of_year(date),
date.weekday())
return self.format(week, num)
else: # week of month
week = self.get_week_number(self.value.day)
if week == 0:
- date = self.value - timedelta(days=self.value.day)
+ date = self.value - datetime.timedelta(days=self.value.day)
week = self.get_week_number(date.day, date.weekday())
return str(week)
@@ -1515,6 +1582,7 @@ class DateTimeFormat:
"""
Return weekday from parsed datetime according to format pattern.
+ >>> from datetime import date
>>> format = DateTimeFormat(date(2016, 2, 28), Locale.parse('en_US'))
>>> format.format_weekday()
u'Sunday'
@@ -1561,6 +1629,7 @@ class DateTimeFormat:
"""
Return period from parsed datetime according to format pattern.
+ >>> from datetime import datetime, time
>>> format = DateTimeFormat(time(13, 42), 'fi_FI')
>>> format.format_period('a', 1)
u'ip.'
@@ -1621,7 +1690,7 @@ class DateTimeFormat:
# variants (summer/standard time)
value = self.value
if self.reference_date:
- value = datetime.combine(self.reference_date, self.value)
+ value = datetime.datetime.combine(self.reference_date, self.value)
if char == 'z':
return get_timezone_name(value, width, locale=self.locale)
@@ -1667,7 +1736,7 @@ class DateTimeFormat:
def format(self, value: SupportsInt, length: int) -> str:
return '%0*d' % (length, value)
- def get_day_of_year(self, date: date | None = None) -> int:
+ def get_day_of_year(self, date: datetime.date | None = None) -> int:
if date is None:
date = self.value
return (date - date.replace(month=1, day=1)).days + 1
@@ -1680,12 +1749,10 @@ class DateTimeFormat:
first week of the period is so short that it actually counts as the last
week of the previous period, this function will return 0.
- >>> format = DateTimeFormat(date(2006, 1, 8), Locale.parse('de_DE'))
- >>> format.get_week_number(6)
+ >>> date = datetime.date(2006, 1, 8)
+ >>> DateTimeFormat(date, 'de_DE').get_week_number(6)
1
-
- >>> format = DateTimeFormat(date(2006, 1, 8), Locale.parse('en_US'))
- >>> format.get_week_number(6)
+ >>> DateTimeFormat(date, 'en_US').get_week_number(6)
2
:param day_of_period: the number of the day in the period (usually
@@ -1710,7 +1777,7 @@ class DateTimeFormat:
# we must count from zero.For example the above calculation gives week 53
# for 2018-12-31. By iso-calender definition 2018 has a max of 52
# weeks, thus the weeknumber must be 53-52=1.
- max_weeks = date(year=self.value.year, day=28, month=12).isocalendar()[1]
+ max_weeks = datetime.date(year=self.value.year, day=28, month=12).isocalendar()[1]
if week_number > max_weeks:
week_number -= max_weeks
diff --git a/babel/localtime/__init__.py b/babel/localtime/__init__.py
index c7f214a..9d227c7 100644
--- a/babel/localtime/__init__.py
+++ b/babel/localtime/__init__.py
@@ -11,7 +11,7 @@
import sys
import time
-from datetime import datetime, timedelta, tzinfo
+import datetime
from threading import RLock
if sys.platform == 'win32':
@@ -23,34 +23,34 @@ else:
_cached_tz = None
_cache_lock = RLock()
-STDOFFSET = timedelta(seconds=-time.timezone)
+STDOFFSET = datetime.timedelta(seconds=-time.timezone)
if time.daylight:
- DSTOFFSET = timedelta(seconds=-time.altzone)
+ DSTOFFSET = datetime.timedelta(seconds=-time.altzone)
else:
DSTOFFSET = STDOFFSET
DSTDIFF = DSTOFFSET - STDOFFSET
-ZERO = timedelta(0)
+ZERO = datetime.timedelta(0)
-class _FallbackLocalTimezone(tzinfo):
+class _FallbackLocalTimezone(datetime.tzinfo):
- def utcoffset(self, dt: datetime) -> timedelta:
+ def utcoffset(self, dt: datetime.datetime) -> datetime.timedelta:
if self._isdst(dt):
return DSTOFFSET
else:
return STDOFFSET
- def dst(self, dt: datetime) -> timedelta:
+ def dst(self, dt: datetime.datetime) -> datetime.timedelta:
if self._isdst(dt):
return DSTDIFF
else:
return ZERO
- def tzname(self, dt: datetime) -> str:
+ def tzname(self, dt: datetime.datetime) -> str:
return time.tzname[self._isdst(dt)]
- def _isdst(self, dt: datetime) -> bool:
+ def _isdst(self, dt: datetime.datetime) -> bool:
tt = (dt.year, dt.month, dt.day,
dt.hour, dt.minute, dt.second,
dt.weekday(), 0, -1)
@@ -59,7 +59,7 @@ class _FallbackLocalTimezone(tzinfo):
return tt.tm_isdst > 0
-def get_localzone() -> tzinfo:
+def get_localzone() -> datetime.tzinfo:
"""Returns the current underlying local timezone object.
Generally this function does not need to be used, it's a
better idea to use the :data:`LOCALTZ` singleton instead.
diff --git a/babel/localtime/_unix.py b/babel/localtime/_unix.py
index 319c8cf..89b461a 100644
--- a/babel/localtime/_unix.py
+++ b/babel/localtime/_unix.py
@@ -1,7 +1,7 @@
import os
import re
-from datetime import tzinfo
+import datetime
from babel.localtime._helpers import (
_get_tzinfo_from_file,
@@ -9,7 +9,7 @@ from babel.localtime._helpers import (
_get_tzinfo,
)
-def _tz_from_env(tzenv: str) -> tzinfo:
+def _tz_from_env(tzenv: str) -> datetime.tzinfo:
if tzenv[0] == ':':
tzenv = tzenv[1:]
@@ -21,7 +21,7 @@ def _tz_from_env(tzenv: str) -> tzinfo:
return _get_tzinfo_or_raise(tzenv)
-def _get_localzone(_root: str = '/') -> tzinfo:
+def _get_localzone(_root: str = '/') -> datetime.tzinfo:
"""Tries to find the local timezone configuration.
This method prefers finding the timezone name and passing that to
zoneinfo or pytz, over passing in the localtime file, as in the later
diff --git a/babel/localtime/_win32.py b/babel/localtime/_win32.py
index 3d7e0d5..42f819a 100644
--- a/babel/localtime/_win32.py
+++ b/babel/localtime/_win32.py
@@ -5,7 +5,7 @@ try:
except ImportError:
winreg = None
-from datetime import tzinfo
+import datetime
from babel.core import get_global
from babel.localtime._helpers import _get_tzinfo_or_raise
from typing import Any, Dict, cast
@@ -89,7 +89,7 @@ def get_localzone_name() -> str:
return timezone
-def _get_localzone() -> tzinfo:
+def _get_localzone() -> datetime.tzinfo:
if winreg is None:
raise LookupError(
'Runtime support not available')
diff --git a/babel/messages/catalog.py b/babel/messages/catalog.py
index 0801de3..4486bec 100644
--- a/babel/messages/catalog.py
+++ b/babel/messages/catalog.py
@@ -13,7 +13,7 @@ import re
from collections import OrderedDict
from collections.abc import Generator, Iterable, Iterator
-from datetime import datetime, time as time_
+import datetime
from difflib import get_close_matches
from email import message_from_string
from copy import copy
@@ -45,10 +45,10 @@ PYTHON_FORMAT = re.compile(r'''
''', re.VERBOSE)
-def _parse_datetime_header(value: str) -> datetime:
+def _parse_datetime_header(value: str) -> datetime.datetime:
match = re.match(r'^(?P<datetime>.*?)(?P<tzoffset>[+-]\d{4})?$', value)
- dt = datetime.strptime(match.group('datetime'), '%Y-%m-%d %H:%M')
+ dt = datetime.datetime.strptime(match.group('datetime'), '%Y-%m-%d %H:%M')
# Separate the offset into a sign component, hours, and # minutes
tzoffset = match.group('tzoffset')
@@ -261,8 +261,8 @@ class Catalog:
version: str | None = None,
copyright_holder: str | None = None,
msgid_bugs_address: str | None = None,
- creation_date: datetime | str | None = None,
- revision_date: datetime | time_ | float | str | None = None,
+ creation_date: datetime.datetime | str | None = None,
+ revision_date: datetime.datetime | datetime.time | float | str | None = None,
last_translator: str | None = None,
language_team: str | None = None,
charset: str | None = None,
@@ -306,13 +306,13 @@ class Catalog:
self.charset = charset or 'utf-8'
if creation_date is None:
- creation_date = datetime.now(LOCALTZ)
- elif isinstance(creation_date, datetime) and not creation_date.tzinfo:
+ creation_date = datetime.datetime.now(LOCALTZ)
+ elif isinstance(creation_date, datetime.datetime) and not creation_date.tzinfo:
creation_date = creation_date.replace(tzinfo=LOCALTZ)
self.creation_date = creation_date
if revision_date is None:
revision_date = 'YEAR-MO-DA HO:MI+ZONE'
- elif isinstance(revision_date, datetime) and not revision_date.tzinfo:
+ elif isinstance(revision_date, datetime.datetime) and not revision_date.tzinfo:
revision_date = revision_date.replace(tzinfo=LOCALTZ)
self.revision_date = revision_date
self.fuzzy = fuzzy
@@ -354,7 +354,7 @@ class Catalog:
def _get_header_comment(self) -> str:
comment = self._header_comment
- year = datetime.now(LOCALTZ).strftime('%Y')
+ year = datetime.datetime.now(LOCALTZ).strftime('%Y')
if hasattr(self.revision_date, 'strftime'):
year = self.revision_date.strftime('%Y')
comment = comment.replace('PROJECT', self.project) \
@@ -409,7 +409,7 @@ class Catalog:
headers.append(('POT-Creation-Date',
format_datetime(self.creation_date, 'yyyy-MM-dd HH:mmZ',
locale='en')))
- if isinstance(self.revision_date, (datetime, time_, int, float)):
+ if isinstance(self.revision_date, (datetime.datetime, datetime.time, int, float)):
headers.append(('PO-Revision-Date',
format_datetime(self.revision_date,
'yyyy-MM-dd HH:mmZ', locale='en')))
@@ -481,6 +481,7 @@ class Catalog:
Here's an example of the output for such a catalog template:
>>> from babel.dates import UTC
+ >>> from datetime import datetime
>>> created = datetime(1990, 4, 1, 15, 30, tzinfo=UTC)
>>> catalog = Catalog(project='Foobar', version='1.0',
... creation_date=created)
diff --git a/babel/messages/frontend.py b/babel/messages/frontend.py
index c42cdc2..c7e921d 100644
--- a/babel/messages/frontend.py
+++ b/babel/messages/frontend.py
@@ -18,7 +18,7 @@ import sys
import tempfile
from collections import OrderedDict
from configparser import RawConfigParser
-from datetime import datetime
+import datetime
from io import StringIO
from babel import __version__ as VERSION
@@ -662,7 +662,7 @@ class init_catalog(Command):
catalog = read_po(infile, locale=self.locale)
catalog.locale = self._locale
- catalog.revision_date = datetime.now(LOCALTZ)
+ catalog.revision_date = datetime.datetime.now(LOCALTZ)
catalog.fuzzy = False
with open(self.output_file, 'wb') as outfile:
@@ -818,7 +818,7 @@ class update_catalog(Command):
catalog = read_po(infile, locale=self.locale)
catalog.locale = self._locale
- catalog.revision_date = datetime.now(LOCALTZ)
+ catalog.revision_date = datetime.datetime.now(LOCALTZ)
catalog.fuzzy = False
with open(filename, 'wb') as outfile:
diff --git a/babel/numbers.py b/babel/numbers.py
index 73155c4..95e9d2a 100644
--- a/babel/numbers.py
+++ b/babel/numbers.py
@@ -23,7 +23,7 @@ import decimal
import re
from typing import TYPE_CHECKING, Any, overload
import warnings
-from datetime import date as date_, datetime as datetime_
+import datetime
from babel.core import Locale, default_locale, get_global
from babel.localedata import LocaleDataDict
@@ -200,8 +200,8 @@ def get_currency_unit_pattern(
@overload
def get_territory_currencies(
territory: str,
- start_date: date_ | None = ...,
- end_date: date_ | None = ...,
+ start_date: datetime.date | None = ...,
+ end_date: datetime.date | None = ...,
tender: bool = ...,
non_tender: bool = ...,
include_details: Literal[False] = ...,
@@ -212,8 +212,8 @@ def get_territory_currencies(
@overload
def get_territory_currencies(
territory: str,
- start_date: date_ | None = ...,
- end_date: date_ | None = ...,
+ start_date: datetime.date | None = ...,
+ end_date: datetime.date | None = ...,
tender: bool = ...,
non_tender: bool = ...,
include_details: Literal[True] = ...,
@@ -223,8 +223,8 @@ def get_territory_currencies(
def get_territory_currencies(
territory: str,
- start_date: date_ | None = None,
- end_date: date_ | None = None,
+ start_date: datetime.date | None = None,
+ end_date: datetime.date | None = None,
tender: bool = True,
non_tender: bool = False,
include_details: bool = False,
@@ -280,12 +280,12 @@ def get_territory_currencies(
"""
currencies = get_global('territory_currencies')
if start_date is None:
- start_date = date_.today()
- elif isinstance(start_date, datetime_):
+ start_date = datetime.date.today()
+ elif isinstance(start_date, datetime.datetime):
start_date = start_date.date()
if end_date is None:
end_date = start_date
- elif isinstance(end_date, datetime_):
+ elif isinstance(end_date, datetime.datetime):
end_date = end_date.date()
curs = currencies.get(territory.upper(), ())
@@ -298,9 +298,9 @@ def get_territory_currencies(
result = []
for currency_code, start, end, is_tender in curs:
if start:
- start = date_(*start)
+ start = datetime.date(*start)
if end:
- end = date_(*end)
+ end = datetime.date(*end)
if ((is_tender and tender) or
(not is_tender and non_tender)) and _is_active(start, end):
if include_details:
diff --git a/babel/support.py b/babel/support.py
index 7477ee1..da111fc 100644
--- a/babel/support.py
+++ b/babel/support.py
@@ -16,14 +16,8 @@ import decimal
import gettext
import locale
import os
+import datetime
from collections.abc import Iterator
-from datetime import (
- date as _date,
- datetime as _datetime,
- time as _time,
- timedelta as _timedelta,
- tzinfo
-)
from typing import TYPE_CHECKING, Any, Callable
from babel.core import Locale
@@ -52,7 +46,7 @@ class Format:
u'1.234'
"""
- def __init__(self, locale: Locale | str, tzinfo: tzinfo | None = None) -> None:
+ def __init__(self, locale: Locale | str, tzinfo: datetime.tzinfo | None = None) -> None:
"""Initialize the formatter.
:param locale: the locale identifier or `Locale` instance
@@ -61,7 +55,11 @@ class Format:
self.locale = Locale.parse(locale)
self.tzinfo = tzinfo
- def date(self, date: _date | None = None, format: _PredefinedTimeFormat | str = 'medium') -> str:
+ def date(
+ self,
+ date: datetime.date | None = None,
+ format: _PredefinedTimeFormat | str = 'medium',
+ ) -> str:
"""Return a date formatted according to the given pattern.
>>> from datetime import date
@@ -71,7 +69,11 @@ class Format:
"""
return format_date(date, format, locale=self.locale)
- def datetime(self, datetime: _date | None = None, format: _PredefinedTimeFormat | str = 'medium') -> str:
+ def datetime(
+ self,
+ datetime: datetime.date | None = None,
+ format: _PredefinedTimeFormat | str = 'medium',
+ ) -> str:
"""Return a date and time formatted according to the given pattern.
>>> from datetime import datetime
@@ -79,10 +81,13 @@ class Format:
>>> fmt.datetime(datetime(2007, 4, 1, 15, 30))
u'Apr 1, 2007, 11:30:00 AM'
"""
- return format_datetime(datetime, format, tzinfo=self.tzinfo,
- locale=self.locale)
+ return format_datetime(datetime, format, tzinfo=self.tzinfo, locale=self.locale)
- def time(self, time: _time | _datetime | None = None, format: _PredefinedTimeFormat | str = 'medium') -> str:
+ def time(
+ self,
+ time: datetime.time | datetime.datetime | None = None,
+ format: _PredefinedTimeFormat | str = 'medium',
+ ) -> str:
"""Return a time formatted according to the given pattern.
>>> from datetime import datetime
@@ -94,7 +99,7 @@ class Format:
def timedelta(
self,
- delta: _timedelta | int,
+ delta: datetime.timedelta | int,
granularity: Literal["year", "month", "week", "day", "hour", "minute", "second"] = "second",
threshold: float = 0.85,
format: Literal["narrow", "short", "medium", "long"] = "long",
diff --git a/babel/util.py b/babel/util.py
index fb4870d..d25ec53 100644
--- a/babel/util.py
+++ b/babel/util.py
@@ -17,7 +17,7 @@ import textwrap
from babel import localtime, dates
from collections.abc import Generator, Iterable
-from datetime import datetime as datetime_, timedelta, tzinfo
+import datetime
from typing import IO, Any, TypeVar
missing = object()
@@ -225,12 +225,12 @@ def wraptext(text: str, width: int = 70, initial_indent: str = '', subsequent_in
odict = collections.OrderedDict
-class FixedOffsetTimezone(tzinfo):
+class FixedOffsetTimezone(datetime.tzinfo):
"""Fixed offset in minutes east from UTC."""
def __init__(self, offset: float, name: str | None = None) -> None:
- self._offset = timedelta(minutes=offset)
+ self._offset = datetime.timedelta(minutes=offset)
if name is None:
name = 'Etc/GMT%+d' % offset
self.zone = name
@@ -241,13 +241,13 @@ class FixedOffsetTimezone(tzinfo):
def __repr__(self) -> str:
return f'<FixedOffset "{self.zone}" {self._offset}>'
- def utcoffset(self, dt: datetime_) -> timedelta:
+ def utcoffset(self, dt: datetime.datetime) -> datetime.timedelta:
return self._offset
- def tzname(self, dt: datetime_) -> str:
+ def tzname(self, dt: datetime.datetime) -> str:
return self.zone
- def dst(self, dt: datetime_) -> timedelta:
+ def dst(self, dt: datetime.datetime) -> datetime.timedelta:
return ZERO