Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 60 additions & 15 deletions Lib/_pydatetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ def _parse_isoformat_time(tstr):
hour, minute, second, microsecond = time_comps
became_next_day = False
error_from_components = False
error_from_tz = None
if (hour == 24):
if all(time_comp == 0 for time_comp in time_comps[1:]):
hour = 0
Expand Down Expand Up @@ -490,14 +491,22 @@ def _parse_isoformat_time(tstr):
else:
tzsign = -1 if tstr[tz_pos - 1] == '-' else 1

td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
seconds=tz_comps[2], microseconds=tz_comps[3])

tzi = timezone(tzsign * td)
try:
# This function is intended to validate datetimes, but because
# we restrict time zones to ±24h, it serves here as well.
_check_time_fields(hour=tz_comps[0], minute=tz_comps[1],
second=tz_comps[2], microsecond=tz_comps[3],
fold=0)
except ValueError as e:
error_from_tz = e
else:
td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
seconds=tz_comps[2], microseconds=tz_comps[3])
tzi = timezone(tzsign * td)

time_comps.append(tzi)

return time_comps, became_next_day, error_from_components
return time_comps, became_next_day, error_from_components, error_from_tz

# tuple[int, int, int] -> tuple[int, int, int] version of date.fromisocalendar
def _isoweek_to_gregorian(year, week, day):
Expand Down Expand Up @@ -1064,7 +1073,11 @@ def fromisocalendar(cls, year, week, day):

@classmethod
def strptime(cls, date_string, format):
"""Parse a date string according to the given format (like time.strptime())."""
"""Parse string according to the given date format (like time.strptime()).

For a list of supported format codes, see the documentation:
https://docs.python.org/3/library/datetime.html#format-codes
"""
import _strptime
return _strptime._strptime_datetime_date(cls, date_string, format)

Expand Down Expand Up @@ -1101,6 +1114,8 @@ def strftime(self, format):
Format using strftime().

Example: "%d/%m/%Y, %H:%M:%S"
For a list of supported format codes, see the documentation:
https://docs.python.org/3/library/datetime.html#format-codes
"""
return _wrap_strftime(self, format, self.timetuple())

Expand Down Expand Up @@ -1291,7 +1306,7 @@ def __reduce__(self):


class tzinfo:
"""Abstract base class for time zone info classes.
"""Abstract base class for time zone info objects.

Subclasses must override the tzname(), utcoffset() and dst() methods.
"""
Expand Down Expand Up @@ -1448,8 +1463,13 @@ def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold
return self

@classmethod

def strptime(cls, date_string, format):
"""string, format -> new time parsed from a string (like time.strptime())."""
"""Parse string according to the given time format (like time.strptime()).

For a list of supported format codes, see the documentation:
https://docs.python.org/3/library/datetime.html#format-codes
"""
import _strptime
return _strptime._strptime_datetime_time(cls, date_string, format)

Expand Down Expand Up @@ -1623,13 +1643,28 @@ def fromisoformat(cls, time_string):
time_string = time_string.removeprefix('T')

try:
return cls(*_parse_isoformat_time(time_string)[0])
except Exception:
raise ValueError(f'Invalid isoformat string: {time_string!r}')
time_components, _, error_from_components, error_from_tz = (
_parse_isoformat_time(time_string)
)
except ValueError:
raise ValueError(
f'Invalid isoformat string: {time_string!r}') from None
else:
if error_from_tz:
raise error_from_tz
if error_from_components:
raise ValueError(
"Minute, second, and microsecond must be 0 when hour is 24"
)

return cls(*time_components)

def strftime(self, format):
"""Format using strftime(). The date part of the timestamp passed
to underlying strftime should not be used.

For a list of supported format codes, see the documentation:
https://docs.python.org/3/library/datetime.html#format-codes
"""
# The year must be >= 1000 else Python's strftime implementation
# can raise a bogus exception.
Expand Down Expand Up @@ -1745,7 +1780,7 @@ def __reduce__(self):


class datetime(date):
"""datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
"""A combination of a date and a time.

The year, month and day arguments are required. tzinfo may be None, or an
instance of a tzinfo subclass. The remaining arguments may be ints.
Expand Down Expand Up @@ -1937,11 +1972,16 @@ def fromisoformat(cls, date_string):

if tstr:
try:
time_components, became_next_day, error_from_components = _parse_isoformat_time(tstr)
(time_components,
became_next_day,
error_from_components,
error_from_tz) = _parse_isoformat_time(tstr)
except ValueError:
raise ValueError(
f'Invalid isoformat string: {date_string!r}') from None
else:
if error_from_tz:
raise error_from_tz
if error_from_components:
raise ValueError("minute, second, and microsecond must be 0 when hour is 24")

Expand Down Expand Up @@ -2079,7 +2119,6 @@ def _local_timezone(self):
else:
ts = (self - _EPOCH) // timedelta(seconds=1)
localtm = _time.localtime(ts)
local = datetime(*localtm[:6])
# Extract TZ data
gmtoff = localtm.tm_gmtoff
zone = localtm.tm_zone
Expand Down Expand Up @@ -2174,7 +2213,11 @@ def __str__(self):

@classmethod
def strptime(cls, date_string, format):
'string, format -> new datetime parsed from a string (like time.strptime()).'
"""Parse string according to the given time format (like time.strptime()).

For a list of supported format codes, see the documentation:
https://docs.python.org/3/library/datetime.html#format-codes
"""
import _strptime
return _strptime._strptime_datetime_datetime(cls, date_string, format)

Expand Down Expand Up @@ -2400,6 +2443,8 @@ def _isoweek1monday(year):


class timezone(tzinfo):
"""Fixed offset from UTC implementation of tzinfo."""

__slots__ = '_offset', '_name'

# Sentinel value to disallow None
Expand Down
17 changes: 14 additions & 3 deletions Lib/_pydecimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,16 @@
'HAVE_THREADS',

# C version: compile time choice that enables the coroutine local context
'HAVE_CONTEXTVAR'
'HAVE_CONTEXTVAR',

# Highest version of the spec this module complies with
'SPEC_VERSION',
]

__xname__ = __name__ # sys.modules lookup (--without-threads)
__name__ = 'decimal' # For pickling
__version__ = '1.70' # Highest version of the spec this complies with
# See http://speleotrove.com/decimal/
SPEC_VERSION = '1.70' # Highest version of the spec this complies with
# See https://speleotrove.com/decimal/decarith.html
__libmpdec_version__ = "2.4.2" # compatible libmpdec version

import math as _math
Expand Down Expand Up @@ -6404,3 +6407,11 @@ def _format_number(is_negative, intpart, fracpart, exp, spec):
# _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS
_PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
del sys

def __getattr__(name):
if name == "__version__":
from warnings import _deprecated

_deprecated("__version__", remove=(3, 20))
return SPEC_VERSION
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
Loading
Loading