summaryrefslogtreecommitdiffstats
path: root/Modules/timemodule.c
diff options
context:
space:
mode:
authorBrett Cannon <bcannon@gmail.com>2004-06-19 20:48:43 (GMT)
committerBrett Cannon <bcannon@gmail.com>2004-06-19 20:48:43 (GMT)
commit298c380c74294bedcc0b5999c57e3aca03fb3731 (patch)
tree3064e192d47ff9049f27351158641410628cd0ef /Modules/timemodule.c
parentcdc7923f6d1c9731d81f299569b1ea72de7eb212 (diff)
downloadcpython-298c380c74294bedcc0b5999c57e3aca03fb3731.zip
cpython-298c380c74294bedcc0b5999c57e3aca03fb3731.tar.gz
cpython-298c380c74294bedcc0b5999c57e3aca03fb3731.tar.bz2
Raise ValueError when value being stored in a time_t variable will result in
more than a second of precision. Primarily affects ctime, localtime, and gmtime. Closes bug #919012 thanks to Tim Peters' code. Tim suggests that the new funciton being introduced, _PyTime_DoubletoTimet(), should be added to the internal C API and then used in datetime where appropriate. Not being done now for lack of time.
Diffstat (limited to 'Modules/timemodule.c')
-rw-r--r--Modules/timemodule.c45
1 files changed, 40 insertions, 5 deletions
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index ef6ee3e..0783f7f 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -84,6 +84,35 @@ static double floattime(void);
/* For Y2K check */
static PyObject *moddict;
+/* Cast double x to time_t, but raise ValueError if x is too large
+ * to fit in a time_t. ValueError is set on return iff the return
+ * value is (time_t)-1 and PyErr_Occurred().
+ */
+static time_t
+_PyTime_DoubleToTimet(double x)
+{
+ time_t result;
+ double diff;
+
+ result = (time_t)x;
+ /* How much info did we lose? time_t may be an integral or
+ * floating type, and we don't know which. If it's integral,
+ * we don't know whether C truncates, rounds, returns the floor,
+ * etc. If we lost a second or more, the C rounding is
+ * unreasonable, or the input just doesn't fit in a time_t;
+ * call it an error regardless. Note that the original cast to
+ * time_t can cause a C error too, but nothing we can do to
+ * worm around that.
+ */
+ diff = x - (double)result;
+ if (diff <= -1.0 || diff >= 1.0) {
+ PyErr_SetString(PyExc_ValueError,
+ "timestamp out of range for platform time_t");
+ result = (time_t)-1;
+ }
+ return result;
+}
+
static PyObject *
time_time(PyObject *self, PyObject *args)
{
@@ -231,11 +260,15 @@ tmtotuple(struct tm *p)
}
static PyObject *
-time_convert(time_t when, struct tm * (*function)(const time_t *))
+time_convert(double when, struct tm * (*function)(const time_t *))
{
struct tm *p;
+ time_t whent = _PyTime_DoubleToTimet(when);
+
+ if (whent == (time_t)-1 && PyErr_Occurred())
+ return NULL;
errno = 0;
- p = function(&when);
+ p = function(&whent);
if (p == NULL) {
#ifdef EINVAL
if (errno == 0)
@@ -254,7 +287,7 @@ time_gmtime(PyObject *self, PyObject *args)
when = floattime();
if (!PyArg_ParseTuple(args, "|d:gmtime", &when))
return NULL;
- return time_convert((time_t)when, gmtime);
+ return time_convert(when, gmtime);
}
PyDoc_STRVAR(gmtime_doc,
@@ -272,7 +305,7 @@ time_localtime(PyObject *self, PyObject *args)
when = floattime();
if (!PyArg_ParseTuple(args, "|d:localtime", &when))
return NULL;
- return time_convert((time_t)when, localtime);
+ return time_convert(when, localtime);
}
PyDoc_STRVAR(localtime_doc,
@@ -480,7 +513,9 @@ time_ctime(PyObject *self, PyObject *args)
else {
if (!PyArg_ParseTuple(args, "|d:ctime", &dt))
return NULL;
- tt = (time_t)dt;
+ tt = _PyTime_DoubleToTimet(dt);
+ if (tt == (time_t)-1 && PyErr_Occurred())
+ return NULL;
}
p = ctime(&tt);
if (p == NULL) {