summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wiebe <mwiebe@enthought.com>2011-05-25 10:21:17 -0500
committerMark Wiebe <mwiebe@enthought.com>2011-05-25 10:21:17 -0500
commita106c2932c9350420a395bd2681ef8f17e4b1e36 (patch)
treebab36c076d6d0bcbfb93bd742966727b3c5a5728
parent6b8ad91154f90e26fb3428f023dab98e858c2b72 (diff)
downloadnumpy-a106c2932c9350420a395bd2681ef8f17e4b1e36.tar.gz
ENH: datetime: Tests and fixes for datetime64 <-> object roundtripping
-rw-r--r--numpy/core/src/multiarray/arraytypes.c.src2
-rw-r--r--numpy/core/src/multiarray/datetime.c43
-rw-r--r--numpy/core/src/multiarray/methods.c2
-rw-r--r--numpy/core/tests/test_datetime.py36
4 files changed, 55 insertions, 28 deletions
diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src
index 80bd59636..ac3da4558 100644
--- a/numpy/core/src/multiarray/arraytypes.c.src
+++ b/numpy/core/src/multiarray/arraytypes.c.src
@@ -1069,7 +1069,7 @@ DATETIME_getitem(char *ip, PyArrayObject *ap) {
/* Get the datetime units metadata */
meta = get_datetime_metadata_from_dtype(PyArray_DESCR(ap));
if (meta == NULL) {
- return -1;
+ return NULL;
}
if ((ap == NULL) || PyArray_ISBEHAVED_RO(ap)) {
diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c
index accadf7c5..0d1ed563e 100644
--- a/numpy/core/src/multiarray/datetime.c
+++ b/numpy/core/src/multiarray/datetime.c
@@ -328,7 +328,7 @@ convert_datetimestruct_to_datetime(PyArray_DatetimeMetaData *meta,
}
else if (base == NPY_FR_M) {
/* Truncate to the month */
- ret = 12 * (dts->year - 1970) + dts->month;
+ ret = 12 * (dts->year - 1970) + (dts->month - 1);
}
else {
/* Otherwise calculate the number of days to start */
@@ -2602,27 +2602,33 @@ convert_datetime_to_pyobject(npy_datetime dt, PyArray_DatetimeMetaData *meta)
/* If the type's precision is greater than microseconds, return an int */
if (meta->base > NPY_FR_us) {
- ret = PyLong_FromLongLong(dt);
+ /* Skip use of a tuple for the events, just return the raw int */
+ return PyLong_FromLongLong(dt);
}
- else {
- /* Convert to a datetimestruct */
- if (convert_datetime_to_datetimestruct(meta, dt, &dts) < 0) {
- return NULL;
- }
- /* If the type's precision is greater than days, return a datetime */
- if (meta->base > NPY_FR_D) {
- ret = PyDateTime_FromDateAndTime(dts.year, dts.month, dts.day,
- dts.hour, dts.min, dts.sec, dts.us);
- }
- /* Otherwise return a date */
- else {
- ret = PyDate_FromDate(dts.year, dts.month, dts.day);
- }
+ /* Convert to a datetimestruct */
+ if (convert_datetime_to_datetimestruct(meta, dt, &dts) < 0) {
+ return NULL;
}
- if (ret == NULL) {
- return NULL;
+ /*
+ * If the year is outside the range of years supported by Python's
+ * datetime, or the datetime64 falls on a leap second,
+ * return a raw int.
+ */
+ if (dts.year < 1 || dts.year > 9999 || dts.sec == 60) {
+ /* Also skip use of a tuple for the events */
+ return PyLong_FromLongLong(dt);
+ }
+
+ /* If the type's precision is greater than days, return a datetime */
+ if (meta->base > NPY_FR_D) {
+ ret = PyDateTime_FromDateAndTime(dts.year, dts.month, dts.day,
+ dts.hour, dts.min, dts.sec, dts.us);
+ }
+ /* Otherwise return a date */
+ else {
+ ret = PyDate_FromDate(dts.year, dts.month, dts.day);
}
/* If there is one event, just return the datetime */
@@ -2637,6 +2643,7 @@ convert_datetime_to_pyobject(npy_datetime dt, PyArray_DatetimeMetaData *meta)
return NULL;
}
PyTuple_SET_ITEM(tup, 0, ret);
+
ret = PyInt_FromLong(dts.event);
if (ret == NULL) {
Py_DECREF(tup);
diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c
index a4c92b2a1..02a619eec 100644
--- a/numpy/core/src/multiarray/methods.c
+++ b/numpy/core/src/multiarray/methods.c
@@ -185,8 +185,6 @@ array_view(PyArrayObject *self, PyObject *args, PyObject *kwds)
if ((out_dtype) &&
(PyArray_DescrConverter(out_dtype, &dtype) == PY_FAIL)) {
- PyErr_SetString(PyExc_ValueError,
- "Dtype must be a numpy data-type");
return NULL;
}
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index 46fcdc0d9..79f3e9e41 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -96,17 +96,39 @@ class TestDateTime(TestCase):
np.dtype('m8[s]'), np.dtype('m8[as]'))
- """
- def test_pyobject_conversion(self):
+ def test_pyobject_roundtrip(self):
# All datetime types should be able to roundtrip through object
- a = np.array([-1020040340, -2942398, -1, 0, 1, 234523453, 1199164176],
+ a = np.array([0,0,0,0,0,0,0,0,
+ -1020040340, -2942398, -1, 0, 1, 234523453, 1199164176],
dtype=np.int64)
for unit in ['M8[as]', 'M8[16fs]', 'M8[ps]', 'M8[us]',
- 'M8[as//12]', 'M8[us//16]', 'M8[D]', 'M8[D]//4',
+ 'M8[as]//12', 'M8[us]//16', 'M8[D]', 'M8[D]//4',
'M8[W]', 'M8[M]', 'M8[Y]']:
- assert_equal(a.view(dtype=unit).astype(object).astype(unit),
- a.view(dtype=unit))
- """
+ b = a.copy().view(dtype=unit)
+ b[0] = '-0001-01-01'
+ b[1] = '-0001-12-31'
+ b[2] = '0000-01-01'
+ b[3] = '0001-01-01'
+ b[4] = '1969-12-31T23:59:59.999999Z'
+ b[5] = '1970-01-01'
+ b[6] = '9999-12-31T23:59:59.999999Z'
+ b[7] = '10000-01-01'
+
+ assert_equal(b.astype(object).astype(unit), b,
+ "Error roundtripping unit %s" % unit)
+
+ def test_month_trucation(self):
+ # Make sure that months are truncating correctly
+ assert_equal(np.array('1945-03-01', dtype='M8[M]'),
+ np.array('1945-03-31', dtype='M8[M]'))
+ assert_equal(np.array('1969-11-01', dtype='M8[M]'),
+ np.array('1969-11-30T23:59:59.999999Z', dtype='M8[M]'))
+ assert_equal(np.array('1969-12-01', dtype='M8[M]'),
+ np.array('1969-12-31T23:59:59.999999Z', dtype='M8[M]'))
+ assert_equal(np.array('1970-01-01', dtype='M8[M]'),
+ np.array('1970-01-31T23:59:59.999999Z', dtype='M8[M]'))
+ assert_equal(np.array('1980-02-01', dtype='M8[M]'),
+ np.array('1980-02-29T23:59:59.999999Z', dtype='M8[M]'))
def test_hours(self):
t = np.ones(3, dtype='M8[s]')