Commit bad8ff08 authored by Tim Peters's avatar Tim Peters

A step on the way to making tzinfo classes writable by mortals: get rid

of the timetz case.  A tzinfo method will always see a datetimetz arg,
or None, now.  In the former case, it's still possible that it will get
a datetimetz argument belonging to a different timezone.  That will get
fixed next.
parent 567332ab
% XXX what order should the types be discussed in? % XXX what order should the types be discussed in?
\section{\module{datetime} --- \section{\module{datetime} ---
Basic date and time types} Basic date and time types}
...@@ -785,13 +785,13 @@ Instance attributes (read-only): ...@@ -785,13 +785,13 @@ Instance attributes (read-only):
\begin{memberdesc}{hour} \begin{memberdesc}{hour}
In \code{range(24)}. In \code{range(24)}.
\end{memberdesc} \end{memberdesc}
\begin{memberdesc}{minute} \begin{memberdesc}{minute}
In \code{range(60)}. In \code{range(60)}.
\end{memberdesc} \end{memberdesc}
\begin{memberdesc}{second} \begin{memberdesc}{second}
In \code{range(60)}. In \code{range(60)}.
\end{memberdesc} \end{memberdesc}
\begin{memberdesc}{microsecond} \begin{memberdesc}{microsecond}
In \code{range(1000000)}. In \code{range(1000000)}.
\end{memberdesc} \end{memberdesc}
...@@ -844,7 +844,7 @@ Instance methods: ...@@ -844,7 +844,7 @@ Instance methods:
should not be instantiated directly. You need to derive a concrete should not be instantiated directly. You need to derive a concrete
subclass, and (at least) supply implementations of the standard subclass, and (at least) supply implementations of the standard
\class{tzinfo} methods needed by the \class{datetime} methods you \class{tzinfo} methods needed by the \class{datetime} methods you
use. The \module{datetime} module does not supply any concrete use. The \module{datetime} module does not supply any concrete
subclasses of \class{tzinfo}. subclasses of \class{tzinfo}.
An instance of (a concrete subclass of) \class{tzinfo} can be passed An instance of (a concrete subclass of) \class{tzinfo} can be passed
...@@ -854,21 +854,17 @@ The latter objects view their fields as being in local time, and the ...@@ -854,21 +854,17 @@ The latter objects view their fields as being in local time, and the
from UTC, the name of the time zone, and DST offset, all relative to a from UTC, the name of the time zone, and DST offset, all relative to a
date or time object passed to them. date or time object passed to them.
Special requirement for pickling: A tzinfo subclass must have an Special requirement for pickling: A \class{tzinfo} subclass must have an
\method{__init__} method that can be called with no arguments, else it \method{__init__} method that can be called with no arguments, else it
can be pickled but possibly not unpickled again. This is a technical can be pickled but possibly not unpickled again. This is a technical
requirement that may be relaxed in the future. requirement that may be relaxed in the future.
A concrete subclass of \class{tzinfo} may need to implement the A concrete subclass of \class{tzinfo} may need to implement the
following methods. Exactly which methods are needed depends on the following methods. Exactly which methods are needed depends on the
uses made of aware \module{datetime} objects; if in doubt, simply uses made of aware \module{datetime} objects. If in doubt, simply
implement all of them. The methods are called by a \class{datetimetz} implement all of them.
or \class{timetz} object, passing itself as the argument. A
\class{tzinfo} subclass's methods should be prepared to accept a dt \begin{methoddesc}{utcoffset}{self, dt}
argument of \code{None} or of type \class{timetz} or
\class{datetimetz}.
\begin{methoddesc}{utcoffset}{dt}
Return offset of local time from UTC, in minutes east of UTC. If Return offset of local time from UTC, in minutes east of UTC. If
local time is west of UTC, this should be negative. Note that this local time is west of UTC, this should be negative. Note that this
is intended to be the total offset from UTC; for example, if a is intended to be the total offset from UTC; for example, if a
...@@ -878,10 +874,14 @@ argument of \code{None} or of type \class{timetz} or ...@@ -878,10 +874,14 @@ argument of \code{None} or of type \class{timetz} or
an integer, in the range -1439 to 1439 inclusive (1440 = 24*60; an integer, in the range -1439 to 1439 inclusive (1440 = 24*60;
the magnitude of the offset must be less than one day), or a the magnitude of the offset must be less than one day), or a
\class{timedelta} object representing a whole number of minutes \class{timedelta} object representing a whole number of minutes
in the same range. in the same range. Most implementations of \method{utcoffset()}
will probably look like:
\begin{verbatim}
return CONSTANT # fixed-offset class
return CONSTANT + self.dst(dt) # daylight-aware class
\end{methoddesc} \end{methoddesc}
\begin{methoddesc}{tzname}{dt} \begin{methoddesc}{tzname}{self, dt}
Return the timezone name corresponding to the \class{datetime} represented Return the timezone name corresponding to the \class{datetime} represented
by dt, as a string. Nothing about string names is defined by the by dt, as a string. Nothing about string names is defined by the
\module{datetime} module, and there's no requirement that it mean anything \module{datetime} module, and there's no requirement that it mean anything
...@@ -893,7 +893,7 @@ argument of \code{None} or of type \class{timetz} or ...@@ -893,7 +893,7 @@ argument of \code{None} or of type \class{timetz} or
of dt passed, especially if the \class{tzinfo} class is accounting for DST. of dt passed, especially if the \class{tzinfo} class is accounting for DST.
\end{methoddesc} \end{methoddesc}
\begin{methoddesc}{dst}{dt} \begin{methoddesc}{dst}{self, dt}
Return the DST offset, in minutes east of UTC, or \code{None} if Return the DST offset, in minutes east of UTC, or \code{None} if
DST information isn't known. Return 0 if DST is not in effect. DST information isn't known. Return 0 if DST is not in effect.
If DST is in effect, return the offset as an integer or If DST is in effect, return the offset as an integer or
...@@ -907,6 +907,26 @@ argument of \code{None} or of type \class{timetz} or ...@@ -907,6 +907,26 @@ argument of \code{None} or of type \class{timetz} or
\member{tm_isdst} flag should be set. \member{tm_isdst} flag should be set.
\end{methoddesc} \end{methoddesc}
These methods are called by a \class{datetimetz} or \class{timetz} object,
in response to their methods of the same names. A \class{datetimetz}
object passes itself as the argument, and a \class{timetz} object passes
\code{None} as the argument. A \class{tzinfo} subclass's methods should
therefore be prepared to accept a \var{dt} argument of \code{None}, or of
class \class{datetimetz}.
When \code{None} is passed, it's up to the class designer to decide the
best response. For example, returning \code{None} is appropriate if the
class wishes to say that timetz objects don't participate in the
\class{tzinfo} protocol. In other applications, it may be more useful
for \code{utcoffset(None}} to return the standard UTC offset.
When a \class{datetimetz} object is passed in response to a
\class{datetimetz} method, \code{dt.tzinfo} is the same object as
\var{self}. \class{tzinfo} methods can rely on this, unless
user code calls \class{tzinfo} methods directly. The intent is that
the \class{tzinfo} methods interpret \var{dt} as being in local time,
and not need to worry about objects in other timezones.
Example \class{tzinfo} classes: Example \class{tzinfo} classes:
\verbatiminput{tzinfo-examples.py} \verbatiminput{tzinfo-examples.py}
......
...@@ -1557,6 +1557,23 @@ class TestTime(unittest.TestCase): ...@@ -1557,6 +1557,23 @@ class TestTime(unittest.TestCase):
# must be legit (which is true for timetz and datetimetz). # must be legit (which is true for timetz and datetimetz).
class TZInfoBase(unittest.TestCase): class TZInfoBase(unittest.TestCase):
def test_argument_passing(self):
cls = self.theclass
# A datetimetz passes itself on, a timetz passes None.
class introspective(tzinfo):
def tzname(self, dt): return dt and "real" or "none"
def utcoffset(self, dt): return dt and 42 or -42
dst = utcoffset
obj = cls(1, 2, 3, tzinfo=introspective())
expected = cls is timetz and "none" or "real"
self.assertEqual(obj.tzname(), expected)
expected = timedelta(minutes=(cls is timetz and -42 or 42))
self.assertEqual(obj.utcoffset(), expected)
self.assertEqual(obj.dst(), expected)
def test_bad_tzinfo_classes(self): def test_bad_tzinfo_classes(self):
cls = self.theclass cls = self.theclass
self.assertRaises(TypeError, cls, 1, 1, 1, tzinfo=12) self.assertRaises(TypeError, cls, 1, 1, 1, tzinfo=12)
...@@ -1677,22 +1694,26 @@ class TZInfoBase(unittest.TestCase): ...@@ -1677,22 +1694,26 @@ class TZInfoBase(unittest.TestCase):
self.assertEqual(got, expected) self.assertEqual(got, expected)
# However, if they're different members, uctoffset is not ignored. # However, if they're different members, uctoffset is not ignored.
d0 = base.replace(minute=3, tzinfo=OperandDependentOffset()) # Note that a timetz can't actually have an operand-depedent offset,
d1 = base.replace(minute=9, tzinfo=OperandDependentOffset()) # though (and timetz.utcoffset() passes None to tzinfo.utcoffset()),
d2 = base.replace(minute=11, tzinfo=OperandDependentOffset()) # so skip this test for timetz.
for x in d0, d1, d2: if cls is not timetz:
for y in d0, d1, d2: d0 = base.replace(minute=3, tzinfo=OperandDependentOffset())
got = cmp(x, y) d1 = base.replace(minute=9, tzinfo=OperandDependentOffset())
if (x is d0 or x is d1) and (y is d0 or y is d1): d2 = base.replace(minute=11, tzinfo=OperandDependentOffset())
expected = 0 for x in d0, d1, d2:
elif x is y is d2: for y in d0, d1, d2:
expected = 0 got = cmp(x, y)
elif x is d2: if (x is d0 or x is d1) and (y is d0 or y is d1):
expected = -1 expected = 0
else: elif x is y is d2:
assert y is d2 expected = 0
expected = 1 elif x is d2:
self.assertEqual(got, expected) expected = -1
else:
assert y is d2
expected = 1
self.assertEqual(got, expected)
class TestTimeTZ(TestTime, TZInfoBase): class TestTimeTZ(TestTime, TZInfoBase):
...@@ -2535,7 +2556,7 @@ class USTimeZone(tzinfo): ...@@ -2535,7 +2556,7 @@ class USTimeZone(tzinfo):
return self.stdoffset + self.dst(dt) return self.stdoffset + self.dst(dt)
def dst(self, dt): def dst(self, dt):
if dt is None or isinstance(dt, time) or dt.tzinfo is None: if dt is None or dt.tzinfo is None:
# An exception instead may be sensible here, in one or more of # An exception instead may be sensible here, in one or more of
# the cases. # the cases.
return ZERO return ZERO
......
...@@ -564,22 +564,22 @@ check_tzinfo_subclass(PyObject *p) ...@@ -564,22 +564,22 @@ check_tzinfo_subclass(PyObject *p)
return -1; return -1;
} }
/* Return tzinfo.methname(self), without any checking of results. /* Return tzinfo.methname(tzinfoarg), without any checking of results.
* If tzinfo is None, returns None. * If tzinfo is None, returns None.
*/ */
static PyObject * static PyObject *
call_tzinfo_method(PyObject *self, PyObject *tzinfo, char *methname) call_tzinfo_method(PyObject *tzinfo, char *methname, PyObject *tzinfoarg)
{ {
PyObject *result; PyObject *result;
assert(self && tzinfo && methname); assert(tzinfo && methname && tzinfoarg);
assert(check_tzinfo_subclass(tzinfo) >= 0); assert(check_tzinfo_subclass(tzinfo) >= 0);
if (tzinfo == Py_None) { if (tzinfo == Py_None) {
result = Py_None; result = Py_None;
Py_INCREF(result); Py_INCREF(result);
} }
else else
result = PyObject_CallMethod(tzinfo, methname, "O", self); result = PyObject_CallMethod(tzinfo, methname, "O", tzinfoarg);
return result; return result;
} }
...@@ -612,8 +612,8 @@ replace_tzinfo(PyObject *self, PyObject *newtzinfo) ...@@ -612,8 +612,8 @@ replace_tzinfo(PyObject *self, PyObject *newtzinfo)
((PyDateTime_DateTimeTZ *)self)->tzinfo = newtzinfo; ((PyDateTime_DateTimeTZ *)self)->tzinfo = newtzinfo;
} }
/* Internal helper.
* Call getattr(tzinfo, name)(tzinfoarg), and extract an int from the /* Call getattr(tzinfo, name)(tzinfoarg), and extract an int from the
* result. tzinfo must be an instance of the tzinfo class. If the method * result. tzinfo must be an instance of the tzinfo class. If the method
* returns None, this returns 0 and sets *none to 1. If the method doesn't * returns None, this returns 0 and sets *none to 1. If the method doesn't
* return a Python int or long or timedelta, TypeError is raised and this * return a Python int or long or timedelta, TypeError is raised and this
...@@ -635,7 +635,7 @@ call_utc_tzinfo_method(PyObject *tzinfo, char *name, PyObject *tzinfoarg, ...@@ -635,7 +635,7 @@ call_utc_tzinfo_method(PyObject *tzinfo, char *name, PyObject *tzinfoarg,
assert(tzinfoarg != NULL); assert(tzinfoarg != NULL);
*none = 0; *none = 0;
u = call_tzinfo_method(tzinfoarg, tzinfo, name); u = call_tzinfo_method(tzinfo, name, tzinfoarg);
if (u == NULL) if (u == NULL)
return -1; return -1;
...@@ -702,18 +702,21 @@ call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg, int *none) ...@@ -702,18 +702,21 @@ call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg, int *none)
static PyObject *new_delta(int d, int sec, int usec, int normalize); static PyObject *new_delta(int d, int sec, int usec, int normalize);
/* Call tzinfo.name(self) and return the offset as a timedelta or None. */ /* Call tzinfo.name(tzinfoarg), and return the offset as a timedelta or None.
*/
static PyObject * static PyObject *
offset_as_timedelta(PyObject *self, PyObject *tzinfo, char *name) { offset_as_timedelta(PyObject *tzinfo, char *name, PyObject *tzinfoarg) {
PyObject *result; PyObject *result;
assert(tzinfo && name && tzinfoarg);
if (tzinfo == Py_None) { if (tzinfo == Py_None) {
result = Py_None; result = Py_None;
Py_INCREF(result); Py_INCREF(result);
} }
else { else {
int none; int none;
int offset = call_utc_tzinfo_method(tzinfo, name, self, &none); int offset = call_utc_tzinfo_method(tzinfo, name, tzinfoarg,
&none);
if (offset < 0 && PyErr_Occurred()) if (offset < 0 && PyErr_Occurred())
return NULL; return NULL;
if (none) { if (none) {
...@@ -740,26 +743,26 @@ call_dst(PyObject *tzinfo, PyObject *tzinfoarg, int *none) ...@@ -740,26 +743,26 @@ call_dst(PyObject *tzinfo, PyObject *tzinfoarg, int *none)
return call_utc_tzinfo_method(tzinfo, "dst", tzinfoarg, none); return call_utc_tzinfo_method(tzinfo, "dst", tzinfoarg, none);
} }
/* Call tzinfo.tzname(self), and return the result. tzinfo must be /* Call tzinfo.tzname(tzinfoarg), and return the result. tzinfo must be
* an instance of the tzinfo class or None. If tzinfo isn't None, and * an instance of the tzinfo class or None. If tzinfo isn't None, and
* tzname() doesn't return None ora string, TypeError is raised and this * tzname() doesn't return None or a string, TypeError is raised and this
* returns NULL. * returns NULL.
*/ */
static PyObject * static PyObject *
call_tzname(PyObject *self, PyObject *tzinfo) call_tzname(PyObject *tzinfo, PyObject *tzinfoarg)
{ {
PyObject *result; PyObject *result;
assert(self != NULL);
assert(tzinfo != NULL); assert(tzinfo != NULL);
assert(check_tzinfo_subclass(tzinfo) >= 0); assert(check_tzinfo_subclass(tzinfo) >= 0);
assert(tzinfoarg != NULL);
if (tzinfo == Py_None) { if (tzinfo == Py_None) {
result = Py_None; result = Py_None;
Py_INCREF(result); Py_INCREF(result);
} }
else else
result = PyObject_CallMethod(tzinfo, "tzname", "O", self); result = PyObject_CallMethod(tzinfo, "tzname", "O", tzinfoarg);
if (result != NULL && result != Py_None && ! PyString_Check(result)) { if (result != NULL && result != Py_None && ! PyString_Check(result)) {
PyErr_Format(PyExc_TypeError, "tzinfo.tzname() must " PyErr_Format(PyExc_TypeError, "tzinfo.tzname() must "
...@@ -816,7 +819,9 @@ classify_utcoffset(PyObject *op, int *offset) ...@@ -816,7 +819,9 @@ classify_utcoffset(PyObject *op, int *offset)
return (PyTime_Check(op) || PyDate_Check(op)) ? return (PyTime_Check(op) || PyDate_Check(op)) ?
OFFSET_NAIVE : OFFSET_UNKNOWN; OFFSET_NAIVE : OFFSET_UNKNOWN;
} }
*offset = call_utcoffset(tzinfo, op, &none); *offset = call_utcoffset(tzinfo,
PyTimeTZ_Check(op) ? Py_None : op,
&none);
if (*offset == -1 && PyErr_Occurred()) if (*offset == -1 && PyErr_Occurred())
return OFFSET_ERROR; return OFFSET_ERROR;
return none ? OFFSET_NAIVE : OFFSET_AWARE; return none ? OFFSET_NAIVE : OFFSET_AWARE;
...@@ -951,9 +956,12 @@ format_utcoffset(char *buf, size_t buflen, const char *sep, ...@@ -951,9 +956,12 @@ format_utcoffset(char *buf, size_t buflen, const char *sep,
* so this imports the module and calls it. All the hair is due to * so this imports the module and calls it. All the hair is due to
* giving special meanings to the %z and %Z format codes via a preprocessing * giving special meanings to the %z and %Z format codes via a preprocessing
* step on the format string. * step on the format string.
* tzinfoarg is the argument to pass to the object's tzinfo method, if
* needed.
*/ */
static PyObject * static PyObject *
wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple) wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
PyObject *tzinfoarg)
{ {
PyObject *result = NULL; /* guilty until proved innocent */ PyObject *result = NULL; /* guilty until proved innocent */
...@@ -1031,11 +1039,12 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple) ...@@ -1031,11 +1039,12 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple)
zreplacement = PyString_FromString(""); zreplacement = PyString_FromString("");
if (zreplacement == NULL) goto Done; if (zreplacement == NULL) goto Done;
if (tzinfo != Py_None && tzinfo != NULL) { if (tzinfo != Py_None && tzinfo != NULL) {
assert(tzinfoarg != NULL);
if (format_utcoffset(buf, if (format_utcoffset(buf,
sizeof(buf), sizeof(buf),
"", "",
tzinfo, tzinfo,
object) < 0) tzinfoarg) < 0)
goto Done; goto Done;
Py_DECREF(zreplacement); Py_DECREF(zreplacement);
zreplacement = PyString_FromString(buf); zreplacement = PyString_FromString(buf);
...@@ -1053,8 +1062,9 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple) ...@@ -1053,8 +1062,9 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple)
Zreplacement = PyString_FromString(""); Zreplacement = PyString_FromString("");
if (Zreplacement == NULL) goto Done; if (Zreplacement == NULL) goto Done;
if (tzinfo != Py_None && tzinfo != NULL) { if (tzinfo != Py_None && tzinfo != NULL) {
PyObject *temp = call_tzname(object, PyObject *temp;
tzinfo); assert(tzinfoarg != NULL);
temp = call_tzname(tzinfo, tzinfoarg);
if (temp == NULL) goto Done; if (temp == NULL) goto Done;
if (temp != Py_None) { if (temp != Py_None) {
assert(PyString_Check(temp)); assert(PyString_Check(temp));
...@@ -2424,7 +2434,8 @@ date_strftime(PyDateTime_Date *self, PyObject *args, PyObject *kw) ...@@ -2424,7 +2434,8 @@ date_strftime(PyDateTime_Date *self, PyObject *args, PyObject *kw)
tuple = PyObject_CallMethod((PyObject *)self, "timetuple", "()"); tuple = PyObject_CallMethod((PyObject *)self, "timetuple", "()");
if (tuple == NULL) if (tuple == NULL)
return NULL; return NULL;
result = wrap_strftime((PyObject *)self, format, tuple); result = wrap_strftime((PyObject *)self, format, tuple,
(PyObject *)self);
Py_DECREF(tuple); Py_DECREF(tuple);
return result; return result;
} }
...@@ -3652,7 +3663,7 @@ time_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw) ...@@ -3652,7 +3663,7 @@ time_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw)
if (tuple == NULL) if (tuple == NULL)
return NULL; return NULL;
assert(PyTuple_Size(tuple) == 9); assert(PyTuple_Size(tuple) == 9);
result = wrap_strftime((PyObject *)self, format, tuple); result = wrap_strftime((PyObject *)self, format, tuple, Py_None);
Py_DECREF(tuple); Py_DECREF(tuple);
return result; return result;
} }
...@@ -4140,18 +4151,17 @@ timetz_dealloc(PyDateTime_TimeTZ *self) ...@@ -4140,18 +4151,17 @@ timetz_dealloc(PyDateTime_TimeTZ *self)
/* These are all METH_NOARGS, so don't need to check the arglist. */ /* These are all METH_NOARGS, so don't need to check the arglist. */
static PyObject * static PyObject *
timetz_utcoffset(PyDateTime_TimeTZ *self, PyObject *unused) { timetz_utcoffset(PyDateTime_TimeTZ *self, PyObject *unused) {
return offset_as_timedelta((PyObject *)self, self->tzinfo, return offset_as_timedelta(self->tzinfo, "utcoffset", Py_None);
"utcoffset");
} }
static PyObject * static PyObject *
timetz_dst(PyDateTime_TimeTZ *self, PyObject *unused) { timetz_dst(PyDateTime_TimeTZ *self, PyObject *unused) {
return offset_as_timedelta((PyObject *)self, self->tzinfo, "dst"); return offset_as_timedelta(self->tzinfo, "dst", Py_None);
} }
static PyObject * static PyObject *
timetz_tzname(PyDateTime_TimeTZ *self, PyObject *unused) { timetz_tzname(PyDateTime_TimeTZ *self, PyObject *unused) {
return call_tzname((PyObject *)self, self->tzinfo); return call_tzname(self->tzinfo, Py_None);
} }
/* /*
...@@ -4181,7 +4191,7 @@ timetz_isoformat(PyDateTime_TimeTZ *self) ...@@ -4181,7 +4191,7 @@ timetz_isoformat(PyDateTime_TimeTZ *self)
/* We need to append the UTC offset. */ /* We need to append the UTC offset. */
if (format_utcoffset(buf, sizeof(buf), ":", self->tzinfo, if (format_utcoffset(buf, sizeof(buf), ":", self->tzinfo,
(PyObject *)self) < 0) { Py_None) < 0) {
Py_DECREF(result); Py_DECREF(result);
return NULL; return NULL;
} }
...@@ -4234,7 +4244,7 @@ timetz_nonzero(PyDateTime_TimeTZ *self) ...@@ -4234,7 +4244,7 @@ timetz_nonzero(PyDateTime_TimeTZ *self)
} }
offset = 0; offset = 0;
if (self->tzinfo != Py_None) { if (self->tzinfo != Py_None) {
offset = call_utcoffset(self->tzinfo, (PyObject *)self, &none); offset = call_utcoffset(self->tzinfo, Py_None, &none);
if (offset == -1 && PyErr_Occurred()) if (offset == -1 && PyErr_Occurred())
return -1; return -1;
} }
...@@ -4543,18 +4553,18 @@ datetimetz_dealloc(PyDateTime_DateTimeTZ *self) ...@@ -4543,18 +4553,18 @@ datetimetz_dealloc(PyDateTime_DateTimeTZ *self)
/* These are all METH_NOARGS, so don't need to check the arglist. */ /* These are all METH_NOARGS, so don't need to check the arglist. */
static PyObject * static PyObject *
datetimetz_utcoffset(PyDateTime_DateTimeTZ *self, PyObject *unused) { datetimetz_utcoffset(PyDateTime_DateTimeTZ *self, PyObject *unused) {
return offset_as_timedelta((PyObject *)self, self->tzinfo, return offset_as_timedelta(self->tzinfo, "utcoffset",
"utcoffset"); (PyObject *)self);
} }
static PyObject * static PyObject *
datetimetz_dst(PyDateTime_DateTimeTZ *self, PyObject *unused) { datetimetz_dst(PyDateTime_DateTimeTZ *self, PyObject *unused) {
return offset_as_timedelta((PyObject *)self, self->tzinfo, "dst"); return offset_as_timedelta(self->tzinfo, "dst", (PyObject *)self);
} }
static PyObject * static PyObject *
datetimetz_tzname(PyDateTime_DateTimeTZ *self, PyObject *unused) { datetimetz_tzname(PyDateTime_DateTimeTZ *self, PyObject *unused) {
return call_tzname((PyObject *)self, self->tzinfo); return call_tzname(self->tzinfo, (PyObject *)self);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment