]> granicus.if.org Git - python/commitdiff
SF bug 660872: datetimetz constructors behave counterintuitively (2.3a1).
authorTim Peters <tim.peters@gmail.com>
Thu, 23 Jan 2003 20:53:10 +0000 (20:53 +0000)
committerTim Peters <tim.peters@gmail.com>
Thu, 23 Jan 2003 20:53:10 +0000 (20:53 +0000)
This gives much the same treatment to datetime.fromtimestamp(stamp, tz) as
the last batch of checkins gave to datetime.now(tz):  do "the obvious"
thing with the tz argument instead of a senseless thing.

Doc/lib/libdatetime.tex
Lib/test/test_datetime.py
Misc/NEWS
Modules/datetimemodule.c

index b890024bfa4fcf7317e3604b94afd757b7271c7b..058d6d519ae144446172fd566451c306fed54680 100644 (file)
@@ -534,26 +534,35 @@ Other constructors, all class methods:
   \cfunction{gettimeofday()} function).
 
   Else \var{tz} must be an instance of a class \class{tzinfo} subclass,
-  and the current date and time are translated to \var{tz}'s time
+  and the current date and time are converted to \var{tz}'s time
   zone.  In this case the result is equivalent to
-  \code{\var{tz}.fromutc(datetime.utcnow().replace(tzinfo=\var{tz})}.
+  \code{\var{tz}.fromutc(datetime.utcnow().replace(tzinfo=\var{tz}))}.
   See also \method{today()}, \method{utcnow()}.
 \end{methoddesc}
 
 \begin{methoddesc}{utcnow}{}
   Return the current UTC date and time, with \member{tzinfo} \code{None}.
-  This is like \method{now()}, but  returns the current UTC date and time,
+  This is like \method{now()}, but returns the current UTC date and time,
   as a naive \class{datetime} object.
   See also \method{now()}.
 \end{methoddesc}
 
-\begin{methoddesc}{fromtimestamp}{timestamp}
-  Return the local \class{datetime} corresponding to the \POSIX{}
-  timestamp, such as is returned by \function{time.time()}.  This
-  may raise \exception{ValueError}, if the timestamp is out of the
-  range of values supported by the platform C
-  \cfunction{localtime()} function.  It's common for this to be
-  restricted to years in 1970 through 2038.
+\begin{methoddesc}{fromtimestamp}{timestamp, tz=None}
+  Return the local date and time corresponding to the \POSIX{}
+  timestamp, such as is returned by \function{time.time()}.
+  If optional argument \var{tz} is \code{None} or not specified, the
+  timestamp is converted to the platform's local date and time, and
+  the returned \class{datetime} object is naive.
+
+  Else \var{tz} must be an instance of a class \class{tzinfo} subclass,
+  and the timestamp is converted to \var{tz}'s time zone.  In this case
+  the result is equivalent to
+  \code{\var{tz}.fromutc(datetime.utcfromtimestamp(\var{timestamp}).replace(tzinfo=\var{tz}))}.
+
+  \method{fromtimestamp()} may raise \exception{ValueError}, if the
+  timestamp is out of the range of values supported by the platform C
+  \cfunction{localtime()} or \cfunction(gmtime()} functions.  It's common
+  for this to be restricted to years in 1970 through 2038.
   Note that on non-POSIX systems that include leap seconds in their
   notion of a timestamp, leap seconds are ignored by
   \method{fromtimestamp()}, and then it's possible to have two timestamps
index 7d503e019e4a9c2b5e243c6f0c2ba0a91c6f0f3f..0b9597a07a88fd8491365ce02b98cb353c651a32 100644 (file)
@@ -2266,7 +2266,7 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase):
         # Try with and without naming the keyword.
         off42 = FixedOffset(42, "42")
         another = meth(ts, off42)
-        again = meth(ts, tzinfo=off42)
+        again = meth(ts, tz=off42)
         self.failUnless(another.tzinfo is again.tzinfo)
         self.assertEqual(another.utcoffset(), timedelta(minutes=42))
         # Bad argument with and w/o naming the keyword.
@@ -2279,6 +2279,20 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase):
         # Too few args.
         self.assertRaises(TypeError, meth)
 
