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
_Omitted = object()
def __init__(self, offset, name=_Omitted):
if name is self._Omitted:
def __new__(cls, offset, name=_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
elif not isinstance(name, str):
raise TypeError("name must be a string")
if isinstance(offset, timedelta):
if self._minoffset <= offset <= self._maxoffset:
if (offset.microseconds != 0 or
offset.seconds % 60 != 0):
raise ValueError("offset must be whole"
" number of minutes")
self._offset = offset
else:
raise ValueError("offset out of range")
else:
raise TypeError("offset must be timedelta")
if not cls._minoffset <= offset <= cls._maxoffset:
raise ValueError("offset must be a timedelta"
" strictly between -timedelta(hours=24) and"
" timedelta(hours=24).")
if (offset.microseconds != 0 or
offset.seconds % 60 != 0):
raise ValueError("offset must be a timedelta"
" representing a whole number of minutes")
return cls._create(offset, name)
@classmethod
def _create(cls, offset, name=None):
self = tzinfo.__new__(cls)
self._offset = offset
self._name = name
return self
def __getinitargs__(self):
"""pickle support"""
@ -1879,9 +1886,9 @@ class timezone(tzinfo):
minutes = rest // timedelta(minutes=1)
return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
timezone.utc = timezone(timedelta(0))
timezone.min = timezone(timezone._minoffset)
timezone.max = timezone(timezone._maxoffset)
timezone.utc = timezone._create(timedelta(0))
timezone.min = timezone._create(timezone._minoffset)
timezone.max = timezone._create(timezone._maxoffset)
"""
Some time zone algebra. For a datetime x, let

View File

@ -176,7 +176,9 @@ class TestTimeZone(unittest.TestCase):
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
for invalid in [timedelta(microseconds=1), timedelta(1, 1),
timedelta(seconds=1), timedelta(1), -timedelta(1)]:

View File

@ -21,6 +21,9 @@ Core and Builtins
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,
where supported by the system. Patch by Nikita Vetoshkin.

View File

@ -767,14 +767,15 @@ typedef struct
PyObject *name;
} PyDateTime_TimeZone;
PyObject *PyDateTime_TimeZone_UTC;
/* The interned UTC timezone instance */
static PyObject *PyDateTime_TimeZone_UTC;
/* Create new timezone instance checking offset range. This
function does not check the name argument. Caller must assure
that offset is a timedelta instance and name is either NULL
or a unicode object. */
static PyObject *
new_timezone(PyObject *offset, PyObject *name)
create_timezone(PyObject *offset, PyObject *name)
{
PyDateTime_TimeZone *self;
PyTypeObject *type = &PyDateTime_TimeZoneType;
@ -783,6 +784,30 @@ new_timezone(PyObject *offset, PyObject *name)
assert(PyDelta_Check(offset));
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) {
PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
" representing a whole number of minutes");
@ -796,15 +821,7 @@ new_timezone(PyObject *offset, PyObject *name)
return NULL;
}
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;
return create_timezone(offset, name);
}
/* ---------------------------------------------------------------------------
@ -5156,7 +5173,7 @@ PyInit__datetime(void)
delta = new_delta(0, 0, 0, 0);
if (delta == NULL)
return NULL;
x = new_timezone(delta, NULL);
x = create_timezone(delta, NULL);
Py_DECREF(delta);
if (x == NULL || PyDict_SetItemString(d, "utc", x) < 0)
return NULL;
@ -5165,7 +5182,7 @@ PyInit__datetime(void)
delta = new_delta(-1, 60, 0, 1); /* -23:59 */
if (delta == NULL)
return NULL;
x = new_timezone(delta, NULL);
x = create_timezone(delta, NULL);
Py_DECREF(delta);
if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
return NULL;
@ -5174,7 +5191,7 @@ PyInit__datetime(void)
delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */
if (delta == NULL)
return NULL;
x = new_timezone(delta, NULL);
x = create_timezone(delta, NULL);
Py_DECREF(delta);
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
return NULL;