]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue 9183: Intern UTC timezone.
authorAlexander Belopolsky <alexander.belopolsky@gmail.com>
Thu, 14 Oct 2010 17:03:51 +0000 (17:03 +0000)
committerAlexander Belopolsky <alexander.belopolsky@gmail.com>
Thu, 14 Oct 2010 17:03:51 +0000 (17:03 +0000)
Lib/datetime.py
Lib/test/datetimetester.py
Misc/NEWS
Modules/_datetimemodule.c

index d640f75616b0bf4c65adb1966a5c7c890d420cd9..29ffe246aa4996e6a7ae3ae9ce4d2d1da27e4e69 100644 (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
index 0ee544b1b75c3bfe6f84b8fa6d1119183c75985e..e91eb673a4d7a1b0bde1c07b9630cb91c889920a 100644 (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)]:
index 7fb305c2adc007e74bbed48402624e1892089f06..c09e24f714acff6d09292c67bd806fbc41274bee 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.
 
index 8c473516327f67f5d114de0a80ebeac60a987bf9..9a04549787dd376bc01ec6cae850520e4eb0068f 100644 (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;