8000 bpo-37642: Update max and min offset in datetime module by nsiregar · Pull Request #14878 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-37642: Update max and min offset in datetime module #14878

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8000
Merged
merged 1 commit into from
Aug 9, 2019
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
9 changes: 6 additions & 3 deletions Lib/datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -2269,7 +2269,7 @@ def fromutc(self, dt):
raise TypeError("fromutc() argument must be a datetime instance"
" or None")

_maxoffset = timedelta(hours=23, minutes=59)
_maxoffset = timedelta(hours=24, microseconds=-1)
_minoffset = -_maxoffset

@staticmethod
Expand All @@ -2293,8 +2293,11 @@ def _name_from_offset(delta):
return f'UTC{sign}{hours:02d}:{minutes:02d}'

timezone.utc = timezone._create(timedelta(0))
timezone.min = timezone._create(timezone._minoffset)
timezone.max = timezone._create(timezone._maxoffset)
# bpo-37642: These attributes are rounded to the nearest minute for backwards
# compatibility, even though the constructor will accept a wider range of
# values. This may change in the future.
timezone.min = timezone._create(-timedelta(hours=23, minutes=59))
timezone.max = timezone._create(timedelta(hours=23, minutes=59))
_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)

# Some time zone algebra. For a datetime x, let
Expand Down
25 changes: 25 additions & 0 deletions Lib/test/datetimetester.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,31 @@ def test_deepcopy(self):
tz_copy = copy.deepcopy(tz)
self.assertIs(tz_copy, tz)

def test_offset_boundaries(self):
# Test timedeltas close to the boundaries
time_deltas = [
timedelta(hours=23, minutes=59),
timedelta(hours=23, minutes=59, seconds=59),
timedelta(hours=23, minutes=59, seconds=59, microseconds=999999),
]
time_deltas.extend([-delta for delta in time_deltas])

for delta in time_deltas:
with self.subTest(test_type='good', delta=delta):
timezone(delta)

# Test timedeltas on and outside the boundaries
bad_time_deltas = [
timedelta(hours=24),
timedelta(hours=24, microseconds=1),
]
bad_time_deltas.extend([-delta for delta in bad_time_deltas])

for delta in bad_time_deltas:
with self.subTest(test_type='bad', delta=delta):
with self.assertRaises(ValueError):
timezone(delta)


#############################################################################
# Base class for testing a particular aspect of timedelta, time, date and
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1881,3 +1881,4 @@ Aleksandr Balezin
Robert Leenders
Tim Hopper
Dan Lidral-Porter
Ngalim Siregar
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that we don’t append to this file, but keep it sorted alphabetically by author last name.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Allowed the pure Python implementation of :class:`datetime.timezone` to represent
sub-minute offsets close to minimum and maximum boundaries, specifically in the
ranges (23:59, 24:00) and (-23:59, 24:00). Patch by Ngalim Siregar
11 changes: 9 additions & 2 deletions Modules/_datetimemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,9 @@ new_timezone(PyObject *offset, PyObject *name)
Py_INCREF(PyDateTime_TimeZone_UTC);
return PyDateTime_TimeZone_UTC;
}
if ((GET_TD_DAYS(offset) == -1 && GET_TD_SECONDS(offset) == 0) ||
if ((GET_TD_DAYS(offset) == -1 &&
GET_TD_SECONDS(offset) == 0 &&
GET_TD_MICROSECONDS(offset) < 1) ||
GET_TD_DAYS(offset) < -1 || GET_TD_DAYS(offset) >= 1) {
PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
" strictly between -timedelta(hours=24) and"
Expand Down Expand Up @@ -1169,7 +1171,9 @@ call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg)
if (offset == Py_None || offset == NULL)
return offset;
if (PyDelta_Check(offset)) {
if ((GET_TD_DAYS(offset) == -1 && GET_TD_SECONDS(offset) == 0) ||
if ((GET_TD_DAYS(offset) == -1 &&
GET_TD_SECONDS(offset) == 0 &&
GET_TD_MICROSECONDS(offset) < 1) ||
GET_TD_DAYS(offset) < -1 || GET_TD_DAYS(offset) >= 1) {
Py_DECREF(offset);
PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
Expand Down Expand Up @@ -6481,6 +6485,9 @@ PyInit__datetime(void)
PyDateTime_TimeZone_UTC = x;
CAPI.TimeZone_UTC = PyDateTime_TimeZone_UTC;

/* bpo-37642: These attributes are rounded to the nearest minute for backwards
* compatibility, even though the constructor will accept a wider range of
* values. This may change in the future.*/
delta = new_delta(-1, 60, 0, 1); /* -23:59 */
if (delta == NULL)
return NULL;
Expand Down
0