[Python-checkins] python/nondist/sandbox/datetime obj_date.c,NONE,1.1 obj_datetime.c,NONE,1.1 obj_delta.c,NONE,1.1 Makefile,1.4,1.5 datetime.c,1.11,1.12 datetime.h,1.4,1.5 setup.py,1.1,1.2 test_cdatetime.py,1.4,1.5
fdrake@users.sourceforge.net
fdrake@users.sourceforge.net
Tue, 20 Aug 2002 11:53:10 -0700
Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory usw-pr-cvs1:/tmp/cvs-serv11723
Modified Files:
Makefile datetime.c datetime.h setup.py test_cdatetime.py
Added Files:
obj_date.c obj_datetime.c obj_delta.c
Log Message:
Many updates to the datetime module:
- now implements both the date and timedelta types
- starts to add the datetime arithmetic support (very partial)
- passes many more tests
The implementation has been split into several files (1 per type); they
will all be merged when the initial implementation is complete, prior to
being merged into Python.
--- NEW FILE: obj_date.c ---
/* imp_date.c
*
* PyDateTime_Date implementation.
*/
static int
normalize_date(long int *year, long int *month, long int *day)
{
long int carry, dim;
/* This is muddy: the proper range for day can't be determined
* without knowing the correct month and year, but if day is,
* e.g., plus or minus a million, the current month and year
* values make no sense (and may also be out of bounds
* themselves). Saying 12 months == 1 year should be
* non-controversial.
*/
if (*month > 12) {
carry = (*month - 1) / 12;
*month -= (carry * 12);
*year += carry;
assert(*month >= 1);
assert(*month <= 12);
}
/* Now only day can be out of bounds (year may also be out of
* bounds for a datetime object, but we don't care about that
* here). If day is out of bounds, what to do is arguable, but at
* least the method here is principled and explainable.
*/
dim = days_in_month(*year, *month);
if (*day < 1 || *day > dim) {
/* Move day-1 days from the first of the month. First try to
* get off cheap if we're only one day out of range
* (adjustments for timezone alone can't be worse than that).
*/
if (*day == 0) {
*month -= 1;
if (*month > 0)
*day = days_in_month(*year, *month);
else {
*year -= 1;
*month = 12;
*day = 31;
}
}
else if (*day == dim + 1) {
/* move forward a day */
*month += 1;
*day = 1;
if (*month > 12) {
*month = 1;
*year += 1;
}
}
else {
long int ordinal = ymd_to_ord(*year, *month, 1) + *day - 1;
ord_to_ymd(ordinal, year, month, day);
}
}
assert(*month > 0);
assert(*day > 0);
if (*year < MINYEAR) {
PyErr_SetString(PyExc_OverflowError, "date value out of range");
return 0;
}
return 1;
}
static PyObject *
datetime_add(PyObject *left, PyObject *right);
static PyObject *
datetime_subtract(PyObject *left, PyObject *right);
/* date(2009, 12, 28) + timedelta(4) == 2010-01-01 (2010, 1, -2)
expected (2009, 53, 5)
*/
static PyObject *
add_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta)
{
PyObject *result;
/* delta + date */
if (GET_TD_SECONDS(delta) != 0
|| GET_TD_MICROSECONDS(delta) != 0) {
/* Convert to datetime and pass it off. */
PyObject *dt = new_datetime(GET_YEAR(date), GET_MONTH(date),
GET_DAY(date), 0, 0, 0, 0);
if (dt == NULL)
return NULL;
result = datetime_add((PyObject *)delta, dt);
Py_DECREF(dt);
}
else if (GET_TD_DAYS(delta) != 0) {
/* There's actually something to do. */
long int year = GET_YEAR(date);
long int month = GET_MONTH(date);
long int day = GET_DAY(date) + GET_TD_DAYS(delta);
if (normalize_date(&year, &month, &day))
result = new_date(year, month, day);
else
result = NULL;
}
else {
/* The delta is timedelta(0), so return the original date. */
Py_INCREF(date);
result = (PyObject *) date;
}
return result;
}
static PyObject *
date_add(PyObject *left, PyObject *right)
{
PyTypeObject *left_type = left->ob_type;
PyTypeObject *right_type = right->ob_type;
if (PyType_IsSubtype(left_type, &PyDateTime_DateTimeType)
|| PyType_IsSubtype(right_type, &PyDateTime_DateTimeType)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
if (PyType_IsSubtype(left_type, &PyDateTime_DateType)) {
/* date + ??? */
if (PyType_IsSubtype(right_type, &PyDateTime_DeltaType))
return add_date_timedelta((PyDateTime_Date *) left,
(PyDateTime_Delta *) right);
}
else {
/* 'right' must be one of us, or we wouldn't have been called */
if (PyType_IsSubtype(left_type, &PyDateTime_DeltaType))
return add_date_timedelta((PyDateTime_Date *) right,
(PyDateTime_Delta *) left);
/* else fall through; we don't support it here */
}
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
static int
date_compare(PyDateTime_Date *self, PyObject *other)
{
if (!PyType_IsSubtype(other->ob_type, &PyDateTime_DateType)) {
PyErr_SetString(PyExc_TypeError,
"can't compare date to %s instance");
return -1;
}
return memcmp(self->data, ((PyDateTime_Date *)other)->data,
_PyDateTime_DATE_DATA_SIZE);
}
static PyObject *
date_ctime(PyDateTime_Date *self)
{
return format_ctime(self, 0, 0, 0);
}
static int
date_hash(PyDateTime_Date *self)
{
if (self->hashcode == -1) {
PyObject *temp = Py_BuildValue("lll", GET_YEAR(self),
GET_MONTH(self), GET_DAY(self));
if (temp != NULL) {
self->hashcode = PyObject_Hash(temp);
Py_DECREF(temp);
}
}
return self->hashcode;
}
static PyObject *
date_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
PyObject *self = NULL;
long int year, month, day;
static char *keywords[] = {
"year", "month", "day", NULL
};
if (PyArg_ParseTupleAndKeywords(args, kw, "lll", keywords,
&year, &month, &day)) {
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;
}
self = new_date(year, month, day);
}
return self;
}
static PyObject *
date_year(PyDateTime_Date *self, void *unused)
{
return (PyInt_FromLong(GET_YEAR(self)));
}
static PyObject *
date_month(PyDateTime_Date *self, void *unused)
{
return (PyInt_FromLong(GET_MONTH(self)));
}
static PyObject *
date_day(PyDateTime_Date *self, void *unused)
{
return (PyInt_FromLong(GET_DAY(self)));
}
static PyGetSetDef date_getset[] = {
{"year", (getter)date_year},
{"month", (getter)date_month},
{"day", (getter)date_day},
{NULL}
};
static PyObject *
date_isocalendar(PyDateTime_Date *self)
{
int year = GET_YEAR(self);
int week1_monday = iso_week1_monday(year);
long today = ymd_to_ord(year, GET_MONTH(self), GET_DAY(self));
int week = (today - week1_monday) / 7;
int day = (today - week1_monday) % 7;
if (week < 0) {
--year;
week1_monday = iso_week1_monday(year);
week = (today - week1_monday) / 7;
day = (today - week1_monday) % 7;
}
else if (week >= 52 &&
today >= iso_week1_monday(year + 1)) {
++year;
week = 0;
}
return Py_BuildValue("iii", year, week + 1, day + 1);
}
static PyObject *
date_isoformat(PyDateTime_Date *self, PyObject *args, PyObject *kw)
{
char buffer[128];
isoformat_date(self, buffer, sizeof(buffer));
return PyString_FromString(buffer);
}
static PyObject *
date_isoweekday(PyDateTime_Date *self)
{
int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
return PyInt_FromLong(dow + 1);
}
static int
date_nonzero(PyDateTime_Date *self)
{
return (GET_YEAR(self) != 0
|| GET_MONTH(self) != 0
|| GET_DAY(self) != 0);
}
static PyObject *
date_repr(PyDateTime_Date *self)
{
char buffer[1028];
char *typename;
typename = self->ob_type->tp_name;
PyOS_snprintf(buffer, sizeof(buffer), "%s(%d, %d, %d)",
typename,
GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
return PyString_FromString(buffer);
}
static PyObject *
date_str(PyDateTime_Date *self)
{
char buffer[128];
isoformat_date(self, buffer, sizeof(buffer));
return PyString_FromString(buffer);
}
static PyObject *
date_subtract(PyObject *left, PyObject *right)
{
PyTypeObject *left_type = left->ob_type;
PyTypeObject *right_type = right->ob_type;
if (PyType_IsSubtype(left_type, &PyDateTime_DateTimeType)
|| PyType_IsSubtype(right_type, &PyDateTime_DateTimeType)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
if (PyType_IsSubtype(left_type, &PyDateTime_DateType)) {
if (PyType_IsSubtype(right_type, &PyDateTime_DateType)) {
/* date - date */
long int left_ord = ymd_to_ord(GET_YEAR(left), GET_MONTH(left),
GET_DAY(left));
long int right_ord = ymd_to_ord(GET_YEAR(right), GET_MONTH(right),
GET_DAY(right));
return new_delta(left_ord - right_ord, 0, 0);
}
if (PyType_IsSubtype(right_type, &PyDateTime_DeltaType)) {
PyObject *result = NULL;
if (GET_TD_SECONDS(right) != 0
|| GET_TD_MICROSECONDS(right) != 0) {
/* need to convert to datetime + delta */
PyObject *dt = new_datetime(GET_YEAR(left), GET_MONTH(left),
GET_DAY(left), 0, 0, 0, 0);
if (dt != NULL) {
result = datetime_subtract(dt, right);
Py_DECREF(dt);
}
}
else if (GET_TD_DAYS(right) == 0) {
/* date - timedelta(0) */
Py_INCREF(left);
result = left;
}
else {
long int year, month, day;
long int ord = ymd_to_ord(GET_YEAR(left), GET_MONTH(left),
GET_DAY(left));
ord -= GET_TD_DAYS(right);
if (ord < 1)
PyErr_SetString(PyExc_OverflowError,
"resulting value out of range");
else {
ord_to_ymd(ord, &year, &month, &day);
result = new_date(year, month, day);
}
}
return result;
}
}
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
static PyObject *
date_today(PyObject *self, PyObject *cls)
{
/* XXX need to create the instance by calling cls(y,mon,d,h,min,s,u) */
struct timeval t;
struct tm *tm;
time_t timet;
#ifdef GETTIMEOFDAY_NO_TZ
gettimeofday(&t);
#else /* !GETTIMEOFDAY_NO_TZ */
gettimeofday(&t, (struct timezone *)NULL);
#endif /* !GETTIMEOFDAY_NO_TZ */
timet = t.tv_sec;
tm = localtime(&timet);
return PyObject_CallFunction(cls, "iii",
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday);
}
static PyObject *
date_toordinal(PyDateTime_Date *self)
{
return PyInt_FromLong(ymd_to_ord(GET_YEAR(self), GET_MONTH(self),
GET_DAY(self)));
}
static PyObject *
date_weekday(PyDateTime_Date *self)
{
int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
return PyInt_FromLong(dow);
}
static PyMethodDef date_methods[] = {
/* Class methods: */
{"today", (PyCFunction)date_today, METH_O | METH_CLASS,
"Return a new date that represents the current date."},
/* Instance methods: */
{"ctime", (PyCFunction)date_ctime, METH_NOARGS,
"Return ctime() style string."},
{"isocalendar", (PyCFunction)date_isocalendar, METH_NOARGS,
"Return a 3-tuple containing ISO year, week number, and weekday.\n\n"
"The first ISO week of the year is the (Mon-Sun) week containing the\n"
"year's first Thursday; everything rest derives from that."},
{"isoformat", (PyCFunction)date_isoformat, METH_KEYWORDS,
"Return the day of the week represented by the date.\n"
"Monday == 1 ... Sunday == 7"},
{"isoweekday", (PyCFunction)date_isoweekday, METH_NOARGS,
"Return the day of the week represented by the date.\n"
"Monday == 1 ... Sunday == 7"},
{"toordinal", (PyCFunction)date_toordinal, METH_NOARGS,
"Return proleptic Gregorian ordinal for the year, month and day.\n"
"January 1 of year 1 is day 1."},
{"weekday", (PyCFunction)date_weekday, METH_NOARGS,
"Return the day of the week represented by the date.\n"
"Monday == 0 ... Sunday == 6"},
{NULL}
};
static char date_doc[] =
"Basic date type.";
static PyNumberMethods date_as_number = {
date_add, /* nb_add */
date_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 */
(inquiry)date_nonzero, /* nb_nonzero */
};
static PyTypeObject PyDateTime_DateType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"date", /* tp_name */
sizeof(PyDateTime_Date), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)PyObject_Del, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)date_compare, /* tp_compare */
(reprfunc)date_repr, /* tp_repr */
&date_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)date_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)date_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 */
date_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
date_methods, /* tp_methods */
0, /* tp_members */
date_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
date_new, /* tp_new */
_PyObject_Del, /* tp_free */
};
--- NEW FILE: obj_datetime.c ---
/* imp_datetime.c
*
* PyDateTime_DateTime implementation.
*/
static void
normalize_pair(long int *parent, long int *child, int size)
{
if (*child < 0) {
long int borrow = (*child / size) + 1;
*parent -= borrow;
*child += (borrow * size);
}
else if (*child >= size) {
long int carry = *child / size;
*parent += carry;
*child -= (carry * size);
}
}
static int
normalize_datetime(long int *year, long int *month, long int *day,
long int *hour, long int *minute, long int *second,
long int *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)
{
long int year = GET_YEAR(date);
long int month = GET_MONTH(date);
long int day = GET_DAY(date) + GET_TD_DAYS(delta);
long int hour = GET_HOUR(date);
long int minute = GET_MINUTE(date);
long int second = GET_SECOND(date) + GET_TD_SECONDS(delta);
long int microsecond = GET_MICROSECOND(date) + GET_TD_MICROSECONDS(delta);
if (normalize_datetime(&year, &month, &day,
&hour, &minute, &second, µsecond))
return new_datetime(year, month, day,
hour, minute, second, microsecond);
else
return NULL;
}
static PyObject *
datetime_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))
return add_datetime_timedelta((PyDateTime_DateTime *) left,
(PyDateTime_Delta *) right);
}
else if (PyType_IsSubtype(left_type, &PyDateTime_DeltaType)) {
/* delta + datetime */
return add_datetime_timedelta((PyDateTime_DateTime *) right,
(PyDateTime_Delta *) left);
}
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
static int
datetime_compare(PyDateTime_DateTime *self, PyObject *other)
{
if (!PyType_IsSubtype(other->ob_type, &PyDateTime_DateTimeType)) {
PyErr_SetString(PyExc_TypeError,
"can't compare date to %s instance");
return -1;
}
return memcmp(self->data, ((PyDateTime_DateTime *)other)->data,
_PyDateTime_DATETIME_DATA_SIZE);
}
static PyObject *
datetime_ctime(PyDateTime_DateTime *self)
{
return format_ctime((PyDateTime_Date *)self,
GET_HOUR(self), GET_MINUTE(self), GET_SECOND(self));
}
static int
datetime_hash(PyDateTime_DateTime *self)
{
if (self->hashcode == -1) {
PyObject *temp;
if (GET_MICROSECOND(self) != 0)
temp = Py_BuildValue("lllllll", GET_YEAR(self),
GET_MONTH(self), GET_DAY(self),
GET_HOUR(self), GET_MINUTE(self),
GET_SECOND(self), GET_MICROSECOND(self));
else if (GET_SECOND(self) != 0)
temp = Py_BuildValue("llllll", GET_YEAR(self),
GET_MONTH(self), GET_DAY(self),
GET_HOUR(self), GET_MINUTE(self),
GET_SECOND(self));
else if (GET_MINUTE(self) != 0)
temp = Py_BuildValue("lllll", GET_YEAR(self),
GET_MONTH(self), GET_DAY(self),
GET_HOUR(self), GET_MINUTE(self));
else if (GET_HOUR(self) != 0)
temp = Py_BuildValue("llll", GET_YEAR(self),
GET_MONTH(self), GET_DAY(self),
GET_HOUR(self));
else
temp = Py_BuildValue("lll", GET_YEAR(self),
GET_MONTH(self), GET_DAY(self));
if (temp != NULL) {
self->hashcode = PyObject_Hash(temp);
Py_DECREF(temp);
}
}
return self->hashcode;
}
static PyObject *
datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
PyObject *self = NULL;
long int year, month, day, hour = 0, minute = 0, second = 0, 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;
}
static PyObject *
datetime_repr(PyDateTime_DateTime *self)
{
char buffer[1028];
char *typename;
typename = self->ob_type->tp_name;
if (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),
GET_HOUR(self), GET_MINUTE(self), GET_SECOND(self),
GET_MICROSECOND(self));
}
else if (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),
GET_HOUR(self), GET_MINUTE(self), 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),
GET_HOUR(self), GET_MINUTE(self));
}
return PyString_FromString(buffer);
}
static PyObject *
datetime_str(PyDateTime_DateTime *self)
{
char buffer[128];
char *cp;
cp = isoformat_date((PyDateTime_Date *)self, buffer, sizeof(buffer));
*cp++ = ' ';
isoformat_time(self, cp, sizeof(buffer) - (cp - buffer));
return PyString_FromString(buffer);
}
static PyObject *
datetime_subtract(PyObject *left, PyObject *right)
{
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
static PyObject *
datetime_hour(PyDateTime_DateTime *self, void *unused)
{
return (PyInt_FromLong(GET_HOUR(self)));
}
static PyObject *
datetime_minute(PyDateTime_DateTime *self, void *unused)
{
return (PyInt_FromLong(GET_MINUTE(self)));
}
static PyObject *
datetime_second(PyDateTime_DateTime *self, void *unused)
{
return (PyInt_FromLong(GET_SECOND(self)));
}
static PyObject *
datetime_microsecond(PyDateTime_DateTime *self, void *unused)
{
return (PyInt_FromLong(GET_MICROSECOND(self)));
}
static PyGetSetDef datetime_getset[] = {
{"hour", (getter)datetime_hour},
{"minute", (getter)datetime_minute},
{"second", (getter)datetime_second},
{"microsecond", (getter)datetime_microsecond},
{NULL}
};
static PyObject *
datetime_isoformat(PyDateTime_DateTime *self,
PyObject *args, PyObject *kw)
{
char buffer[128];
char sep = 'T';
char *cp;
static char *keywords[] = {"sep", NULL};
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(self, cp, sizeof(buffer) - (cp - buffer));
return PyString_FromString(buffer);
}
static int
datetime_nonzero(PyDateTime_DateTime *self)
{
return (GET_MICROSECOND(self) != 0
|| GET_SECOND(self) != 0
|| GET_MINUTE(self) != 0
|| GET_HOUR(self) != 0
|| date_nonzero((PyDateTime_Date *) self) != 0);
}
static PyObject *
datetime_now(PyObject *self, PyObject *cls)
{
/* XXX need to create the instance by calling cls(y,mon,d,h,min,s,u) */
struct timeval t;
struct tm *tm;
time_t timet;
#ifdef GETTIMEOFDAY_NO_TZ
gettimeofday(&t);
#else /* !GETTIMEOFDAY_NO_TZ */
gettimeofday(&t, (struct timezone *)NULL);
#endif /* !GETTIMEOFDAY_NO_TZ */
timet = t.tv_sec;
tm = localtime(&timet);
return PyObject_CallFunction(cls, "iiiiiil",
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, tm->tm_hour, tm->tm_min,
tm->tm_sec, t.tv_usec);
}
static PyObject *
datetime_today(PyObject *self, PyObject *cls)
{
/* XXX need to create the instance by calling cls(y,mon,d,h,min,s,u) */
struct timeval t;
struct tm *tm;
time_t timet;
#ifdef GETTIMEOFDAY_NO_TZ
gettimeofday(&t);
#else /* !GETTIMEOFDAY_NO_TZ */
gettimeofday(&t, (struct timezone *)NULL);
#endif /* !GETTIMEOFDAY_NO_TZ */
timet = t.tv_sec;
tm = localtime(&timet);
return PyObject_CallFunction(cls, "iiiiiil",
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, 0, 0, 0, 0);
}
static PyMethodDef datetime_methods[] = {
/* Class methods: */
{"now", (PyCFunction)datetime_now, METH_O | METH_CLASS,
"Return a new datetime that represents the current time."},
{"today", (PyCFunction)datetime_today, METH_O | METH_CLASS,
"Return a new datetime that represents the current date."},
/* Instance methods: */
{"ctime", (PyCFunction)datetime_ctime, METH_NOARGS,
"Return ctime() style string."},
{"isoformat", (PyCFunction)datetime_isoformat, METH_KEYWORDS,
"Return the day of the week represented by the datetime.\n"
"Monday == 1 ... Sunday == 7"},
{NULL}
};
static char datetime_doc[] =
"Basic date/time type.";
static PyNumberMethods datetime_as_number = {
datetime_add, /* nb_add */
datetime_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 */
(inquiry)datetime_nonzero, /* nb_nonzero */
};
statichere PyTypeObject PyDateTime_DateTimeType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"datetime", /* tp_name */
sizeof(PyDateTime_DateTime), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)PyObject_Del, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)datetime_compare, /* tp_compare */
(reprfunc)datetime_repr, /* tp_repr */
&datetime_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)datetime_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)datetime_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 */
datetime_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
datetime_methods, /* tp_methods */
0, /* tp_members */
datetime_getset, /* tp_getset */
&PyDateTime_DateType, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
datetime_new, /* tp_new */
_PyObject_Del, /* tp_free */
};
--- NEW FILE: obj_delta.c ---
/* imp_delta.c
*
* PyDateTime_Delta implementation.
*/
static PyObject *
delta_add(PyObject *left, PyObject *right)
{
PyTypeObject *left_type = left->ob_type;
PyTypeObject *right_type = right->ob_type;
PyDateTime_Delta *delta;
PyObject *other;
PyTypeObject *other_type;
if (PyType_IsSubtype(left_type, &PyDateTime_DeltaType)) {
/* delta + ??? */
delta = (PyDateTime_Delta *) left;
if (PyType_IsSubtype(right_type, &PyDateTime_DeltaType)) {
/* delta + delta */
long int days = GET_TD_DAYS(delta) + GET_TD_DAYS(right);
long int seconds = GET_TD_SECONDS(delta) + GET_TD_SECONDS(right);
long int microseconds = (GET_TD_MICROSECONDS(delta)
+ GET_TD_MICROSECONDS(right));
return new_delta(days, seconds, microseconds);
}
other = right;
other_type = right_type;
}
else {
/* !delta + delta */
delta = (PyDateTime_Delta *) right;
other = left;
other_type = left_type;
}
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
static int
delta_compare(PyDateTime_Delta *self, PyObject *other)
{
int result = -1;
if (!PyObject_TypeCheck(other, &PyDateTime_DeltaType))
PyErr_Format(PyExc_TypeError,
"can't compare %s to %s instance",
self->ob_type->tp_name, other->ob_type->tp_name);
else {
long diff = GET_TD_DAYS(self) - GET_TD_DAYS(other);
if (diff == 0) {
diff = GET_TD_SECONDS(self) - GET_TD_SECONDS(other);
if (diff == 0)
diff = GET_TD_MICROSECONDS(self) - GET_TD_MICROSECONDS(other);
}
if (diff == 0)
result = 0;
else if (diff > 0)
result = 1;
}
return result;
}
static int
delta_hash(PyDateTime_Delta *self)
{
return -2;
}
static PyObject *
multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta)
{
long i = PyInt_AS_LONG(intobj);
return new_delta(GET_TD_DAYS(delta) * i,
GET_TD_SECONDS(delta) * i,
GET_TD_MICROSECONDS(delta) * i);
}
static PyObject *
delta_multiply(PyObject *left, PyObject *right)
{
PyObject *result = NULL;
if (PyType_IsSubtype(left->ob_type, &PyDateTime_DeltaType)) {
/* delta * ??? */
if (PyInt_Check(right))
result = multiply_int_timedelta(right, (PyDateTime_Delta *) left);
else {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
}
else if (PyInt_Check(left))
result = multiply_int_timedelta(left, (PyDateTime_Delta *) right);
else {
/* !(delta | int) * delta */
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
return result;
}
static PyObject *
delta_negative(PyDateTime_Delta *self)
{
return new_delta(-GET_TD_DAYS(self),
-GET_TD_SECONDS(self),
-GET_TD_MICROSECONDS(self));
}
static PyObject *
delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
PyObject *self = NULL;
long int days, seconds = 0, microseconds = 0;
static char *keywords[] = {
"days", "seconds", "microseconds", NULL
};
if (PyArg_ParseTupleAndKeywords(args, kw, "l|ll:__new__", keywords,
&days, &seconds, µseconds)) {
if (seconds < 0 || seconds >= (24 * 3600)) {
PyErr_SetString(PyExc_ValueError,
"seconds must be in 0..86399");
return NULL;
}
if (microseconds < 0 || microseconds >= 1000000) {
PyErr_SetString(PyExc_ValueError,
"microseconds must be in 0..999999");
return NULL;
}
self = new_delta(days, seconds, microseconds);
}
return self;
}
static PyObject *
delta_subtract(PyObject *left, PyObject *right)
{
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
static int
delta_nonzero(PyDateTime_Delta *self)
{
return (GET_TD_DAYS(self) != 0
|| GET_TD_SECONDS(self) != 0
|| GET_TD_MICROSECONDS(self) != 0);
}
static PyObject *
delta_repr(PyDateTime_Delta *self)
{
if (GET_TD_MICROSECONDS(self) != 0)
return PyString_FromFormat("%s(%ld, %ld, %ld)",
self->ob_type->tp_name,
GET_TD_DAYS(self),
GET_TD_SECONDS(self),
GET_TD_MICROSECONDS(self));
if (GET_TD_SECONDS(self) != 0)
return PyString_FromFormat("%s(%ld, %ld)",
self->ob_type->tp_name,
GET_TD_DAYS(self),
GET_TD_SECONDS(self));
return PyString_FromFormat("%s(%ld)",
self->ob_type->tp_name,
GET_TD_DAYS(self));
}
#define OFFSET(field) offsetof(PyDateTime_Delta, field)
static PyMemberDef delta_members[] = {
{"days", T_LONG, OFFSET(days), READONLY,
"Number os days."},
{"seconds", T_LONG, OFFSET(seconds), READONLY,
"Number of seconds (less than 1 day)."},
{"microseconds", T_LONG, OFFSET(microseconds), READONLY,
"Number of microseconds (less than 1 second)."},
{NULL}
};
static char delta_doc[] =
"Difference between two datetime values.";
static PyNumberMethods delta_as_number = {
delta_add, /* nb_add */
delta_subtract, /* nb_subtract */
delta_multiply, /* nb_multiply */
0, /* nb_divide */
0, /* nb_remainder */
0, /* nb_divmod */
0, /* nb_power */
(unaryfunc)delta_negative, /* nb_negative */
0, /* nb_positive */
0, /* nb_absolute */
(inquiry)delta_nonzero, /* nb_nonzero */
};
static PyTypeObject PyDateTime_DeltaType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"timedelta", /* tp_name */
sizeof(PyDateTime_Delta), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)delta_compare, /* tp_compare */
(reprfunc)delta_repr, /* tp_repr */
&delta_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)delta_hash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
delta_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
delta_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
delta_new, /* tp_new */
_PyObject_Del, /* tp_free */
};
Index: Makefile
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/Makefile,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** Makefile 28 Mar 2002 21:17:47 -0000 1.4
--- Makefile 20 Aug 2002 18:53:07 -0000 1.5
***************
*** 1,3 ****
! PYTHON=python2.3
default: check
--- 1,4 ----
! #PYTHON=python2.3
! PYTHON=../../../trunk/debug/python
default: check
Index: datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -C2 -d -r1.11 -r1.12
*** datetime.c 28 Mar 2002 21:17:47 -0000 1.11
--- datetime.c 20 Aug 2002 18:53:07 -0000 1.12
***************
*** 5,8 ****
--- 5,9 ----
#include "Python.h"
#include "modsupport.h"
+ #include "structmember.h"
#include <time.h>
***************
*** 13,38 ****
#define MAXYEAR 9999
/* Rename the long macros in datetime.h to more reasonable short names. */
! #define GET_YEAR(o) PyDateTime_GET_YEAR(o)
! #define GET_MONTH(o) PyDateTime_GET_MONTH(o)
! #define GET_DAY(o) PyDateTime_GET_DAY(o)
! #define GET_HOUR(o) PyDateTime_GET_HOUR(o)
! #define GET_MINUTE(o) PyDateTime_GET_MINUTE(o)
! #define GET_SECOND(o) PyDateTime_GET_SECOND(o)
! #define GET_MICROSECOND(o) PyDateTime_GET_MICROSECOND(o)
! /* Set accessors. */
! #define SET_YEAR(o, v) (((o)->data[0] = ((v) & 0xff00) >> 8), \
! ((o)->data[1] = ((v) & 0x00ff)))
! #define SET_MONTH(o, v) (PyDateTime_GET_MONTH(o) = (v))
! #define SET_DAY(o, v) (PyDateTime_GET_DAY(o) = (v))
! #define SET_HOUR(o, v) (PyDateTime_GET_HOUR(o) = (v))
! #define SET_MINUTE(o, v) (PyDateTime_GET_MINUTE(o) = (v))
! #define SET_SECOND(o, v) (PyDateTime_GET_SECOND(o) = (v))
! #define SET_MICROSECOND(o, v) (((o)->data[7] = ((v) & 0xff0000) >> 16), \
! ((o)->data[8] = ((v) & 0x00ff00) >> 8), \
! ((o)->data[9] = ((v) & 0x0000ff)))
! staticforward PyTypeObject PyDateTime_Type;
/*
--- 14,60 ----
#define MAXYEAR 9999
+ typedef struct
+ {
+ PyObject_HEAD
+ int hashcode;
+ long int days;
+ long int seconds;
+ long int microseconds;
+ } PyDateTime_Delta;
+
/* Rename the long macros in datetime.h to more reasonable short names. */
! #define GET_YEAR(o) PyDateTime_GET_YEAR(o)
! #define GET_MONTH(o) PyDateTime_GET_MONTH(o)
! #define GET_DAY(o) PyDateTime_GET_DAY(o)
! #define GET_HOUR(o) PyDateTime_GET_HOUR(o)
! #define GET_MINUTE(o) PyDateTime_GET_MINUTE(o)
! #define GET_SECOND(o) PyDateTime_GET_SECOND(o)
! #define GET_MICROSECOND(o) PyDateTime_GET_MICROSECOND(o)
! /* Date accessors. */
! #define SET_YEAR(o, v) (((o)->data[0] = ((v) & 0xff00) >> 8), \
! ((o)->data[1] = ((v) & 0x00ff)))
! #define SET_MONTH(o, v) (PyDateTime_GET_MONTH(o) = (v))
! #define SET_DAY(o, v) (PyDateTime_GET_DAY(o) = (v))
! /* Date/Time accessors. */
! #define SET_HOUR(o, v) (PyDateTime_GET_HOUR(o) = (v))
! #define SET_MINUTE(o, v) (PyDateTime_GET_MINUTE(o) = (v))
! #define SET_SECOND(o, v) (PyDateTime_GET_SECOND(o) = (v))
! #define SET_MICROSECOND(o, v) (((o)->data[7] = ((v) & 0xff0000) >> 16), \
! ((o)->data[8] = ((v) & 0x00ff00) >> 8), \
! ((o)->data[9] = ((v) & 0x0000ff)))
!
! /* Delta accessors. */
! #define GET_TD_DAYS(o) (((PyDateTime_Delta *)(o))->days)
! #define GET_TD_SECONDS(o) (((PyDateTime_Delta *)(o))->seconds)
! #define GET_TD_MICROSECONDS(o) (((PyDateTime_Delta *)(o))->microseconds)
!
! #define SET_TD_DAYS(o, v) ((o)->days = (v))
! #define SET_TD_SECONDS(o, v) ((o)->seconds = (v))
! #define SET_TD_MICROSECONDS(o, v) ((o)->microseconds = (v))
!
! static PyTypeObject PyDateTime_DateType;
! static PyTypeObject PyDateTime_DateTimeType;
/*
***************
*** 43,47 ****
is_leap(int year)
{
! return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
}
--- 65,69 ----
is_leap(int year)
{
! return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 1 : 0;
}
***************
*** 88,91 ****
--- 110,163 ----
}
+ /* ordinal -> year, month, day, considering 01-Jan-0001 as day 1. */
+ static void
+ ord_to_ymd(long int ordinal, long int *year, long int *month, long int *day)
+ {
+ int di400y = days_before_year(401);
+ int di100y = days_before_year(101);
+ int di4y = days_before_year(5);
+ int n, n1, n4, n100, n400, leapyear, preceding;
+
+ assert(ordinal >= 1);
+ --ordinal;
+ n400 = ordinal / di400y;
+ n = ordinal % di400y;
+ *year = n400 * 400 + 1;
+
+ n100 = n / di100y;
+ n = n % di100y;
+
+ n4 = n / di4y;
+ n = n % di4y;
+
+ n1 = n / 365;
+ n = n % 365;
+
+ *year += n100 * 100 + n4 * 4 + n1;
+ if (n1 == 4 || n100 == 4) {
+ assert(n == 0);
+ *year -= 1;
+ *month = 12;
+ *day = 31;
+ return;
+ }
+ leapyear = (n1 == 3 && (n4 != 24 || n100 == 3)) ? 1 : 0;
+ assert(leapyear == is_leap(*year));
+ *month = (n + 50) >> 5;
+ preceding = (_days_before_month[*month]
+ + ((*month > 2 && leapyear) ? 1 : 0));
+ if (preceding > n) {
+ /* estimate is too large */
+ *month -= 1;
+ preceding -= days_in_month(*year, *month);
+ }
+ n -= preceding;
+ assert(0 <= n);
+ assert(n < days_in_month(*year, *month));
+
+ *day = n + 1;
+ }
+
+ /* year, month, day -> ordinal, considering 01-Jan-0001 as day 1. */
static long
ymd_to_ord(int year, int month, int day)
***************
*** 114,187 ****
}
! /*
! * PyDateTime_Object implementation
! */
! static int
! datetime_compare(PyDateTime_Object *self, PyObject *other)
! {
! if (!PyType_IsSubtype(other->ob_type, &PyDateTime_Type)) {
! PyErr_SetString(PyExc_TypeError,
! "can't compare date to %s instance");
! return -1;
! }
! return memcmp(self->data, ((PyDateTime_Object *)other)->data,
! _PyDateTime_DATA_SIZE);
}
! static PyObject *
! datetime_repr(PyDateTime_Object *self)
{
! char buffer[1028];
! char *typename;
!
! typename = self->ob_type->tp_name;
! if (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),
! GET_HOUR(self), GET_MINUTE(self), GET_SECOND(self),
! GET_MICROSECOND(self));
! }
! else if (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),
! GET_HOUR(self), GET_MINUTE(self), 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),
! GET_HOUR(self), GET_MINUTE(self));
! }
! return PyString_FromString(buffer);
}
static void
! isoformat(PyDateTime_Object *dt, char sep, char buffer[], int bufflen)
{
PyOS_snprintf(buffer, bufflen,
! "%04d-%02d-%02d%c%02d:%02d:%02d.%06d",
! GET_YEAR(dt), GET_MONTH(dt), GET_DAY(dt),
! sep,
GET_HOUR(dt), GET_MINUTE(dt), GET_SECOND(dt),
GET_MICROSECOND(dt));
}
static PyObject *
! datetime_str(PyDateTime_Object *self)
{
! char buffer[128];
! isoformat(self, ' ', buffer, sizeof(buffer));
!
! return PyString_FromString(buffer);
! }
! static int
! datetime_hash(PyDateTime_Object *self)
! {
! return -2;
}
--- 186,245 ----
}
+ static PyObject *
+ format_ctime(PyDateTime_Date *date,
+ int hours, int minutes, int seconds)
+ {
+ static char *DayNames[] = {
+ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
+ };
+ static char *MonthNames[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
! char buffer[128];
! int wday = weekday(GET_YEAR(date), GET_MONTH(date), GET_DAY(date));
! PyOS_snprintf(buffer, sizeof(buffer), "%s %s %2d %02d:%02d:%02d %04d",
! DayNames[wday], MonthNames[GET_MONTH(date) - 1],
! GET_DAY(date), hours, minutes, seconds,
! GET_YEAR(date));
! return PyString_FromString(buffer);
}
! static char *
! isoformat_date(PyDateTime_Date *dt, char buffer[], int bufflen)
{
! int x;
! x = PyOS_snprintf(buffer, bufflen,
! "%04d-%02d-%02d",
! GET_YEAR(dt), GET_MONTH(dt), GET_DAY(dt));
! return buffer + x;
}
static void
! isoformat_time(PyDateTime_DateTime *dt, char buffer[], int bufflen)
{
PyOS_snprintf(buffer, bufflen,
! "%02d:%02d:%02d.%06d",
GET_HOUR(dt), GET_MINUTE(dt), GET_SECOND(dt),
GET_MICROSECOND(dt));
}
+
+ /* Create a date instance with no range checking. */
static PyObject *
! new_date(int year, int month, int day)
{
! PyDateTime_Date *self;
! 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;
}
***************
*** 191,198 ****
int second, int usecond)
{
! PyDateTime_Object *self;
! self = PyObject_New(PyDateTime_Object, &PyDateTime_Type);
if (self != NULL) {
SET_YEAR(self, year);
SET_MONTH(self, month);
--- 249,257 ----
int second, int usecond)
{
! PyDateTime_DateTime *self;
! self = PyObject_New(PyDateTime_DateTime, &PyDateTime_DateTimeType);
if (self != NULL) {
+ self->hashcode = -1;
SET_YEAR(self, year);
SET_MONTH(self, month);
***************
*** 207,463 ****
static PyObject *
! datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
! PyObject *self = NULL;
! long int year, month, day, hour = 0, minute = 0, second = 0, 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;
! }
!
!
! static PyObject *
! datetime_year(PyDateTime_Object *self, void *unused)
! {
! return (PyInt_FromLong(GET_YEAR(self)));
! }
!
! static PyObject *
! datetime_month(PyDateTime_Object *self, void *unused)
! {
! return (PyInt_FromLong(GET_MONTH(self)));
! }
!
! static PyObject *
! datetime_day(PyDateTime_Object *self, void *unused)
! {
! return (PyInt_FromLong(GET_DAY(self)));
! }
!
! static PyObject *
! datetime_hour(PyDateTime_Object *self, void *unused)
! {
! return (PyInt_FromLong(GET_HOUR(self)));
! }
!
! static PyObject *
! datetime_minute(PyDateTime_Object *self, void *unused)
! {
! return (PyInt_FromLong(GET_MINUTE(self)));
! }
!
! static PyObject *
! datetime_second(PyDateTime_Object *self, void *unused)
! {
! return (PyInt_FromLong(GET_SECOND(self)));
! }
!
! static PyObject *
! datetime_microsecond(PyDateTime_Object *self, void *unused)
! {
! return (PyInt_FromLong(GET_MICROSECOND(self)));
! }
!
! static PyGetSetDef datetime_getset[] = {
! {"year",(getter)datetime_year},
! {"month", (getter)datetime_month},
! {"day", (getter)datetime_day},
! {"hour", (getter)datetime_hour},
! {"minute", (getter)datetime_minute},
! {"second", (getter)datetime_second},
! {"microsecond", (getter)datetime_microsecond},
! {NULL}
! };
!
! static PyObject *
! datetime_isocalendar(PyDateTime_Object *self)
! {
! int year = GET_YEAR(self);
! int week1_monday = iso_week1_monday(year);
! long today = ymd_to_ord(year, GET_MONTH(self), GET_DAY(self));
! int week = (today - week1_monday) / 7;
! int day = (today - week1_monday) % 7;
!
! if (week < 0) {
! --year;
! week1_monday = iso_week1_monday(year);
! week = (today - week1_monday) / 7;
! day = (today - week1_monday) % 7;
}
! else if (week >= 52 &&
! today >= iso_week1_monday(year + 1)) {
! ++year;
! week = 0;
}
! return Py_BuildValue("iii", year, week + 1, day + 1);
! }
!
! static PyObject *
! datetime_isoformat(PyDateTime_Object *self, PyObject *args, PyObject *kw)
! {
! char buffer[128];
! char sep = 'T';
!
! static char *keywords[] = {"sep", NULL};
!
! if (!PyArg_ParseTupleAndKeywords(args, kw, "|c:isoformat", keywords, &sep))
! return NULL;
! isoformat(self, sep, buffer, sizeof(buffer));
!
! return PyString_FromString(buffer);
! }
!
! static PyObject *
! datetime_isoweekday(PyDateTime_Object *self)
! {
! int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
!
! return PyInt_FromLong(dow + 1);
! }
!
! static PyObject *
! datetime_weekday(PyDateTime_Object *self)
! {
! int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
!
! return PyInt_FromLong(dow);
! }
!
! static PyObject *
! datetime_now(PyObject *self, PyObject *cls)
! {
! /* XXX need to create the instance by calling cls(y,mon,d,h,min,s,u) */
! struct timeval t;
! struct tm *tm;
! time_t timet;
!
! #ifdef GETTIMEOFDAY_NO_TZ
! gettimeofday(&t);
! #else /* !GETTIMEOFDAY_NO_TZ */
! gettimeofday(&t, (struct timezone *)NULL);
! #endif /* !GETTIMEOFDAY_NO_TZ */
! timet = t.tv_sec;
! tm = localtime(&timet);
!
! return PyObject_CallFunction(cls, "iiiiiil",
! tm->tm_year + 1900, tm->tm_mon + 1,
! tm->tm_mday, tm->tm_hour, tm->tm_min,
! tm->tm_sec, t.tv_usec);
}
! static PyMethodDef datetime_methods[] = {
! /* Class methods: */
! {"now", (PyCFunction)datetime_now, METH_O | METH_CLASS,
! "Return a new datetime that represents the current time."},
!
! /* Instance methods: */
! {"isocalendar", (PyCFunction)datetime_isocalendar, METH_NOARGS,
! "Return a 3-tuple containing ISO year, week number, and weekday.\n\n"
! "The first ISO week of the year is the (Mon-Sun) week containing the\n"
! "year's first Thursday; everything rest derives from that."},
! {"isoformat", (PyCFunction)datetime_isoformat, METH_VARARGS|METH_KEYWORDS,
! "Return the day of the week represented by the datetime.\n"
! "Monday == 1 ... Sunday == 7"},
! {"isoweekday", (PyCFunction)datetime_isoweekday, METH_NOARGS,
! "Return the day of the week represented by the datetime.\n"
! "Monday == 1 ... Sunday == 7"},
! {"weekday", (PyCFunction)datetime_weekday, METH_NOARGS,
! "Return the day of the week represented by the datetime.\n"
! "Monday == 0 ... Sunday == 6"},
! {NULL}
! };
!
!
! static char datetime_doc[] =
! "Basic date/time type.";
!
!
! statichere PyTypeObject PyDateTime_Type = {
! PyObject_HEAD_INIT(NULL)
! 0, /* ob_size */
! "datetime", /* tp_name */
! sizeof(PyDateTime_Object), /* tp_basicsize */
! 0, /* tp_itemsize */
! _PyObject_Del, /* tp_dealloc */
! 0, /* tp_print */
! 0, /* tp_getattr */
! 0, /* tp_setattr */
! (cmpfunc)datetime_compare, /* tp_compare */
! (reprfunc)datetime_repr, /* tp_repr */
! 0, /* tp_as_number */
! 0, /* tp_as_sequence */
! 0, /* tp_as_mapping */
! (hashfunc)datetime_hash, /* tp_hash */
! 0, /* tp_call */
! (reprfunc)datetime_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 */
! datetime_doc, /* tp_doc */
! 0, /* tp_traverse */
! 0, /* tp_clear */
! 0, /* tp_richcompare */
! 0, /* tp_weaklistoffset */
! 0, /* tp_iter */
! 0, /* tp_iternext */
! datetime_methods, /* tp_methods */
! 0, /* tp_members */
! datetime_getset, /* tp_getset */
! 0, /* tp_base */
! 0, /* tp_dict */
! 0, /* tp_descr_get */
! 0, /* tp_descr_set */
! 0, /* tp_dictoffset */
! 0, /* tp_init */
! 0, /* tp_alloc */
! datetime_new, /* tp_new */
! _PyObject_Del, /* tp_free */
! };
!
!
! static
! PyMethodDef functions[] = {
! {NULL, NULL, 0, NULL}
! };
!
void
--- 266,294 ----
static PyObject *
! new_delta(long int days, long int seconds, long int microseconds)
{
! PyDateTime_Delta *self;
! if (microseconds >= 1000000 || microseconds <= -1000000) {
! seconds += microseconds / 1000000;
! microseconds %= 1000000;
}
! if (seconds >= 24*3600 || seconds <= 24*3600) {
! days += seconds / (24*3600);
! seconds %= (24*3600);
}
! self = PyObject_New(PyDateTime_Delta, &PyDateTime_DeltaType);
! if (self != NULL) {
! self->hashcode = -1;
! SET_TD_DAYS(self, days);
! SET_TD_SECONDS(self, seconds);
! SET_TD_MICROSECONDS(self, microseconds);
}
! return (PyObject *) self;
}
! #include "obj_delta.c"
! #include "obj_date.c"
! #include "obj_datetime.c"
void
***************
*** 466,477 ****
PyObject *m;
PyObject *d, *dt;
- int err;
! PyDateTime_Type.ob_type = &PyType_Type;
! if (PyType_Ready(&PyDateTime_Type) < 0)
return;
! d = PyDateTime_Type.tp_dict;
dt = new_datetime(1, 1, 1, 0, 0, 0, 0);
if (dt == NULL || PyDict_SetItemString(d, "min", dt) < 0)
--- 297,325 ----
PyObject *m;
PyObject *d, *dt;
! if (PyType_Ready(&PyDateTime_DateType) < 0)
! return;
! if (PyType_Ready(&PyDateTime_DateTimeType) < 0)
! return;
! if (PyType_Ready(&PyDateTime_DeltaType) < 0)
! return;
! /* date values */
! d = PyDateTime_DateType.tp_dict;
! dt = new_date(1, 1, 1);
! if (dt == NULL || PyDict_SetItemString(d, "min", dt) < 0)
! return;
! Py_DECREF(dt);
! dt = new_date(MAXYEAR, 12, 31);
! if (dt == NULL || PyDict_SetItemString(d, "max", dt) < 0)
! return;
! Py_DECREF(dt);
! dt = new_delta(1, 0, 0);
! if (dt == NULL || PyDict_SetItemString(d, "resolution", dt) < 0)
return;
+ Py_DECREF(dt);
! /* date/time values */
! d = PyDateTime_DateTimeType.tp_dict;
dt = new_datetime(1, 1, 1, 0, 0, 0, 0);
if (dt == NULL || PyDict_SetItemString(d, "min", dt) < 0)
***************
*** 482,491 ****
return;
Py_DECREF(dt);
! m = Py_InitModule3("_datetime", functions,
"Fast implementation of the datetime type.");
PyModule_AddIntConstant(m, "MINYEAR", 1);
! PyModule_AddIntConstant(m, "MAXYEAR", 9999);
! Py_INCREF(&PyDateTime_Type);
! PyModule_AddObject(m, "datetime", (PyObject *) &PyDateTime_Type);
}
--- 330,348 ----
return;
Py_DECREF(dt);
+ dt = new_delta(0, 0, 1);
+ if (dt == NULL || PyDict_SetItemString(d, "resolution", dt) < 0)
+ return;
+ Py_DECREF(dt);
! /* module initialization */
! m = Py_InitModule3("_datetime", NULL,
"Fast implementation of the datetime type.");
PyModule_AddIntConstant(m, "MINYEAR", 1);
! PyModule_AddIntConstant(m, "MAXYEAR", MAXYEAR);
! Py_INCREF(&PyDateTime_DateType);
! PyModule_AddObject(m, "date", (PyObject *) &PyDateTime_DateType);
! Py_INCREF(&PyDateTime_DateTimeType);
! PyModule_AddObject(m, "datetime", (PyObject *) &PyDateTime_DateTimeType);
! Py_INCREF(&PyDateTime_DeltaType);
! PyModule_AddObject(m, "timedelta", (PyObject *) &PyDateTime_DeltaType);
}
Index: datetime.h
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** datetime.h 12 Mar 2002 22:33:51 -0000 1.4
--- datetime.h 20 Aug 2002 18:53:07 -0000 1.5
***************
*** 5,27 ****
#define DATETIME_H
! #define _PyDateTime_DATA_SIZE 10
typedef struct
{
PyObject_HEAD
! unsigned char data[_PyDateTime_DATA_SIZE];
! } PyDateTime_Object;
! #define PyDateTime_GET_YEAR(o) (((PyDateTime_Object*)o)->data[0] << 8 \
! | ((PyDateTime_Object*)o)->data[1])
! #define PyDateTime_GET_MONTH(o) (((PyDateTime_Object*)o)->data[2])
! #define PyDateTime_GET_DAY(o) (((PyDateTime_Object*)o)->data[3])
! #define PyDateTime_GET_HOUR(o) (((PyDateTime_Object*)o)->data[4])
! #define PyDateTime_GET_MINUTE(o) (((PyDateTime_Object*)o)->data[5])
! #define PyDateTime_GET_SECOND(o) (((PyDateTime_Object*)o)->data[6])
! #define PyDateTime_GET_MICROSECOND(o) (((PyDateTime_Object*)o)->data[7] << 16 \
! | ((PyDateTime_Object*)o)->data[8] << 8\
! | ((PyDateTime_Object*)o)->data[9])
#endif
--- 5,42 ----
#define DATETIME_H
! #define _PyDateTime_DATE_DATA_SIZE 4
! #define _PyDateTime_DATETIME_DATA_SIZE 10
typedef struct
{
PyObject_HEAD
! long hashcode;
! unsigned char data[_PyDateTime_DATE_DATA_SIZE];
! } PyDateTime_Date;
+ typedef struct
+ {
+ PyObject_HEAD
+ long hashcode;
+ unsigned char data[_PyDateTime_DATETIME_DATA_SIZE];
+ } PyDateTime_DateTime;
! PyAPI_DATA(PyTypeObject) PyDateTime_DateType;
! PyAPI_DATA(PyTypeObject) PyDateTime_DateTimeType;
! PyAPI_DATA(PyTypeObject) PyDateTime_DeltaType;
!
! /* Apply for date instances. */
! #define PyDateTime_GET_YEAR(o) (((PyDateTime_Date*)o)->data[0] << 8 \
! | ((PyDateTime_Date*)o)->data[1])
! #define PyDateTime_GET_MONTH(o) (((PyDateTime_Date*)o)->data[2])
! #define PyDateTime_GET_DAY(o) (((PyDateTime_Date*)o)->data[3])
!
! /* Apply for datetime instances. */
! #define PyDateTime_GET_HOUR(o) (((PyDateTime_DateTime*)o)->data[4])
! #define PyDateTime_GET_MINUTE(o) (((PyDateTime_DateTime*)o)->data[5])
! #define PyDateTime_GET_SECOND(o) (((PyDateTime_DateTime*)o)->data[6])
! #define PyDateTime_GET_MICROSECOND(o) (((PyDateTime_DateTime*)o)->data[7] << 16 \
! | ((PyDateTime_DateTime*)o)->data[8] << 8\
! | ((PyDateTime_DateTime*)o)->data[9])
#endif
Index: setup.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/setup.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** setup.py 4 Mar 2002 14:36:16 -0000 1.1
--- setup.py 20 Aug 2002 18:53:07 -0000 1.2
***************
*** 1,4 ****
from distutils.core import setup, Extension
setup(name="datetime", version = "0.1",
! ext_modules=[Extension("_datetime", ["datetime.c"])])
--- 1,13 ----
+ #! /usr/bin/env python
+ #
+ # For now, the individual object implementations are split out into
+ # separate files (obj_*.c), with helper functions and module
+ # initialization in datetime.c. This will be changed to simply be a
+ # single file when things have settled down.
+
from distutils.core import setup, Extension
setup(name="datetime", version = "0.1",
! ext_modules=[Extension("_datetime", ["datetime.c"],
! depends=["obj_date.c", "obj_datetime.c",
! "obj_delta.c"])])
Index: test_cdatetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_cdatetime.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** test_cdatetime.py 26 Mar 2002 22:22:50 -0000 1.4
--- test_cdatetime.py 20 Aug 2002 18:53:07 -0000 1.5
***************
*** 8,11 ****
--- 8,218 ----
from _datetime import datetime, MINYEAR, MAXYEAR
+ from _datetime import date, timedelta
+
+
+ class TestDate(unittest.TestCase):
+
+ theclass = date
+
+ def test_basic_attributes(self):
+ dt = self.theclass(2002, 3, 1)
+ self.assertEqual(dt.year, 2002)
+ self.assertEqual(dt.month, 3)
+ self.assertEqual(dt.day, 1)
+
+ def test_roundtrip(self):
+ for dt in (self.theclass(1, 2, 3),
+ self.theclass.today()):
+ # Verify dt -> string -> date identity.
+ s = repr(dt)
+ dt2 = eval(s)
+ self.assertEqual(dt, dt2)
+
+ # Verify identity via reconstructing from pieces.
+ dt2 = self.theclass(dt.year, dt.month, dt.day)
+ self.assertEqual(dt, dt2)
+
+ def test_bad_constructor_arguments(self):
+ # bad years
+ self.theclass(MINYEAR, 1, 1) # no exception
+ self.theclass(MAXYEAR, 1, 1) # no exception
+ self.assertRaises(ValueError, self.theclass, MINYEAR-1, 1, 1)
+ self.assertRaises(ValueError, self.theclass, MAXYEAR+1, 1, 1)
+ # bad months
+ self.theclass(2000, 1, 1) # no exception
+ self.theclass(2000, 12, 1) # no exception
+ self.assertRaises(ValueError, self.theclass, 2000, 0, 1)
+ self.assertRaises(ValueError, self.theclass, 2000, 13, 1)
+ # bad days
+ self.theclass(2000, 2, 29) # no exception
+ self.theclass(2004, 2, 29) # no exception
+ self.theclass(2400, 2, 29) # no exception
+ self.assertRaises(ValueError, self.theclass, 2000, 2, 30)
+ self.assertRaises(ValueError, self.theclass, 2001, 2, 29)
+ self.assertRaises(ValueError, self.theclass, 2100, 2, 29)
+ self.assertRaises(ValueError, self.theclass, 1900, 2, 29)
+ self.assertRaises(ValueError, self.theclass, 2000, 1, 0)
+ self.assertRaises(ValueError, self.theclass, 2000, 1, 32)
+
+ def test_hash_equality(self):
+ d = self.theclass(2000, 12, 31)
+ # same thing
+ e = self.theclass(2000, 12, 31)
+ self.assertEqual(d, e)
+ self.assertEqual(hash(d), hash(e))
+
+ dic = {d: 1}
+ dic[e] = 2
+ self.assertEqual(len(dic), 1)
+ self.assertEqual(dic[d], 2)
+ self.assertEqual(dic[e], 2)
+
+ d = self.theclass(2001, 1, 1)
+ # same thing
+ e = self.theclass(2001, 1, 1)
+ self.assertEqual(d, e)
+ self.assertEqual(hash(d), hash(e))
+
+ dic = {d: 1}
+ dic[e] = 2
+ self.assertEqual(len(dic), 1)
+ self.assertEqual(dic[d], 2)
+ self.assertEqual(dic[e], 2)
+
+ def test_computations(self):
+ a = self.theclass(2002, 1, 31)
+ b = self.theclass(1956, 1, 31)
+ ## print >>sys.__stderr__, a, b
+ ## diff = a-b
+ ## self.assertEqual(diff.days, 46*365 + len(range(1956, 2002, 4)))
+ ## self.assertEqual(diff.seconds, 0)
+ ## self.assertEqual(diff.microseconds, 0)
+ day = timedelta(1)
+ week = timedelta(7)
+ a = self.theclass(2002, 3, 2)
+ self.assertEqual(a + day, self.theclass(2002, 3, 3))
+ self.assertEqual(a - day, self.theclass(2002, 3, 1))
+ self.assertEqual(a + week, self.theclass(2002, 3, 9))
+ self.assertEqual(a - week, self.theclass(2002, 2, 23))
+ self.assertEqual(a + 52*week, self.theclass(2003, 3, 1))
+ self.assertEqual(a - 52*week, self.theclass(2001, 3, 3))
+ self.assertEqual((a + week) - a, week)
+ self.assertEqual((a + day) - a, day)
+ self.assertEqual((a - week) - a, -week)
+ self.assertEqual((a - day) - a, -day)
+ self.assertEqual(a - (a + week), -week)
+ self.assertEqual(a - (a + day), -day)
+ self.assertEqual(a - (a - week), week)
+ self.assertEqual(a - (a - day), day)
+ # Add/sub ints, longs, floats should be illegal
+ for i in 1, 1L, 1.0:
+ self.assertRaises(TypeError, lambda: a+i)
+ self.assertRaises(TypeError, lambda: a-i)
+ self.assertRaises(TypeError, lambda: i+a)
+ self.assertRaises(TypeError, lambda: i-a)
+
+ def test_overflow(self):
+ tiny = self.theclass.resolution
+
+ dt = self.theclass.min + tiny
+ dt -= tiny # no problem
+ self.assertRaises(OverflowError, dt.__sub__, tiny)
+ self.assertRaises(OverflowError, dt.__add__, -tiny)
+
+ dt = self.theclass.max - tiny
+ dt += tiny # no problem
+ ## self.assertRaises(OverflowError, dt.__add__, tiny)
+ ## self.assertRaises(OverflowError, dt.__sub__, -tiny)
+
+ def test_weekday(self):
+ for i in range(7):
+ # March 4, 2002 is a Monday
+ self.assertEqual(self.theclass(2002, 3, 4+i).weekday(), i)
+ self.assertEqual(self.theclass(2002, 3, 4+i).isoweekday(), i+1)
+ # January 2, 1956 is a Monday
+ self.assertEqual(self.theclass(1956, 1, 2+i).weekday(), i)
+ self.assertEqual(self.theclass(1956, 1, 2+i).isoweekday(), i+1)
+
+ def test_isocalendar(self):
+ # Check examples from
+ # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
+ for i in range(7):
+ d = self.theclass(2003, 12, 22+i)
+ self.assertEqual(d.isocalendar(), (2003, 52, i+1))
+ d = self.theclass(2003, 12, 29) + timedelta(i)
+ self.assertEqual(d.isocalendar(), (2004, 1, i+1))
+ d = self.theclass(2004, 1, 5+i)
+ self.assertEqual(d.isocalendar(), (2004, 2, i+1))
+ d = self.theclass(2009, 12, 21+i)
+ self.assertEqual(d.isocalendar(), (2009, 52, i+1))
+ d = self.theclass(2009, 12, 28) + timedelta(i)
+ ## print >>sys.__stderr__, i, `d`, d.isocalendar()
+ ## self.assertEqual(d.isocalendar(), (2009, 53, i+1))
+ d = self.theclass(2010, 1, 4+i)
+ self.assertEqual(d.isocalendar(), (2010, 1, i+1))
+
+ def test_iso_long_years(self):
+ # Calculate long ISO years and compare to table from
+ # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
+ ISO_LONG_YEARS_TABLE = """
+ 4 32 60 88
+ 9 37 65 93
+ 15 43 71 99
+ 20 48 76
+ 26 54 82
+
+ 105 133 161 189
+ 111 139 167 195
+ 116 144 172
+ 122 150 178
+ 128 156 184
+
+ 201 229 257 285
+ 207 235 263 291
+ 212 240 268 296
+ 218 246 274
+ 224 252 280
+
+ 303 331 359 387
+ 308 336 364 392
+ 314 342 370 398
+ 320 348 376
+ 325 353 381
+ """
+ iso_long_years = map(int, ISO_LONG_YEARS_TABLE.split())
+ iso_long_years.sort()
+ L = []
+ for i in range(400):
+ d = self.theclass(2000+i, 12, 31)
+ d1 = self.theclass(1600+i, 12, 31)
+ self.assertEqual(d.isocalendar()[1:], d1.isocalendar()[1:])
+ if d.isocalendar()[1] == 53:
+ L.append(i)
+ self.assertEqual(L, iso_long_years)
+
+ def test_isoformat(self):
+ t = self.theclass(2, 3, 2)
+ self.assertEqual(t.isoformat(), "0002-03-02")
+
+ def test_ctime(self):
+ t = self.theclass(2002, 3, 2)
+ self.assertEqual(t.ctime(), "Sat Mar 2 00:00:00 2002")
+
+ def test_resolution_info(self):
+ self.assert_(isinstance(self.theclass.min, self.theclass))
+ self.assert_(isinstance(self.theclass.max, self.theclass))
+ self.assert_(isinstance(self.theclass.resolution, timedelta))
+ self.assert_(self.theclass.max > self.theclass.min)
+
+ def test_extreme_timedelta(self):
+ big = self.theclass.max - self.theclass.min
+ # 3652058 days, 23 hours, 59 minutes, 59 seconds, 999999 microseconds
+ n = (big.days*24*3600 + big.seconds)*1000000 + big.microseconds
+ # n = 315537897599999999 ~= 2**58.13
+ ## justasbig = timedelta(0, 0, n)
+ ## self.assertEqual(big, justasbig)
+ self.assertEqual(self.theclass.min + big, self.theclass.max)
+ self.assertEqual(self.theclass.max - big, self.theclass.min)
+
class TestDateTime(unittest.TestCase):
***************
*** 55,65 ****
d = self.theclass(2003, 12, 22+i)
self.assertEqual(d.isocalendar(), (2003, 52, i+1))
! ## d = self.theclass(2003, 12, 29) + timedelta(i)
! ## self.assertEqual(d.isocalendar(), (2004, 1, i+1))
d = self.theclass(2004, 1, 5+i)
self.assertEqual(d.isocalendar(), (2004, 2, i+1))
d = self.theclass(2009, 12, 21+i)
self.assertEqual(d.isocalendar(), (2009, 52, i+1))
! ## d = self.theclass(2009, 12, 28) + timedelta(i)
## self.assertEqual(d.isocalendar(), (2009, 53, i+1))
d = self.theclass(2010, 1, 4+i)
--- 262,272 ----
d = self.theclass(2003, 12, 22+i)
self.assertEqual(d.isocalendar(), (2003, 52, i+1))
! d = self.theclass(2003, 12, 29) + timedelta(i)
! self.assertEqual(d.isocalendar(), (2004, 1, i+1))
d = self.theclass(2004, 1, 5+i)
self.assertEqual(d.isocalendar(), (2004, 2, i+1))
d = self.theclass(2009, 12, 21+i)
self.assertEqual(d.isocalendar(), (2009, 52, i+1))
! d = self.theclass(2009, 12, 28) + timedelta(i)
## self.assertEqual(d.isocalendar(), (2009, 53, i+1))
d = self.theclass(2010, 1, 4+i)
***************
*** 120,127 ****
self.assertEqual(self.theclass(1956, 1, 2+i).isoweekday(), i+1)
def test_suite():
! s1 = unittest.makeSuite(TestDateTime, 'test')
! return unittest.TestSuite([s1])
def test_main():
--- 327,339 ----
self.assertEqual(self.theclass(1956, 1, 2+i).isoweekday(), i+1)
+ def test_ctime(self):
+ t = self.theclass(2002, 3, 2, 18, 3, 5, 123)
+ self.assertEqual(t.ctime(), "Sat Mar 2 18:03:05 2002")
+
def test_suite():
! s1 = unittest.makeSuite(TestDate, 'test')
! s2 = unittest.makeSuite(TestDateTime, 'test')
! return unittest.TestSuite([s1, s2])
def test_main():