[Python-checkins] python/nondist/sandbox/datetime obj_datetimetz.c,NONE,1.1 datetime.c,1.62,1.63 datetime.h,1.15,1.16 obj_date.c,1.48,1.49 obj_datetime.c,1.46,1.47
tim_one@users.sourceforge.net
tim_one@users.sourceforge.net
Thu, 12 Dec 2002 17:13:49 -0800
Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv26152
Modified Files:
datetime.c datetime.h obj_date.c obj_datetime.c
Added Files:
obj_datetimetz.c
Log Message:
Added a non-functional C datetimetz implementation. It compiles and
the tests pass, but the new C type isn't really being used yet.
--- NEW FILE: obj_datetimetz.c ---
/* XXX This isn't functional yet, it merely compiles. It's a copy and
* XXX very light edit of obj_datetime.c.
*/
/*
* PyDateTime_DateTimeTZ implementation.
*/
/* Accessor properties. */
static PyObject *
datetimetz_hour(PyDateTime_DateTimeTZ *self, void *unused)
{
return PyInt_FromLong(DATE_GET_HOUR(self));
}
static PyObject *
datetimetz_minute(PyDateTime_DateTimeTZ *self, void *unused)
{
return PyInt_FromLong(DATE_GET_MINUTE(self));
}
static PyObject *
datetimetz_second(PyDateTime_DateTimeTZ *self, void *unused)
{
return PyInt_FromLong(DATE_GET_SECOND(self));
}
static PyObject *
datetimetz_microsecond(PyDateTime_DateTimeTZ *self, void *unused)
{
return PyInt_FromLong(DATE_GET_MICROSECOND(self));
}
static PyGetSetDef datetimetz_getset[] = {
{"hour", (getter)datetimetz_hour},
{"minute", (getter)datetimetz_minute},
{"second", (getter)datetimetz_second},
{"microsecond", (getter)datetimetz_microsecond},
{NULL}
};
/* Constructors. */
static PyObject *
datetimetz_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
PyObject *self = NULL;
long year;
long month;
long day;
long hour = 0;
long minute = 0;
long second = 0;
long usecond = 0;
static char *keywords[] = {
"year", "month", "day", "hour", "minute", "second",
"microsecond", NULL
};
if (PyArg_ParseTupleAndKeywords(args, kw, "lll|llll", keywords,
&year, &month, &day, &hour, &minute,
&second, &usecond)) {
if (year < MINYEAR || year > MAXYEAR) {
PyErr_SetString(PyExc_ValueError,
"year is out of range");
return NULL;
}
if (month < 1 || month > 12) {
PyErr_SetString(PyExc_ValueError,
"month must be in 1..12");
return NULL;
}
if (day < 1 || day > days_in_month(year, month)) {
PyErr_SetString(PyExc_ValueError,
"day is out of range for month");
return NULL;
}
if (hour < 0 || hour > 23) {
PyErr_SetString(PyExc_ValueError,
"hour must be in 0..23");
return NULL;
}
if (minute < 0 || minute > 59) {
PyErr_SetString(PyExc_ValueError,
"minute must be in 0..59");
return NULL;
}
if (second < 0 || second > 59) {
PyErr_SetString(PyExc_ValueError,
"second must be in 0..59");
return NULL;
}
if (usecond < 0 || usecond > 999999) {
PyErr_SetString(PyExc_ValueError,
"microsecond must be in 0..999999");
return NULL;
}
self = new_datetime(year, month, day, hour, minute, second,
usecond);
}
return self;
}
/* TM_FUNC is the shared type of localtime() and gmtime(). */
typedef struct tm *(*TM_FUNC)(const time_t *timer);
/* Internal helper.
* Build datetime from a time_t and a distinct count of microseconds.
* Pass localtime or gmtime for f, to control the interpretation of timet.
*/
static PyObject *
datetimetz_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, long us)
{
struct tm *tm;
PyObject *result = NULL;
tm = f(&timet);
if (tm)
result = PyObject_CallFunction(cls, "iiiiiil",
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour,
tm->tm_min,
tm->tm_sec,
us);
else
PyErr_SetString(PyExc_ValueError,
"timestamp out of range for "
"platform localtime()/gmtime() function");
return result;
}
/* Internal helper.
* Build datetime from a Python timestamp. Pass localtime or gmtime for f,
* to control the interpretation of the timestamp. Since a double doesn't
* have enough bits to cover a datetime's full range of precision, it's
* better to call datetimetz_from_timet_and_us provided you have a way
* to get that much precision (e.g., C time() isn't good enough).
*/
static PyObject *
datetimetz_from_timestamp(PyObject *cls, TM_FUNC f, double timestamp)
{
time_t timet = (time_t)timestamp;
long us = (long)((timestamp - (double)timet) * 1e6);
return datetimetz_from_timet_and_us(cls, f, timet, us);
}
/* Internal helper.
* Build most accurate possible datetime for current time. Pass localtime or
* gmtime for f as appropriate.
*/
static PyObject *
datetimetz_best_possible(PyObject *cls, TM_FUNC f)
{
#ifdef HAVE_GETTIMEOFDAY
struct timeval t;
#ifdef GETTIMEOFDAY_NO_TZ
gettimeofday(&t);
#else
gettimeofday(&t, (struct timezone *)NULL);
#endif
return datetimetz_from_timet_and_us(cls, f, t.tv_sec, t.tv_usec);
#else /* ! HAVE_GETTIMEOFDAY */
/* No flavor of gettimeofday exists on this platform. Python's
* time.time() does a lot of other platform tricks to get the
* best time it can on the platform, and we're not going to do
* better than that (if we could, the better code would belong
* in time.time()!) We're limited by the precision of a double,
* though.
*/
PyObject *time;
double dtime;
time = time_time();
if (time == NULL)
return NULL;
dtime = PyFloat_AsDouble(time);
Py_DECREF(time);
if (dtime == -1.0 && PyErr_Occurred())
return NULL;
return datetimetz_from_timestamp(cls, f, dtime);
#endif /* ! HAVE_GETTIMEOFDAY */
}
/* Return new local datetime from timestamp (Python timestamp -- a double). */
static PyObject *
datetimetz_fromtimestamp(PyObject *cls, PyObject *args)
{
double timestamp;
PyObject *result = NULL;
if (PyArg_ParseTuple(args, "d:fromtimestamp", ×tamp))
result = datetimetz_from_timestamp(cls, localtime, timestamp);
return result;
}
/* Return new UTC datetime from timestamp (Python timestamp -- a double). */
static PyObject *
datetimetz_utcfromtimestamp(PyObject *cls, PyObject *args)
{
double timestamp;
PyObject *result = NULL;
if (PyArg_ParseTuple(args, "d:utcfromtimestamp", ×tamp))
result = datetimetz_from_timestamp(cls, gmtime, timestamp);
return result;
}
/* Return best possible local time -- this isn't constrained by the
* precision of a timestamp.
*/
static PyObject *
datetimetz_now(PyObject *cls, PyObject *dummy)
{
return datetimetz_best_possible(cls, localtime);
}
/* Return best possible UTC time -- this isn't constrained by the
* precision of a timestamp.
*/
static PyObject *
datetimetz_utcnow(PyObject *cls, PyObject *dummy)
{
return datetimetz_best_possible(cls, gmtime);
}
/* Return new datetime from date and time arguments. */
static PyObject *
datetimetz_combine(PyObject *cls, PyObject *args, PyObject *kw)
{
static char *keywords[] = {"date", "time", NULL};
PyObject *date;
PyObject *time;
PyObject *result = NULL;
if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!:combine", keywords,
&PyDateTime_DateType, &date,
&PyDateTime_TimeType, &time))
result = PyObject_CallFunction(cls, "iiiiiii",
GET_YEAR(date),
GET_MONTH(date),
GET_DAY(date),
TIME_GET_HOUR(time),
TIME_GET_MINUTE(time),
TIME_GET_SECOND(time),
TIME_GET_MICROSECOND(time));
return result;
}
/* datetime arithmetic. */
static PyObject *
add_datetimetz_timedelta(PyDateTime_DateTimeTZ *date, PyDateTime_Delta *delta)
{
/* Note that the C-level additions can't overflow, because of
* invariant bounds on the member values.
*/
long year = GET_YEAR(date);
long month = GET_MONTH(date);
long day = GET_DAY(date) + GET_TD_DAYS(delta);
long hour = DATE_GET_HOUR(date);
long minute = DATE_GET_MINUTE(date);
long second = DATE_GET_SECOND(date) + GET_TD_SECONDS(delta);
long microsecond = DATE_GET_MICROSECOND(date) +
GET_TD_MICROSECONDS(delta);
if (normalize_datetime(&year, &month, &day,
&hour, &minute, &second, µsecond) < 0)
return NULL;
else
return new_datetime(year, month, day,
hour, minute, second, microsecond);
}
static PyObject *
sub_datetimetz_timedelta(PyDateTime_DateTimeTZ *date, PyDateTime_Delta *delta)
{
/* Note that the C-level subtractions can't overflow, because of
* invariant bounds on the member values.
*/
long year = GET_YEAR(date);
long month = GET_MONTH(date);
long day = GET_DAY(date) - GET_TD_DAYS(delta);
long hour = DATE_GET_HOUR(date);
long minute = DATE_GET_MINUTE(date);
long second = DATE_GET_SECOND(date) - GET_TD_SECONDS(delta);
long microsecond = DATE_GET_MICROSECOND(date) -
GET_TD_MICROSECONDS(delta);
if (normalize_datetime(&year, &month, &day,
&hour, &minute, &second, µsecond) < 0)
return NULL;
else
return new_datetime(year, month, day,
hour, minute, second, microsecond);
}
static PyObject *
sub_datetimetz_datetime(PyDateTime_DateTimeTZ *left, PyDateTime_DateTimeTZ *right)
{
long days1 = ymd_to_ord(GET_YEAR(left),
GET_MONTH(left),
GET_DAY(left));
long days2 = ymd_to_ord(GET_YEAR(right),
GET_MONTH(right),
GET_DAY(right));
/* These can't overflow, since the values are normalized. At most
* this gives the number of seconds in one day.
*/
long delta_s = (DATE_GET_HOUR(left) - DATE_GET_HOUR(right)) * 3600 +
(DATE_GET_MINUTE(left) - DATE_GET_MINUTE(right)) * 60 +
DATE_GET_SECOND(left) - DATE_GET_SECOND(right);
long delta_us = DATE_GET_MICROSECOND(left) -
DATE_GET_MICROSECOND(right);
return new_delta(days1 - days2, delta_s, delta_us, 1);
}
static PyObject *
datetimetz_add(PyObject *left, PyObject *right)
{
PyTypeObject *left_type = left->ob_type;
PyTypeObject *right_type = right->ob_type;
if (PyType_IsSubtype(left_type, &PyDateTime_DateTimeType)) {
/* datetime + ??? */
if (PyType_IsSubtype(right_type, &PyDateTime_DeltaType))
/* datetime + delta */
return add_datetimetz_timedelta(
(PyDateTime_DateTimeTZ *)left,
(PyDateTime_Delta *)right);
}
else if (PyType_IsSubtype(left_type, &PyDateTime_DeltaType)) {
/* delta + datetime */
return add_datetimetz_timedelta((PyDateTime_DateTimeTZ *) right,
(PyDateTime_Delta *) left);
}
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
static PyObject *
datetimetz_subtract(PyObject *left, PyObject *right)
{
PyTypeObject *left_type = left->ob_type;
PyTypeObject *right_type = right->ob_type;
PyObject *result = Py_NotImplemented;
if (PyType_IsSubtype(left_type, &PyDateTime_DateTimeType)) {
/* datetime - ??? */
if (PyType_IsSubtype(right_type, &PyDateTime_DateTimeType)) {
/* datetime - datetime */
result = sub_datetimetz_datetime(
(PyDateTime_DateTimeTZ *)left,
(PyDateTime_DateTimeTZ *)right);
}
else if (PyType_IsSubtype(right_type, &PyDateTime_DeltaType)) {
/* datetime - delta */
result = sub_datetimetz_timedelta(
(PyDateTime_DateTimeTZ *)left,
(PyDateTime_Delta *)right);
}
}
if (result == Py_NotImplemented)
Py_INCREF(result);
return result;
}
/* Various ways to turn a datetime into a string. */
static PyObject *
datetimetz_repr(PyDateTime_DateTimeTZ *self)
{
char buffer[1000];
char *typename = self->ob_type->tp_name;
if (DATE_GET_MICROSECOND(self)) {
PyOS_snprintf(buffer, sizeof(buffer),
"%s(%d, %d, %d, %d, %d, %d, %d)",
typename,
GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
DATE_GET_SECOND(self),
DATE_GET_MICROSECOND(self));
}
else if (DATE_GET_SECOND(self)) {
PyOS_snprintf(buffer, sizeof(buffer),
"%s(%d, %d, %d, %d, %d, %d)",
typename,
GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
DATE_GET_SECOND(self));
}
else {
PyOS_snprintf(buffer, sizeof(buffer),
"%s(%d, %d, %d, %d, %d)",
typename,
GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
DATE_GET_HOUR(self), DATE_GET_MINUTE(self));
}
return PyString_FromString(buffer);
}
static PyObject *
datetimetz_str(PyDateTime_DateTimeTZ *self)
{
return PyObject_CallMethod((PyObject *)self, "isoformat", "(s)", " ");
}
static PyObject *
datetimetz_isoformat(PyDateTime_DateTimeTZ *self,
PyObject *args, PyObject *kw)
{
char sep = 'T';
static char *keywords[] = {"sep", NULL};
char buffer[100];
char *cp;
if (!PyArg_ParseTupleAndKeywords(args, kw, "|c:isoformat", keywords,
&sep))
return NULL;
cp = isoformat_date((PyDateTime_Date *)self, buffer, sizeof(buffer));
assert(cp != NULL);
*cp++ = sep;
isoformat_time((PyDateTime_DateTime *)self,
cp,
sizeof(buffer) - (cp - buffer));
return PyString_FromString(buffer);
}
static PyObject *
datetimetz_ctime(PyDateTime_DateTimeTZ *self)
{
return format_ctime((PyDateTime_Date *)self,
DATE_GET_HOUR(self),
DATE_GET_MINUTE(self),
DATE_GET_SECOND(self));
}
/* Miscellaneous methods. */
/* This is more natural as a tp_compare, but doesn't work then: for whatever
* reason, Python's try_3way_compare ignores tp_compare unless
* PyInstance_Check returns true, but these aren't old-style classes.
*/
static PyObject *
datetimetz_richcompare(PyDateTime_DateTimeTZ *self, PyObject *other, int op)
{
long diff;
if (!PyType_IsSubtype(other->ob_type, &PyDateTime_DateTimeTZType)) {
PyErr_Format(PyExc_TypeError,
"can't compare datetime to %s instance",
other->ob_type->tp_name);
return NULL;
}
diff = memcmp(self->data, ((PyDateTime_DateTimeTZ *)other)->data,
_PyDateTime_DATETIME_DATASIZE);
return diff_to_bool(diff, op);
}
static PyObject *datetimetz_getstate(PyDateTime_DateTimeTZ *self);
static long
datetimetz_hash(PyDateTime_DateTimeTZ *self)
{
if (self->hashcode == -1) {
PyObject *temp = datetimetz_getstate(self);
if (temp != NULL) {
self->hashcode = PyObject_Hash(temp);
Py_DECREF(temp);
}
}
return self->hashcode;
}
static PyObject *
datetimetz_timetuple(PyDateTime_DateTimeTZ *self)
{
return build_struct_time(GET_YEAR(self),
GET_MONTH(self),
GET_DAY(self),
DATE_GET_HOUR(self),
DATE_GET_MINUTE(self),
DATE_GET_SECOND(self));
}
static PyObject *
datetimetz_getdate(PyDateTime_DateTimeTZ *self)
{
return new_date(GET_YEAR(self),
GET_MONTH(self),
GET_DAY(self));
}
static PyObject *
datetimetz_gettime(PyDateTime_DateTimeTZ *self)
{
return new_time(DATE_GET_HOUR(self),
DATE_GET_MINUTE(self),
DATE_GET_SECOND(self),
DATE_GET_MICROSECOND(self));
}
/* Pickle support. Quite a maze! */
static PyObject *
datetimetz_getstate(PyDateTime_DateTimeTZ *self)
{
return PyString_FromStringAndSize(self->data,
_PyDateTime_DATETIME_DATASIZE);
}
static PyObject *
datetimetz_setstate(PyDateTime_DateTimeTZ *self, PyObject *state)
{
const int len = PyString_Size(state);
unsigned char *pdata = (unsigned char*)PyString_AsString(state);
if (! PyString_Check(state) ||
len != _PyDateTime_DATETIME_DATASIZE) {
PyErr_SetString(PyExc_TypeError,
"bad argument to datetime.__setstate__");
return NULL;
}
memcpy(self->data, pdata, _PyDateTime_DATETIME_DATASIZE);
self->hashcode = -1;
Py_INCREF(Py_None);
return Py_None;
}
/* XXX This seems a ridiculously inefficient way to pickle a short string. */
static PyObject *
datetimetz_pickler(PyObject *module, PyDateTime_DateTimeTZ *datetime)
{
PyObject *state;
PyObject *result = NULL;
if (datetime->ob_type != &PyDateTime_DateTimeType) {
PyErr_Format(PyExc_TypeError,
"bad type passed to datetime pickler: %s",
datetime->ob_type->tp_name);
return NULL;
}
state = datetimetz_getstate(datetime);
if (state) {
result = Py_BuildValue("O(O)",
datetimetz_unpickler_object,
state);
Py_DECREF(state);
}
return result;
}
static PyObject *
datetimetz_unpickler(PyObject *module, PyObject *arg)
{
PyDateTime_DateTimeTZ *self;
if (! PyString_CheckExact(arg)) {
PyErr_Format(PyExc_TypeError,
"bad type passed to datetime unpickler: %s",
arg->ob_type->tp_name);
return NULL;
}
self = PyObject_New(PyDateTime_DateTimeTZ, &PyDateTime_DateTimeType);
if (self != NULL) {
PyObject *res = datetimetz_setstate(self, arg);
if (res == NULL) {
Py_DECREF(self);
return NULL;
}
Py_DECREF(res);
}
return (PyObject *)self;
}
static PyMethodDef datetimetz_methods[] = {
/* Class methods: */
{"now", (PyCFunction)datetimetz_now,
METH_NOARGS | METH_CLASS,
PyDoc_STR("Return a new datetime representing local day and time.")},
{"utcnow", (PyCFunction)datetimetz_utcnow,
METH_NOARGS | METH_CLASS,
PyDoc_STR("Return a new datetime representing UTC day and time.")},
{"fromtimestamp", (PyCFunction)datetimetz_fromtimestamp,
METH_VARARGS | METH_CLASS,
PyDoc_STR("timestamp -> local datetime from a POSIX timestamp "
"(like time.time()).")},
{"utcfromtimestamp", (PyCFunction)datetimetz_utcfromtimestamp,
METH_VARARGS | METH_CLASS,
PyDoc_STR("timestamp -> UTC datetime from a POSIX timestamp "
"(like time.time()).")},
{"combine", (PyCFunction)datetimetz_combine,
METH_VARARGS | METH_KEYWORDS | METH_CLASS,
PyDoc_STR("date, time -> datetime with same date and time fields")},
/* Instance methods: */
{"timetuple", (PyCFunction)datetimetz_timetuple, METH_NOARGS,
PyDoc_STR("Return time tuple, compatible with time.localtime().")},
{"date", (PyCFunction)datetimetz_getdate, METH_NOARGS,
PyDoc_STR("Return date object with same year, month and day.")},
{"time", (PyCFunction)datetimetz_gettime, METH_NOARGS,
PyDoc_STR("Return time object with same hour, minute, second and "
"microsecond.")},
{"ctime", (PyCFunction)datetimetz_ctime, METH_NOARGS,
PyDoc_STR("Return ctime() style string.")},
{"isoformat", (PyCFunction)datetimetz_isoformat, METH_KEYWORDS,
PyDoc_STR("[sep] -> string in ISO 8601 format, "
"YYYY-MM-DDTHH:MM:SS[.mmmmmm].\n\n"
"sep is used to separate the year from the time, and "
"defaults\n"
"to 'T'.")},
{"__setstate__", (PyCFunction)datetimetz_setstate, METH_O,
PyDoc_STR("__setstate__(state)")},
{"__getstate__", (PyCFunction)datetimetz_getstate, METH_NOARGS,
PyDoc_STR("__getstate__() -> state")},
{NULL, NULL}
};
static char datetimetz_doc[] =
PyDoc_STR("date/time type.");
static PyNumberMethods datetimetz_as_number = {
datetimetz_add, /* nb_add */
datetimetz_subtract, /* nb_subtract */
0, /* nb_multiply */
0, /* nb_divide */
0, /* nb_remainder */
0, /* nb_divmod */
0, /* nb_power */
0, /* nb_negative */
0, /* nb_positive */
0, /* nb_absolute */
0, /* nb_nonzero */
};
statichere PyTypeObject PyDateTime_DateTimeTZType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
/* XXX When this module is renamed to datetime, change tp_name. */
"_datetime.datetimetz", /* tp_name */
sizeof(PyDateTime_DateTimeTZ), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)PyObject_Del, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)datetimetz_repr, /* tp_repr */
&datetimetz_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)datetimetz_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)datetimetz_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
Py_TPFLAGS_BASETYPE, /* tp_flags */
datetimetz_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
(richcmpfunc)datetimetz_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
datetimetz_methods, /* tp_methods */
0, /* tp_members */
datetimetz_getset, /* tp_getset */
&PyDateTime_DateTimeType, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
datetimetz_new, /* tp_new */
_PyObject_Del, /* tp_free */
};
Index: datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.c,v
retrieving revision 1.62
retrieving revision 1.63
diff -C2 -d -r1.62 -r1.63
*** datetime.c 12 Dec 2002 22:08:22 -0000 1.62
--- datetime.c 13 Dec 2002 01:13:46 -0000 1.63
***************
*** 70,73 ****
--- 70,74 ----
static PyTypeObject PyDateTime_DateType;
static PyTypeObject PyDateTime_DateTimeType;
+ static PyTypeObject PyDateTime_DateTimeTZType;
static PyTypeObject PyDateTime_DeltaType;
static PyTypeObject PyDateTime_TimeType;
***************
*** 404,434 ****
}
- /* Fiddle days (d), seconds (s), and microseconds (us) so that
- * 0 <= *s < 24*3600
- * 0 <= *us < 1000000
- * The input values must be such that the internals don't overflow.
- * The way this routine is used, we don't get close.
- */
- static void
- normalize_d_s_us(long *d, long *s, long *us)
- {
- if (*us < 0 || *us >= 1000000) {
- normalize_pair(s, us, 1000000);
- /* |s| can't be bigger than about
- * |original s| + |original us|/1000000 now.
- */
-
- }
- if (*s < 0 || *s >= 24*3600) {
- normalize_pair(d, s, 24*3600);
- /* |d| can't be bigger than about
- * |original d| +
- * (|original s| + |original us|/1000000) / (24*3600) now.
- */
- }
- assert(0 <= *s && *s < 24*3600);
- assert(0 <= *us && *us < 1000000);
- }
-
/* Fiddle years (y), months (m), and days (d) so that
* 1 <= *m <= 12
--- 405,408 ----
***************
*** 499,502 ****
--- 473,538 ----
}
+ /* Fiddle out-of-bounds months and days so that the result makes some kind
+ * of sense. The parameters are both inputs and outputs. Returns < 0 on
+ * failure, where failure means the adjusted year is out of bounds.
+ */
+ static int
+ normalize_date(long *year, long *month, long *day)
+ {
+ int result;
+
+ normalize_y_m_d(year, month, day);
+ if (MINYEAR <= *year && *year <= MAXYEAR)
+ result = 0;
+ else {
+ PyErr_SetString(PyExc_OverflowError,
+ "date value out of range");
+ result = -1;
+ }
+ return result;
+ }
+
+ /* Force all the datetime fields into range. The parameters are both
+ * inputs and outputs. Returns < 0 on error.
+ */
+ static int
+ normalize_datetime(long *year, long *month, long *day,
+ long *hour, long *minute, long *second,
+ long *microsecond)
+ {
+ normalize_pair(second, microsecond, 1000000);
+ normalize_pair(minute, second, 60);
+ normalize_pair(hour, minute, 60);
+ normalize_pair(day, hour, 24);
+ return normalize_date(year, month, day);
+ }
+
+ /* Fiddle days (d), seconds (s), and microseconds (us) so that
+ * 0 <= *s < 24*3600
+ * 0 <= *us < 1000000
+ * The input values must be such that the internals don't overflow.
+ * The way this routine is used, we don't get close.
+ */
+ static void
+ normalize_d_s_us(long *d, long *s, long *us)
+ {
+ if (*us < 0 || *us >= 1000000) {
+ normalize_pair(s, us, 1000000);
+ /* |s| can't be bigger than about
+ * |original s| + |original us|/1000000 now.
+ */
+
+ }
+ if (*s < 0 || *s >= 24*3600) {
+ normalize_pair(d, s, 24*3600);
+ /* |d| can't be bigger than about
+ * |original d| +
+ * (|original s| + |original us|/1000000) / (24*3600) now.
+ */
+ }
+ assert(0 <= *s && *s < 24*3600);
+ assert(0 <= *us && *us < 1000000);
+ }
+
/* Wrap functions from the time module. These aren't directly available
* from C. Perhaps they should be.
***************
*** 579,582 ****
--- 615,636 ----
}
+ static void
+ set_date_fields(PyDateTime_Date *self, int y, int m, int d)
+ {
+ self->hashcode = -1;
+ SET_YEAR(self, y);
+ SET_MONTH(self, m);
+ SET_DAY(self, d);
+ }
+
+ static void
+ set_datetime_time_fields(PyDateTime_Date *self, int h, int m, int s, int us)
+ {
+ DATE_SET_HOUR(self, h);
+ DATE_SET_MINUTE(self, m);
+ DATE_SET_SECOND(self, s);
+ DATE_SET_MICROSECOND(self, us);
+ }
+
/* Create a date instance with no range checking. */
static PyObject *
***************
*** 586,595 ****
self = PyObject_New(PyDateTime_Date, &PyDateTime_DateType);
! if (self != NULL) {
! self->hashcode = -1;
! SET_YEAR(self, year);
! SET_MONTH(self, month);
! SET_DAY(self, day);
! }
return (PyObject *) self;
}
--- 640,645 ----
self = PyObject_New(PyDateTime_Date, &PyDateTime_DateType);
! if (self != NULL)
! set_date_fields(self, year, month, day);
return (PyObject *) self;
}
***************
*** 604,615 ****
self = PyObject_New(PyDateTime_DateTime, &PyDateTime_DateTimeType);
if (self != NULL) {
! self->hashcode = -1;
! SET_YEAR(self, year);
! SET_MONTH(self, month);
! SET_DAY(self, day);
! DATE_SET_HOUR(self, hour);
! DATE_SET_MINUTE(self, minute);
! DATE_SET_SECOND(self, second);
! DATE_SET_MICROSECOND(self, usecond);
}
return (PyObject *) self;
--- 654,678 ----
self = PyObject_New(PyDateTime_DateTime, &PyDateTime_DateTimeType);
if (self != NULL) {
! set_date_fields((PyDateTime_Date *)self, year, month, day);
! set_datetime_time_fields((PyDateTime_Date *)self,
! hour, minute, second, usecond);
! }
! return (PyObject *) self;
! }
!
! /* Create a datetimetz instance with no range checking. */
! static PyObject *
! new_datetimetz(int year, int month, int day, int hour, int minute,
! int second, int usecond, PyObject *tzinfo)
! {
! PyDateTime_DateTimeTZ *self;
!
! self = PyObject_New(PyDateTime_DateTimeTZ, &PyDateTime_DateTimeTZType);
! if (self != NULL) {
! set_date_fields((PyDateTime_Date *)self, year, month, day);
! set_datetime_time_fields((PyDateTime_Date *)self,
! hour, minute, second, usecond);
! Py_INCREF(tzinfo);
! self->tzinfo = tzinfo;
}
return (PyObject *) self;
***************
*** 791,797 ****
static PyObject *date_unpickler_object = NULL;
static PyObject *datetime_unpickler_object = NULL;
static PyObject *time_unpickler_object = NULL;
static PyObject *timetz_unpickler_object = NULL;
- static PyObject *tzinfo_unpickler_object = NULL;
#include "obj_delta.c"
--- 854,861 ----
static PyObject *date_unpickler_object = NULL;
static PyObject *datetime_unpickler_object = NULL;
+ static PyObject *datetimetz_unpickler_object = NULL;
+ static PyObject *tzinfo_unpickler_object = NULL;
static PyObject *time_unpickler_object = NULL;
static PyObject *timetz_unpickler_object = NULL;
#include "obj_delta.c"
***************
*** 801,804 ****
--- 865,869 ----
#include "obj_tzinfo.c"
#include "obj_timetz.c"
+ #include "obj_datetimetz.c"
***************
*** 811,814 ****
--- 876,881 ----
{"_datetime_pickler", (PyCFunction)datetime_pickler, METH_O, NULL},
{"_datetime_unpickler", (PyCFunction)datetime_unpickler,METH_O, NULL},
+ {"_datetimetz_pickler", (PyCFunction)datetimetz_pickler,METH_O, NULL},
+ {"_datetimetz_unpickler",(PyCFunction)datetimetz_unpickler,METH_O, NULL},
{"_time_pickler", (PyCFunction)time_pickler, METH_O, NULL},
{"_time_unpickler", (PyCFunction)time_unpickler, METH_O, NULL},
***************
*** 850,853 ****
--- 917,922 ----
if (PyType_Ready(&PyDateTime_TimeTZType) < 0)
return;
+ if (PyType_Ready(&PyDateTime_DateTimeTZType) < 0)
+ return;
/* Pickling support, via registering functions with copy_reg. */
***************
*** 857,924 ****
PyObject *copyreg = PyImport_ImportModule("copy_reg");
! assert(copyreg);
pickler = PyObject_GetAttrString(m, "_date_pickler");
! assert(pickler);
date_unpickler_object = PyObject_GetAttrString(m,
"_date_unpickler");
! assert(date_unpickler_object);
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_DateType,
pickler,
date_unpickler_object);
! assert(temp);
Py_DECREF(temp);
Py_DECREF(pickler);
pickler = PyObject_GetAttrString(m, "_datetime_pickler");
! assert(pickler);
datetime_unpickler_object = PyObject_GetAttrString(m,
"_datetime_unpickler");
! assert(datetime_unpickler_object);
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_DateTimeType,
pickler,
datetime_unpickler_object);
! assert(temp);
Py_DECREF(temp);
Py_DECREF(pickler);
pickler = PyObject_GetAttrString(m, "_time_pickler");
! assert(pickler);
time_unpickler_object = PyObject_GetAttrString(m,
"_time_unpickler");
! assert(time_unpickler_object);
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_TimeType,
pickler,
time_unpickler_object);
! assert(temp);
Py_DECREF(temp);
Py_DECREF(pickler);
pickler = PyObject_GetAttrString(m, "_timetz_pickler");
! assert(pickler);
timetz_unpickler_object = PyObject_GetAttrString(m,
"_timetz_unpickler");
! assert(timetz_unpickler_object);
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_TimeTZType,
pickler,
timetz_unpickler_object);
! assert(temp);
Py_DECREF(temp);
Py_DECREF(pickler);
pickler = PyObject_GetAttrString(m, "_tzinfo_pickler");
! assert(pickler);
tzinfo_unpickler_object = PyObject_GetAttrString(m,
"_tzinfo_unpickler");
! assert(tzinfo_unpickler_object);
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_TZInfoType,
pickler,
tzinfo_unpickler_object);
! assert(temp);
Py_DECREF(temp);
Py_DECREF(pickler);
--- 926,1006 ----
PyObject *copyreg = PyImport_ImportModule("copy_reg");
! if (copyreg == NULL) return;
pickler = PyObject_GetAttrString(m, "_date_pickler");
! if (pickler == NULL) return;
date_unpickler_object = PyObject_GetAttrString(m,
"_date_unpickler");
! if (date_unpickler_object == NULL) return;
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_DateType,
pickler,
date_unpickler_object);
! if (temp == NULL) return;
Py_DECREF(temp);
Py_DECREF(pickler);
pickler = PyObject_GetAttrString(m, "_datetime_pickler");
! if (pickler == NULL) return;
datetime_unpickler_object = PyObject_GetAttrString(m,
"_datetime_unpickler");
! if (datetime_unpickler_object == NULL) return;
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_DateTimeType,
pickler,
datetime_unpickler_object);
! if (temp == NULL) return;
Py_DECREF(temp);
Py_DECREF(pickler);
pickler = PyObject_GetAttrString(m, "_time_pickler");
! if (pickler == NULL) return;
time_unpickler_object = PyObject_GetAttrString(m,
"_time_unpickler");
! if (time_unpickler_object == NULL) return;
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_TimeType,
pickler,
time_unpickler_object);
! if (temp == NULL) return;
Py_DECREF(temp);
Py_DECREF(pickler);
pickler = PyObject_GetAttrString(m, "_timetz_pickler");
! if (pickler == NULL) return;
timetz_unpickler_object = PyObject_GetAttrString(m,
"_timetz_unpickler");
! if (timetz_unpickler_object == NULL) return;
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_TimeTZType,
pickler,
timetz_unpickler_object);
! if (temp == NULL) return;
Py_DECREF(temp);
Py_DECREF(pickler);
pickler = PyObject_GetAttrString(m, "_tzinfo_pickler");
! if (pickler == NULL) return;
tzinfo_unpickler_object = PyObject_GetAttrString(m,
"_tzinfo_unpickler");
! if (tzinfo_unpickler_object == NULL) return;
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_TZInfoType,
pickler,
tzinfo_unpickler_object);
! if (temp == NULL) return;
! Py_DECREF(temp);
! Py_DECREF(pickler);
!
! pickler = PyObject_GetAttrString(m, "_datetimetz_pickler");
! if (pickler == NULL) return;
! datetimetz_unpickler_object = PyObject_GetAttrString(m,
! "_datetimetz_unpickler");
! if (datetimetz_unpickler_object == NULL) return;
! temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
! &PyDateTime_DateTimeTZType,
! pickler,
! datetimetz_unpickler_object);
! if (temp == NULL) return;
Py_DECREF(temp);
Py_DECREF(pickler);
***************
*** 1011,1014 ****
--- 1093,1114 ----
x = new_timetz(23, 59, 59, 999999, Py_None);
+ if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
+ return;
+ Py_DECREF(x);
+
+ x = new_delta(0, 0, 1, 0);
+ if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)
+ return;
+ Py_DECREF(x);
+
+ /* datetimetz values */
+ d = PyDateTime_DateTimeTZType.tp_dict;
+
+ x = new_datetimetz(1, 1, 1, 0, 0, 0, 0, Py_None);
+ if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
+ return;
+ Py_DECREF(x);
+
+ x = new_datetimetz(MAXYEAR, 12, 31, 23, 59, 59, 999999, Py_None);
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
return;
Index: datetime.h
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -C2 -d -r1.15 -r1.16
*** datetime.h 11 Dec 2002 18:54:10 -0000 1.15
--- datetime.h 13 Dec 2002 01:13:46 -0000 1.16
***************
*** 16,21 ****
* 6 second 1 byte, 0-59
* 7 usecond 3 bytes, 0-999999
! * 10 tzoffset 2 bytes, signed, in minutes, -1439 .. 1439
! * 12
*/
--- 16,20 ----
* 6 second 1 byte, 0-59
* 7 usecond 3 bytes, 0-999999
! * 10
*/
***************
*** 47,50 ****
--- 46,57 ----
PyObject_HEAD
long hashcode;
+ unsigned char data[_PyDateTime_DATETIME_DATASIZE];
+ PyObject *tzinfo;
+ } PyDateTime_DateTimeTZ;
+
+ typedef struct
+ {
+ PyObject_HEAD
+ long hashcode;
unsigned char data[_PyDateTime_TIME_DATASIZE];
} PyDateTime_Time;
***************
*** 72,76 ****
} PyDateTime_TZInfo;
! /* Apply for date instances. */
#define PyDateTime_GET_YEAR(o) ((((PyDateTime_Date*)o)->data[0] << 8) | \
((PyDateTime_Date*)o)->data[1])
--- 79,83 ----
} PyDateTime_TZInfo;
! /* Apply for date, datetime, and datetimetz instances. */
#define PyDateTime_GET_YEAR(o) ((((PyDateTime_Date*)o)->data[0] << 8) | \
((PyDateTime_Date*)o)->data[1])
***************
*** 78,82 ****
#define PyDateTime_GET_DAY(o) (((PyDateTime_Date*)o)->data[3])
- /* Apply for datetime and date instances. */
#define PyDateTime_DATE_GET_HOUR(o) (((PyDateTime_DateTime*)o)->data[4])
#define PyDateTime_DATE_GET_MINUTE(o) (((PyDateTime_DateTime*)o)->data[5])
--- 85,88 ----
Index: obj_date.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_date.c,v
retrieving revision 1.48
retrieving revision 1.49
diff -C2 -d -r1.48 -r1.49
*** obj_date.c 12 Dec 2002 18:48:01 -0000 1.48
--- obj_date.c 13 Dec 2002 01:13:46 -0000 1.49
***************
*** 149,173 ****
}
! /* date arithmetic. */
!
! /* Fiddle out-of-bounds months and days so that the result makes some kind
! * of sense. The parameters are both inputs and outputs. Returns < 0 on
! * failure, where failure means the adjusted year is out of bounds.
*/
- static int
- normalize_date(long *year, long *month, long *day)
- {
- int result;
-
- normalize_y_m_d(year, month, day);
- if (MINYEAR <= *year && *year <= MAXYEAR)
- result = 0;
- else {
- PyErr_SetString(PyExc_OverflowError,
- "date value out of range");
- result = -1;
- }
- return result;
- }
/* date + timedelta -> date. If arg negate is true, subtract the timedelta
--- 149,155 ----
}
! /*
! * Date arithmetic.
*/
/* date + timedelta -> date. If arg negate is true, subtract the timedelta
Index: obj_datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_datetime.c,v
retrieving revision 1.46
retrieving revision 1.47
diff -C2 -d -r1.46 -r1.47
*** obj_datetime.c 12 Dec 2002 18:48:01 -0000 1.46
--- obj_datetime.c 13 Dec 2002 01:13:46 -0000 1.47
***************
*** 253,271 ****
/* datetime arithmetic. */
- /* Force all the datetime fields into range. The parameters are both
- * inputs and outputs. Returns < 0 on error.
- */
- static int
- normalize_datetime(long *year, long *month, long *day,
- long *hour, long *minute, long *second,
- long *microsecond)
- {
- normalize_pair(second, microsecond, 1000000);
- normalize_pair(minute, second, 60);
- normalize_pair(hour, minute, 60);
- normalize_pair(day, hour, 24);
- return normalize_date(year, month, day);
- }
-
static PyObject *
add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta)
--- 253,256 ----