+        # Try to make sure tz= actually does some conversion.
+        timestamp = 1000000000  #  2001-09-09 01:46:40 UTC, give or take
+        utc = FixedOffset(0, "utc", 0)
+        expected = datetime(2001, 9, 9, 1, 46, 40)
+        got = datetime.utcfromtimestamp(timestamp)
+        # We don't support leap seconds, but maybe the platfrom insists
+        # on using them, so don't demand exact equality).
+        self.failUnless(abs(got - expected) < timedelta(minutes=1))
+
+        est = FixedOffset(-5*60, "est", 0)
+        expected -= timedelta(hours=5)
+        got = datetime.fromtimestamp(timestamp, est).replace(tzinfo=None)
+        self.failUnless(abs(got - expected) < timedelta(minutes=1))
+
     def test_tzinfo_utcnow(self):
         meth = self.theclass.utcnow
         # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
index 39ebd9360e86666195407aaa06b04b86d7dd0681..bfcddd93e591b099b1c4804f98d1544b9744ce08 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -93,6 +93,10 @@ Extension modules
   a tz argument, now() continues to return the current local date and time,
   as a naive datetime object.
 
+  datetime.fromtimestamp():  Like datetime.now() above, this had less than
+  useful behavior when the optional tinzo argument was specified.  See
+  also SF bug report <http://www.python.org/sf/660872>.
+
   The constructors building a datetime from a timestamp could raise
   ValueError if the platform C localtime()/gmtime() inserted "leap
   seconds".  Leap seconds are ignored now.  On such platforms, it's
index d81d5636f7d67f24aec604245334bc477e8f6140..aeccfda94222f13ccfa59b848cda286a000cc180 100644 (file)
@@ -3682,8 +3682,7 @@ datetime_now(PyObject *cls, PyObject *args, PyObject *kw)
        if (self != NULL && tzinfo != Py_None) {
                /* Convert UTC to tzinfo's zone. */
                PyObject *temp = self;
-               self = PyObject_CallMethod(tzinfo, "fromutc",
-                                          "O", self);
+               self = PyObject_CallMethod(tzinfo, "fromutc", "O", self);
                Py_DECREF(temp);
        }
        return self;
@@ -3702,17 +3701,26 @@ datetime_utcnow(PyObject *cls, PyObject *dummy)
 static PyObject *
 datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw)
 {
-       PyObject *self = NULL;
+       PyObject *self;
        double timestamp;
        PyObject *tzinfo = Py_None;
-       static char *keywords[] = {"timestamp", "tzinfo", NULL};
+       static char *keywords[] = {"timestamp", "tz", NULL};
 
-       if (PyArg_ParseTupleAndKeywords(args, kw, "d|O:fromtimestamp",
-                                       keywords, &timestamp, &tzinfo)) {
-               if (check_tzinfo_subclass(tzinfo) < 0)
-                       return NULL;
-               self = datetime_from_timestamp(cls, localtime, timestamp,
-                                              tzinfo);
+       if (! PyArg_ParseTupleAndKeywords(args, kw, "d|O:fromtimestamp",
+                                         keywords, &timestamp, &tzinfo))
+               return NULL;
+       if (check_tzinfo_subclass(tzinfo) < 0)
+               return NULL;
+
+       self = datetime_from_timestamp(cls,
+                                      tzinfo == Py_None ? localtime : gmtime,
+                                      timestamp,
+                                      tzinfo);
+       if (self != NULL && tzinfo != Py_None) {
+               /* Convert UTC to tzinfo's zone. */
+               PyObject *temp = self;
+               self = PyObject_CallMethod(tzinfo, "fromutc", "O", self);
+               Py_DECREF(temp);
        }
        return self;
 }
@@ -4404,7 +4412,7 @@ static PyMethodDef datetime_methods[] = {
 
        {"now",         (PyCFunction)datetime_now,
         METH_KEYWORDS | METH_CLASS,
-        PyDoc_STR("[tzinfo] -> new datetime with local day and time.")},
+        PyDoc_STR("[tz] -> new datetime with tz's locl day and time.")},
 
        {"utcnow",         (PyCFunction)datetime_utcnow,
         METH_NOARGS | METH_CLASS,
@@ -4412,7 +4420,7 @@ static PyMethodDef datetime_methods[] = {
 
        {"fromtimestamp", (PyCFunction)datetime_fromtimestamp,
         METH_KEYWORDS | METH_CLASS,
-        PyDoc_STR("timestamp[, tzinfo] -> local time from POSIX timestamp.")},
+        PyDoc_STR("timestamp[, tz] -> tz's local time from POSIX timestamp.")},
 
        {"utcfromtimestamp", (PyCFunction)datetime_utcfromtimestamp,
         METH_VARARGS | METH_CLASS,