Issue 9183: Intern UTC timezone.
This commit is contained in:
parent
5bc4fa7a49
commit
1bcbaab15a
|
@ -1784,24 +1784,31 @@ class timezone(tzinfo):
|
||||||
|
|
||||||
# Sentinel value to disallow None
|
# Sentinel value to disallow None
|
||||||
_Omitted = object()
|
_Omitted = object()
|
||||||
def __init__(self, offset, name=_Omitted):
|
def __new__(cls, offset, name=_Omitted):
|
||||||
if name is self._Omitted:
|
if not isinstance(offset, timedelta):
|
||||||
|
raise TypeError("offset must be a timedelta")
|
||||||
|
if name is cls._Omitted:
|
||||||
|
if not offset:
|
||||||
|
return cls.utc
|
||||||
name = None
|
name = None
|
||||||
elif not isinstance(name, str):
|
elif not isinstance(name, str):
|
||||||
raise TypeError("name must be a string")
|
raise TypeError("name must be a string")
|
||||||
if isinstance(offset, timedelta):
|
if not cls._minoffset <= offset <= cls._maxoffset:
|
||||||
if self._minoffset <= offset <= self._maxoffset:
|
raise ValueError("offset must be a timedelta"
|
||||||
if (offset.microseconds != 0 or
|
" strictly between -timedelta(hours=24) and"
|
||||||
offset.seconds % 60 != 0):
|
" timedelta(hours=24).")
|
||||||
raise ValueError("offset must be whole"
|
if (offset.microseconds != 0 or
|
||||||
" number of minutes")
|
offset.seconds % 60 != 0):
|
||||||
self._offset = offset
|
raise ValueError("offset must be a timedelta"
|
||||||
else:
|
" representing a whole number of minutes")
|
||||||
raise ValueError("offset out of range")
|
return cls._create(offset, name)
|
||||||
else:
|
|
||||||
raise TypeError("offset must be timedelta")
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _create(cls, offset, name=None):
|
||||||
|
self = tzinfo.__new__(cls)
|
||||||
|
self._offset = offset
|
||||||
self._name = name
|
self._name = name
|
||||||
|
return self
|
||||||
|
|
||||||
def __getinitargs__(self):
|
def __getinitargs__(self):
|
||||||
"""pickle support"""
|
"""pickle support"""
|
||||||
|
@ -1879,9 +1886,9 @@ class timezone(tzinfo):
|
||||||
minutes = rest // timedelta(minutes=1)
|
minutes = rest // timedelta(minutes=1)
|
||||||
return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
|
return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
|
||||||
|
|
||||||
timezone.utc = timezone(timedelta(0))
|
timezone.utc = timezone._create(timedelta(0))
|
||||||
timezone.min = timezone(timezone._minoffset)
|
timezone.min = timezone._create(timezone._minoffset)
|
||||||
timezone.max = timezone(timezone._maxoffset)
|
timezone.max = timezone._create(timezone._maxoffset)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Some time zone algebra. For a datetime x, let
|
Some time zone algebra. For a datetime x, let
|
||||||
|
|
|
@ -176,7 +176,9 @@ class TestTimeZone(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
def test_constructor(self):
|
def test_constructor(self):
|
||||||
self.assertEqual(timezone.utc, timezone(timedelta(0)))
|
self.assertIs(timezone.utc, timezone(timedelta(0)))
|
||||||
|
self.assertIsNot(timezone.utc, timezone(timedelta(0), 'UTC'))
|
||||||
|
self.assertEqual(timezone.utc, timezone(timedelta(0), 'UTC'))
|
||||||
# invalid offsets
|
# invalid offsets
|
||||||
for invalid in [timedelta(microseconds=1), timedelta(1, 1),
|
for invalid in [timedelta(microseconds=1), timedelta(1, 1),
|
||||||
timedelta(seconds=1), timedelta(1), -timedelta(1)]:
|
timedelta(seconds=1), timedelta(1), -timedelta(1)]:
|
||||||
|
|
|
@ -21,6 +21,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue 9183: ``datetime.timezone(datetime.timedelta(0))`` will now
|
||||||
|
return the same instance as ``datetime.timezone.utc``.
|
||||||
|
|
||||||
- Issue #7523: Add SOCK_CLOEXEC and SOCK_NONBLOCK to the socket module,
|
- Issue #7523: Add SOCK_CLOEXEC and SOCK_NONBLOCK to the socket module,
|
||||||
where supported by the system. Patch by Nikita Vetoshkin.
|
where supported by the system. Patch by Nikita Vetoshkin.
|
||||||
|
|
||||||
|
|
|
@ -767,14 +767,15 @@ typedef struct
|
||||||
PyObject *name;
|
PyObject *name;
|
||||||
} PyDateTime_TimeZone;
|
} PyDateTime_TimeZone;
|
||||||
|
|
||||||
PyObject *PyDateTime_TimeZone_UTC;
|
/* The interned UTC timezone instance */
|
||||||
|
static PyObject *PyDateTime_TimeZone_UTC;
|
||||||
|
|
||||||
/* Create new timezone instance checking offset range. This
|
/* Create new timezone instance checking offset range. This
|
||||||
function does not check the name argument. Caller must assure
|
function does not check the name argument. Caller must assure
|
||||||
that offset is a timedelta instance and name is either NULL
|
that offset is a timedelta instance and name is either NULL
|
||||||
or a unicode object. */
|
or a unicode object. */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
new_timezone(PyObject *offset, PyObject *name)
|
create_timezone(PyObject *offset, PyObject *name)
|
||||||
{
|
{
|
||||||
PyDateTime_TimeZone *self;
|
PyDateTime_TimeZone *self;
|
||||||
PyTypeObject *type = &PyDateTime_TimeZoneType;
|
PyTypeObject *type = &PyDateTime_TimeZoneType;
|
||||||
|
@ -783,6 +784,30 @@ new_timezone(PyObject *offset, PyObject *name)
|
||||||
assert(PyDelta_Check(offset));
|
assert(PyDelta_Check(offset));
|
||||||
assert(name == NULL || PyUnicode_Check(name));
|
assert(name == NULL || PyUnicode_Check(name));
|
||||||
|
|
||||||
|
self = (PyDateTime_TimeZone *)(type->tp_alloc(type, 0));
|
||||||
|
if (self == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_INCREF(offset);
|
||||||
|
self->offset = offset;
|
||||||
|
Py_XINCREF(name);
|
||||||
|
self->name = name;
|
||||||
|
return (PyObject *)self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int delta_bool(PyDateTime_Delta *self);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
new_timezone(PyObject *offset, PyObject *name)
|
||||||
|
{
|
||||||
|
assert(offset != NULL);
|
||||||
|
assert(PyDelta_Check(offset));
|
||||||
|
assert(name == NULL || PyUnicode_Check(name));
|
||||||
|
|
||||||
|
if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) {
|
||||||
|
Py_INCREF(PyDateTime_TimeZone_UTC);
|
||||||
|
return PyDateTime_TimeZone_UTC;
|
||||||
|
}
|
||||||
if (GET_TD_MICROSECONDS(offset) != 0 || GET_TD_SECONDS(offset) % 60 != 0) {
|
if (GET_TD_MICROSECONDS(offset) != 0 || GET_TD_SECONDS(offset) % 60 != 0) {
|
||||||
PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
|
PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
|
||||||
" representing a whole number of minutes");
|
" representing a whole number of minutes");
|
||||||
|
@ -796,15 +821,7 @@ new_timezone(PyObject *offset, PyObject *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
self = (PyDateTime_TimeZone *)(type->tp_alloc(type, 0));
|
return create_timezone(offset, name);
|
||||||
if (self == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Py_INCREF(offset);
|
|
||||||
self->offset = offset;
|
|
||||||
Py_XINCREF(name);
|
|
||||||
self->name = name;
|
|
||||||
return (PyObject *)self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
|
@ -5156,7 +5173,7 @@ PyInit__datetime(void)
|
||||||
delta = new_delta(0, 0, 0, 0);
|
delta = new_delta(0, 0, 0, 0);
|
||||||
if (delta == NULL)
|
if (delta == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
x = new_timezone(delta, NULL);
|
x = create_timezone(delta, NULL);
|
||||||
Py_DECREF(delta);
|
Py_DECREF(delta);
|
||||||
if (x == NULL || PyDict_SetItemString(d, "utc", x) < 0)
|
if (x == NULL || PyDict_SetItemString(d, "utc", x) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5165,7 +5182,7 @@ PyInit__datetime(void)
|
||||||
delta = new_delta(-1, 60, 0, 1); /* -23:59 */
|
delta = new_delta(-1, 60, 0, 1); /* -23:59 */
|
||||||
if (delta == NULL)
|
if (delta == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
x = new_timezone(delta, NULL);
|
x = create_timezone(delta, NULL);
|
||||||
Py_DECREF(delta);
|
Py_DECREF(delta);
|
||||||
if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
|
if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5174,7 +5191,7 @@ PyInit__datetime(void)
|
||||||
delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */
|
delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */
|
||||||
if (delta == NULL)
|
if (delta == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
x = new_timezone(delta, NULL);
|
x = create_timezone(delta, NULL);
|
||||||
Py_DECREF(delta);
|
Py_DECREF(delta);
|
||||||
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
|
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Loading…
Reference in New Issue