[Python-checkins] python/nondist/sandbox/datetime doc.txt,1.12,1.13 obj_datetime.c,1.19,1.20 test_both.py,1.38,1.39
tim_one@users.sourceforge.net
tim_one@users.sourceforge.net
Thu, 05 Dec 2002 15:16:01 -0800
Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv22288
Modified Files:
doc.txt obj_datetime.c test_both.py
Log Message:
Brute-forced datetime.today() and datetime.fromtimestamp() to work as
intended. I hate this. I think what I really want is to figure out how,
at the C level, to say "OK, I've got a type object. Now figure out what
*it* calls the 'fromtimestamp' class method, and call that". Else,
like now, I get goofy code duplication and a lack of extensibility.
Also got a start on serious docs for datetime.
Index: doc.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/doc.txt,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** doc.txt 5 Dec 2002 20:28:41 -0000 1.12
--- doc.txt 5 Dec 2002 23:15:59 -0000 1.13
***************
*** 317,320 ****
--- 317,495 ----
class datetime
==============
+ A datetime object is a single object containing all the information from
+ a date object and a time object. Like a date object, datetime assumes
+ the current Gregorian calendar extended in both directions; like a time
+ object, datetime assumes there are exact 3600*24 seconds in every day.
+
+ Constructor:
+
+ datetime(year, month, day,
+ hour=0, minute=0, second=0, microsecond=0)
+
+ The year, month and day arguments are required. Arguments may be ints
+ or longs, in the following ranges:
+
+ MINYEAR <= year <= MAXYEAR
+ 1 <= month <= 12
+ 1 <= day <= number of days in the given month and year
+ 0 <= hour < 24
+ 0 <= minute < 60
+ 0 <= second < 60
+ 0 <= microsecond < 1000000
+
+ If an argument outside those ranges is given, ValueError is raised.
+
+ Other constructors (class methods):
+
+ - today()
+
+ Return the current local datetime. This is equivalent to
+ datetime.fromtimestamp(time.time()).
+
+ - now()
+
+ Return the current local datetime. This is like today(), but, if
+ possible, supplies more precision than can be gotten from going
+ through a time.time() timestamp.
+ XXX It currently doesn't.
+
+ - fromtimestamp(timestamp)
+
+ Return the local datetime corresponding to the POSIX timestamp, such as
+ is returned by time.time(). This may raise ValueError, if the
+ timestamp is out of the range of values supported by the platform C
+ localtime() function. It's common for this to be restricted to
+ years in 1970 through 2038.
+
+ - fromordinal(ordinal)
+
+ Return the date corresponding to the proleptic Gregorian ordinal,
+ where January 1 of year 1 has ordinal 1. ValueError is raised
+ unless 1 <= ordinal <= datetime.max.toordinal().
+
+ XXX THERE ARE A SLEW OF OTHER CONSTRUCTORS IN THE PYTHON IMPLEMENTATION
+ XXX THAT DON'T EXIST YET IN THE C IMPLEMENTATION.
+
+ Class attributes:
+
+ .min
+ The earliest representable datetime,
+ datetime(MINYEAR, 1, 1).
+
+ .max
+ The latest representable datetime,
+ datetime(MAXYEAR, 12, 31, 23, 59, 59, 999999).
+
+ .resolution
+ The smallest possible difference between non-equal datetime
+ objects, timedelta(microseconds=1).
+
+ Instance attributes (read-only):
+
+ .year between MINYEAR and MAXYEAR inclusive
+ .month between 1 and 12 inclusive
+ .day between 1 and the number of days in the given month
+ of the given year
+ .hour in range(24)
+ .minute in range(60)
+ .second in range(60)
+ .microsecond in range(1000000)
+
+ Supported operations:
+
+ - datetime1 + timedelta -> datetime2
+ timedelta + datetime1 -> datetime2
+ datetime2 is a duration of timedelta removed from datetime1, moving
+ forward in time if timedelta.days > 0, or backward if
+ timedelta.days < 0. datetime2 - datetime1 == timedelta after.
+ OverflowError is raised if date2.year would be smaller than MINYEAR
+ or larger than MAXYEAR.
+
+ XXX NOTHING BELOW THIS POINT HAS BEEN CHECKED, AND MUCH IS CERTAINLY
+ XXX WRONG (CUT & PASTE ERRORS MOSTLY) AND/OR MISIMPLEMENTED.
+
+ - date1 - timedelta -> date2
+ Computes the date2 such that date2 + timedelta == date1. This
+ isn't quite equivalent to date1 + (-timedelta), because -timedelta
+ in isolation can overflow in cases where date1 - timedelta does
+ not. timedelta.seconds and timedelta.microseconds are ignored.
+
+ - date1 - date2 -> timedelta
+ This is exact, and cannot overflow. timedelta.seconds and
+ timedelta.microseconds are 0, and date2 + timedelta == date1
+ after.
+
+ - comparison of date to date, where date1 is considered less than
+ date2 when date1 precedes date2 in time. In other words,
+ date1 < date2 if and only if date1.toordinal() < date2.toordinal().
+
+ - hash, use as dict key
+
+ - pickling
+
+ Instance methods:
+
+ - timetuple()
+ Return a 9-element tuple of the form returned by time.localtime().
+ The hours, minutes and seconds are 0, and the DST flag is -1.
+ d.timetuple() is equivalent to
+ (d.year, d.month, d.day,
+ 0, 0, 0, # h, m, s
+ d.weekday(), # 0 is Monday
+ d.toordinal() - date(d.year, 1, 1).toordinal() + 1, # day of year
+ -1)
+
+ - toordinal()
+ Return the proleptic Gregorian ordinal of the date, where January 1
+ of year 1 has ordinal 1. For any date object d,
+ date.fromordinal(d.toordinal()) == d.
+
+ - weekday()
+ Return the day of the week as an integer, where Monday is 0 and
+ Sunday is 6. For example, date(2002, 12, 4).weekday() == 2, a
+ Wednesday.
+ See also isoweekday().
+
+ - isoweekday()
+ Return the day of the week as an integer, where Monday is 1 and
+ Sunday is 7. For example, date(2002, 12, 4).isoweekday() == 3, a
+ Wednesday.
+ See also weekday() and isocalendar().
+
+ - isocalendar()
+ Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
+
+ The ISO calendar is a widely used variant of the Gregorian calendar.
+ See <http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm>
+ for a good explanation.
+
+ The ISO year consists of 52 or 53 full weeks, and where a week starts
+ on a Monday and ends on a Sunday. The first week of an ISO year is
+ the first (Gregorian) calendar week of a year containing a Thursday.
+ This is called week number 1, and the ISO year of that Thursday is
+ the same as its Gregorian year.
+
+ For example, 2004 begins on a Thursday, so the first week of ISO
+ year 2004 begins on Monday, 29 Dec 2003 and ends on Sunday, 4 Jan
+ 2004, so that
+
+ date(2003, 12, 29).isocalendar() == (2004, 1, 1)
+ date(2004, 1, 4).isocalendar() == (2004, 1, 7)
+
+ - isoformat()
+ Return a string representing the date in ISO 8601 format,
+ 'YYYY-MM-DD'. For example,
+ date(2002, 12, 4).isoformat() == '2002-12-04'.
+ str(d) is equivalent to d.isoformat().
+
+ - ctime()
+ Return a string representing the date, for example
+ date(2002, 12, 4).ctime() == 'Wed Dec 4 00:00:00 2002'.
+ d.ctime() is equivalent to time.ctime(time.mktime(d.timetuple())).
+
+ - strftime(format)
+ Return a string representing the date, controlled by an explicit
+ format string. d.strftime(f) is the same as
+ time.strftime(f, d.timetuple()).
Index: obj_datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_datetime.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -C2 -d -r1.19 -r1.20
*** obj_datetime.c 5 Dec 2002 21:29:36 -0000 1.19
--- obj_datetime.c 5 Dec 2002 23:15:59 -0000 1.20
***************
*** 241,244 ****
--- 241,337 ----
static PyObject *
+ datetime_local_from_time_t(PyObject *cls, time_t t)
+ {
+ struct tm *tm;
+ PyObject *result = NULL;
+
+ tm = localtime(&t);
+ if (tm)
+ result = PyObject_CallFunction(cls, "llllll",
+ tm->tm_year + 1900,
+ tm->tm_mon + 1,
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ else
+ PyErr_SetString(PyExc_ValueError,
+ "timestamp out of range for "
+ "platform localtime() function");
+ return result;
+ }
+
+ /* Return new datetime from given timestamp (Python timestamp -- a double). */
+ static PyObject *
+ datetime_fromtimestamp(PyObject *self, PyObject *args)
+ {
+ PyObject *cls;
+ double timestamp;
+ PyObject *result = NULL;
+
+ if (PyArg_ParseTuple(args, "Od:fromtimestamp", &cls, ×tamp))
+ result = datetime_local_from_time_t(cls, (time_t)timestamp);
+ return result;
+ }
+
+ static PyObject *
+ datetime_now(PyObject *self, PyObject *cls)
+ {
+ /* XXX MAJOR: This needs to get some notion of current time
+ * XXX to better than 1-second resolution. Doing this in a x-
+ * XXX platform way is mondo painful. Maybe floattime() from
+ * XXX timemodule.c is good enough? We're running out of bits
+ * XXX in a typical time_t, though, and gettimeofday() should do
+ * XXX better than floattime() -- but gettimeofday isn't portable.
+ */
+ #if 0
+ /* 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);
+ #else
+ /* XXX need to create the instance by calling cls(y,mon,d,h,min,s,u) */
+ struct tm *tm;
+ time_t timet;
+
+ time(&timet);
+ tm = localtime(&timet);
+
+ return PyObject_CallFunction(cls, "llllll",
+ tm->tm_year + 1900, tm->tm_mon + 1,
+ tm->tm_mday, tm->tm_hour, tm->tm_min,
+ tm->tm_sec);
+ #endif
+ }
+
+ static PyObject *
+ datetime_today(PyObject *self, PyObject *cls)
+ {
+ struct tm *tm;
+ time_t timet;
+
+ time(&timet);
+ tm = localtime(&timet);
+
+ return PyObject_CallFunction(cls, "llllll",
+ tm->tm_year + 1900, tm->tm_mon + 1,
+ tm->tm_mday, tm->tm_hour,
+ tm->tm_min, tm->tm_sec);
+ }
+
+ static PyObject *
datetime_hour(PyDateTime_DateTime *self, void *unused)
{
***************
*** 345,406 ****
}
- static PyObject *
- datetime_now(PyObject *self, PyObject *cls)
- {
- /* XXX MAJOR: This needs to get some notion of current time
- * XXX to better than 1-second resolution. Doing this in a x-
- * XXX platform way is mondo painful. Maybe floattime() from
- * XXX timemodule.c is good enough? We're running out of bits
- * XXX in a typical time_t, though, and gettimeofday() should do
- * XXX better than floattime() -- but gettimeofday isn't portable.
- */
- #if 0
- /* 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);
- #else
- /* XXX need to create the instance by calling cls(y,mon,d,h,min,s,u) */
- struct tm *tm;
- time_t timet;
-
- time(&timet);
- 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, 0);
- #endif
- }
-
- 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 tm *tm;
- time_t timet;
-
- time(&timet);
- tm = localtime(&timet);
-
- return PyObject_CallFunction(cls, "iiiiiil",
- tm->tm_year + 1900, tm->tm_mon + 1,
- tm->tm_mday, 0, 0, 0, 0);
- }
-
/* Pickle support. Quite a maze! */
static PyObject *
--- 438,441 ----
***************
*** 463,478 ****
--- 498,522 ----
{"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."},
+ {"fromtimestamp", (PyCFunction)datetime_fromtimestamp, METH_VARARGS |
+ METH_CLASS,
+ "timestamp -> local datetime from a POSIX timestamp "
+ "(like time.time())."},
+
/* Instance methods: */
{"ctime", (PyCFunction)datetime_ctime, METH_NOARGS,
"Return ctime() style string."},
+
{"isoformat", (PyCFunction)datetime_isoformat, METH_KEYWORDS,
"[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)datetime_setstate, METH_O,
PyDoc_STR("__setstate__(state)")},
+
{"__getstate__", (PyCFunction)datetime_getstate, METH_NOARGS,
PyDoc_STR("__getstate__() -> state")},
Index: test_both.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_both.py,v
retrieving revision 1.38
retrieving revision 1.39
diff -C2 -d -r1.38 -r1.39
*** test_both.py 5 Dec 2002 20:28:41 -0000 1.38
--- test_both.py 5 Dec 2002 23:15:59 -0000 1.39
***************
*** 563,577 ****
self.assertEqual(d.day, day)
! # Try today.
! today = self.theclass.today()
! ts = time.time()
! todayagain = self.theclass.fromtimestamp(ts)
! if today != todayagain:
! # It's possible that equality fails if we're running at a
! # midnight boundary, so wait a little and try again.
! time.sleep(5)
today = self.theclass.today()
ts = time.time()
todayagain = self.theclass.fromtimestamp(ts)
self.assertEqual(today, todayagain)
--- 563,583 ----
self.assertEqual(d.day, day)
! def test_today(self):
! import time
!
! count = 0
! while count < 3:
! count += 1
today = self.theclass.today()
ts = time.time()
todayagain = self.theclass.fromtimestamp(ts)
+ if today == todayagain:
+ break
+ # It's possible that equality fails if we're running at a
+ # midnight boundary, and also possible that it fails if we're
+ # testing datetime and it takes more than a second between
+ # operations above. Wait a little and try again.
+ time.sleep(1)
+
self.assertEqual(today, todayagain)
***************
*** 1014,1017 ****
--- 1020,1037 ----
self.assertEqual(cmp(t2, t1), 1)
+ def test_fromtimestamp(self):
+ import time
+
+ # Try an arbitrary fixed value.
+ year, month, day = 1999, 9, 19
+ hour, minute, second = 22, 17, 36
+ ts = time.mktime((year, month, day, hour, minute, second, 0, 0, -1))
+ d = self.theclass.fromtimestamp(ts)
+ self.assertEqual(d.year, year)
+ self.assertEqual(d.month, month)
+ self.assertEqual(d.day, day)
+ self.assertEqual(d.hour, hour)
+ self.assertEqual(d.minute, minute)
+ self.assertEqual(d.second, second)
def test_suite():