Issue 9183: Intern UTC timezone.

This commit is contained in:
Alexander Belopolsky 2010-10-14 17:03:51 +00:00
parent 5bc4fa7a49
commit 1bcbaab15a
4 changed files with 60 additions and 31 deletions

View File

@ -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

View File

@ -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)]:

View File

@ -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.

View File

@ -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;