From 10cadce41ec7b94aafc11b4f2c9cfb7587f5b81d Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Thu, 23 Jan 2003 19:58:02 +0000 Subject: [PATCH] Reimplemented datetime.now() to be useful. --- Doc/lib/libdatetime.tex | 22 ++++++++++++++-------- Lib/test/test_datetime.py | 22 ++++++++++++++++++++-- Misc/NEWS | 11 +++++++++++ Modules/datetimemodule.c | 24 +++++++++++++++++------- 4 files changed, 62 insertions(+), 17 deletions(-) diff --git a/Doc/lib/libdatetime.tex b/Doc/lib/libdatetime.tex index 9133f1e00d4..b890024bfa4 100644 --- a/Doc/lib/libdatetime.tex +++ b/Doc/lib/libdatetime.tex @@ -525,19 +525,25 @@ Other constructors, all class methods: See also \method{now()}, \method{fromtimestamp()}. \end{methoddesc} -\begin{methoddesc}{now}{} - Return the current local datetime. This is like \method{today()}, - but, if possible, supplies more precision than can be gotten from - going through a \function{time.time()} timestamp (for example, - this may be possible on platforms that supply the C +\begin{methoddesc}{now(tz=None)}{} + Return the current local date and time. If optional argument + \var{tz} is \code{None} or not specified, this is like + \method{today()}, but, if possible, supplies more precision than can + be gotten from going through a \function{time.time()} timestamp (for + example, this may be possible on platforms supplying the C \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 + zone. In this case the result is equivalent to + \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 datetime, with \member{tzinfo} \code{None}. - This is like \method{now()}, but - returns the current UTC date and time. + 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, + as a naive \class{datetime} object. See also \method{now()}. \end{methoddesc} diff --git a/Lib/test/test_datetime.py b/Lib/test/test_datetime.py index 88783868db8..7d503e019e4 100644 --- a/Lib/test/test_datetime.py +++ b/Lib/test/test_datetime.py @@ -2228,7 +2228,7 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase): # Try with and without naming the keyword. off42 = FixedOffset(42, "42") another = meth(off42) - again = meth(tzinfo=off42) + again = meth(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. @@ -2239,6 +2239,24 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase): # Too many args. self.assertRaises(TypeError, meth, off42, off42) + # We don't know which time zone we're in, and don't have a tzinfo + # class to represent it, so seeing whether a tz argument actually + # does a conversion is tricky. + weirdtz = FixedOffset(timedelta(hours=15, minutes=58), "weirdtz", 0) + utc = FixedOffset(0, "utc", 0) + for dummy in range(3): + now = datetime.now(weirdtz) + self.failUnless(now.tzinfo is weirdtz) + utcnow = datetime.utcnow().replace(tzinfo=utc) + now2 = utcnow.astimezone(weirdtz) + if abs(now - now2) < timedelta(seconds=30): + break + # Else the code is broken, or more than 30 seconds passed between + # calls; assuming the latter, just try again. + else: + # Three strikes and we're out. + self.fail("utcnow(), now(tz), or astimezone() may be broken") + def test_tzinfo_fromtimestamp(self): import time meth = self.theclass.fromtimestamp @@ -2448,7 +2466,7 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase): f44m = FixedOffset(44, "44") fm5h = FixedOffset(-timedelta(hours=5), "m300") - dt = self.theclass.now(tzinfo=f44m) + dt = self.theclass.now(tz=f44m) self.failUnless(dt.tzinfo is f44m) # Replacing with degenerate tzinfo raises an exception. self.assertRaises(ValueError, dt.astimezone, fnone) diff --git a/Misc/NEWS b/Misc/NEWS index 780bf5ab7be..39ebd9360e8 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -82,6 +82,17 @@ Extension modules creativity of political time zone fiddling appears unbounded -- fromutc() allows the highly motivated to emulate any scheme expressible in Python. + datetime.now(): The optional tzinfo argument was undocumented (that's + repaired), and its name was changed to tz ("tzinfo" is overloaded enough + already). With a tz argument, now(tz) used to return the local date + and time, and attach tz to it, without any conversion of date and time + members. This was less than useful. Now now(tz) returns the current + date and time as local time in tz's time zone, akin to + tz.fromutc(datetime.utcnow().replace(tzinfo=utc)) + where "utc" is an instance of a tzinfo subclass modeling UTC. Without + a tz argument, now() continues to return the current local date and time, + as a naive datetime object. + 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 diff --git a/Modules/datetimemodule.c b/Modules/datetimemodule.c index f615f6851b2..d81d5636f7d 100644 --- a/Modules/datetimemodule.c +++ b/Modules/datetimemodule.c @@ -3666,15 +3666,25 @@ datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo) static PyObject * datetime_now(PyObject *cls, PyObject *args, PyObject *kw) { - PyObject *self = NULL; + PyObject *self; PyObject *tzinfo = Py_None; - static char *keywords[] = {"tzinfo", NULL}; + static char *keywords[] = {"tz", NULL}; - if (PyArg_ParseTupleAndKeywords(args, kw, "|O:now", keywords, - &tzinfo)) { - if (check_tzinfo_subclass(tzinfo) < 0) - return NULL; - self = datetime_best_possible(cls, localtime, tzinfo); + if (! PyArg_ParseTupleAndKeywords(args, kw, "|O:now", keywords, + &tzinfo)) + return NULL; + if (check_tzinfo_subclass(tzinfo) < 0) + return NULL; + + self = datetime_best_possible(cls, + tzinfo == Py_None ? localtime : gmtime, + 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; }