cpython: 88a5f2730579 (original) (raw)
Mercurial > cpython
changeset 77569:88a5f2730579
Issue #9527: datetime.astimezone() method will now supply a class timezone instance corresponding to the system local timezone when called with no arguments. [#9527]
Alexander Belopolsky alexander.belopolsky@gmail.com | |
---|---|
date | Fri, 22 Jun 2012 12:23:23 -0400 |
parents | ace45d23628a |
children | 336c53c1f547 |
files | Doc/library/datetime.rst Lib/datetime.py Lib/test/datetimetester.py Misc/NEWS Modules/_datetimemodule.c |
diffstat | 5 files changed, 138 insertions(+), 12 deletions(-)[+] [-] Doc/library/datetime.rst 11 Lib/datetime.py 28 Lib/test/datetimetester.py 21 Misc/NEWS 4 Modules/_datetimemodule.c 86 |
line wrap: on
line diff
--- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -958,17 +958,22 @@ Instance methods: datetime with no conversion of date and time data. -.. method:: datetime.astimezone(tz) +.. method:: datetime.astimezone(tz=None)
- Return a :class:
datetime
object with new :attr:tzinfo
attribute tz, adjusting the date and time data so the result is the same UTC time as self, but in tz's local time.
- If provided, tz must be an instance of a :class:
tzinfo
subclass, and its :meth:utcoffset
and :meth:dst
methods must not returnNone
. self must be aware (self.tzinfo
must not beNone
, andself.utcoffset()
must not returnNone
). - If called without arguments (or with
tz=None
) the system local - timezone is assumed. The
tzinfo
attribute of the converted - datetime instance will be set to an instance of :class:
timezone
- with the zone name and offset obtained from the OS.
+
If
self.tzinfo
is tz,self.astimezone(tz)
is equal to self: no adjustment of date or time data is performed. Else the result is local time in time zone tz, representing the same UTC time as self: after
--- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -1493,8 +1493,32 @@ class datetime(date): return datetime(year, month, day, hour, minute, second, microsecond, tzinfo)
- def astimezone(self, tz=None):
if tz is None:[](#l2.10)
if self.tzinfo is None:[](#l2.11)
raise ValueError("astimezone() requires an aware datetime")[](#l2.12)
ts = (self - _EPOCH) // timedelta(seconds=1)[](#l2.13)
localtm = _time.localtime(ts)[](#l2.14)
local = datetime(*localtm[:6])[](#l2.15)
try:[](#l2.16)
# Extract TZ data if available [](#l2.17)
gmtoff = localtm.tm_gmtoff[](#l2.18)
zone = localtm.tm_zone[](#l2.19)
except AttributeError:[](#l2.20)
# Compute UTC offset and compare with the value implied[](#l2.21)
# by tm_isdst. If the values match, use the zone name[](#l2.22)
# implied by tm_isdst.[](#l2.23)
delta = local - datetime(*_time.gmtime(ts)[:6])[](#l2.24)
dst = _time.daylight and localtm.tm_isdst > 0[](#l2.25)
gmtoff = _time.altzone if dst else _time.timezone[](#l2.26)
if delta == timedelta(seconds=-gmtoff):[](#l2.27)
tz = timezone(delta, _time.tzname[dst])[](#l2.28)
else:[](#l2.29)
tz = timezone(delta)[](#l2.30)
else:[](#l2.31)
tz = timezone(timedelta(seconds=-gmtoff), zone)[](#l2.32)
[](#l2.33)
elif not isinstance(tz, tzinfo):[](#l2.34) raise TypeError("tz argument must be an instance of tzinfo")[](#l2.35)
--- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1972,7 +1972,7 @@ class TestDateTime(TestDate): # simply can't be applied to a naive object. dt = self.theclass.now() f = FixedOffset(44, "")
self.assertRaises(TypeError, dt.astimezone) # not enough args[](#l3.7)
self.assertRaises(ValueError, dt.astimezone) # naive[](#l3.8) self.assertRaises(TypeError, dt.astimezone, f, f) # too many args[](#l3.9) self.assertRaises(TypeError, dt.astimezone, dt) # arg wrong type[](#l3.10) self.assertRaises(ValueError, dt.astimezone, f) # naive[](#l3.11)
@@ -3253,8 +3253,6 @@ class TestDateTimeTZ(TestDateTime, TZInf self.assertTrue(dt.tzinfo is f44m) # Replacing with degenerate tzinfo raises an exception. self.assertRaises(ValueError, dt.astimezone, fnone)
# Ditto with None tz.[](#l3.16)
self.assertRaises(TypeError, dt.astimezone, None)[](#l3.17) # Replacing with same tzinfo makes no change.[](#l3.18) x = dt.astimezone(dt.tzinfo)[](#l3.19) self.assertTrue(x.tzinfo is f44m)[](#l3.20)
@@ -3274,6 +3272,23 @@ class TestDateTimeTZ(TestDateTime, TZInf self.assertTrue(got.tzinfo is expected.tzinfo) self.assertEqual(got, expected)
- @support.run_with_tz('UTC')
- def test_astimezone_default_utc(self):
dt = self.theclass.now(timezone.utc)[](#l3.27)
self.assertEqual(dt.astimezone(None), dt)[](#l3.28)
self.assertEqual(dt.astimezone(), dt)[](#l3.29)
- @support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
- def test_astimezone_default_eastern(self):
dt = self.theclass(2012, 11, 4, 6, 30, tzinfo=timezone.utc)[](#l3.33)
local = dt.astimezone()[](#l3.34)
self.assertEqual(dt, local)[](#l3.35)
self.assertEqual(local.strftime("%z %Z"), "+0500 EST") [](#l3.36)
dt = self.theclass(2012, 11, 4, 5, 30, tzinfo=timezone.utc)[](#l3.37)
local = dt.astimezone()[](#l3.38)
self.assertEqual(dt, local)[](#l3.39)
self.assertEqual(local.strftime("%z %Z"), "+0400 EDT") [](#l3.40)
+ def test_aware_subtract(self): cls = self.theclass
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -40,6 +40,10 @@ Core and Builtins Library ------- +- Issue #9527: datetime.astimezone() method will now supply a class
- Issue #14653: email.utils.mktime_tz() no longer relies on system mktime() when timezone offest is supplied.
--- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4686,17 +4686,87 @@ datetime_replace(PyDateTime_DateTime *se } static PyObject * +local_timezone(PyObject *utc_time) +{
- PyObject *result = NULL;
- struct tm *timep;
- time_t timestamp;
- long offset;
- PyObject *delta;
- PyObject *one_second;
- PyObject *seconds;
- PyObject *nameo = NULL;
- const char *zone = NULL;
- delta = datetime_subtract((PyObject *)utc_time, PyDateTime_Epoch);
- if (delta == NULL)
return NULL;[](#l5.21)
- one_second = new_delta(0, 1, 0, 0);
- if (one_second == NULL)
goto error;[](#l5.24)
- seconds = divide_timedelta_timedelta((PyDateTime_Delta *)delta,
(PyDateTime_Delta *)one_second);[](#l5.26)
- Py_DECREF(one_second);
- if (seconds == NULL)
goto error;[](#l5.29)
- Py_DECREF(delta);
- timestamp = PyLong_AsLong(seconds);
- Py_DECREF(seconds);
- if (timestamp == -1 && PyErr_Occurred())
return NULL;[](#l5.34)
- timep = localtime(×tamp);
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+#else /* HAVE_STRUCT_TM_TM_ZONE */
- {
PyObject *local_time;[](#l5.42)
Py_INCREF(utc_time->tzinfo);[](#l5.43)
local_time = new_datetime(timep->tm_year + 1900, timep->tm_mon + 1,[](#l5.44)
timep->tm_mday, timep->tm_hour, timep->tm_min,[](#l5.45)
timep->tm_sec, utc_time->tzinfo);[](#l5.46)
if (local_time == NULL) {[](#l5.47)
Py_DECREF(utc_time->tzinfo);[](#l5.48)
goto error;[](#l5.49)
}[](#l5.50)
delta = datetime_subtract(local_time, utc_time);[](#l5.51)
/* XXX: before relying on tzname, we should compare delta[](#l5.52)
to the offset implied by timezone/altzone */[](#l5.53)
if (daylight && timep->tm_isdst >= 0)[](#l5.54)
zone = tzname[timep->tm_isdst % 2];[](#l5.55)
else[](#l5.56)
zone = tzname[0];[](#l5.57)
Py_DECREF(local_time);[](#l5.58)
- }
+#endif /* HAVE_STRUCT_TM_TM_ZONE */
- if (zone != NULL) {
nameo = PyUnicode_DecodeLocale(zone, "surrogateescape");[](#l5.62)
if (nameo == NULL)[](#l5.63)
goto error;[](#l5.64)
- }
- result = new_timezone(delta, nameo);
- Py_DECREF(nameo);
- error:
- Py_DECREF(delta);
- return result;
+} + +static PyObject * datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) { PyObject *result; PyObject *offset; PyObject *temp;
- if (! PyArg_ParseTupleAndKeywords(args, kw, "O!:astimezone", keywords,
&PyDateTime_TZInfoType, &tzinfo))[](#l5.85)
- if (! PyArg_ParseTupleAndKeywords(args, kw, "|O:astimezone", keywords,
&tzinfo))[](#l5.87)
return NULL;[](#l5.88)
if (!HASTZINFO(self) || self->tzinfo == Py_None) @@ -4729,8 +4799,16 @@ datetime_astimezone(PyDateTime_DateTime /* Attach new tzinfo and let fromutc() do the rest. */ temp = ((PyDateTime_DateTime *)result)->tzinfo;