diff options
author | Mark Wiebe <mwiebe@enthought.com> | 2011-05-25 10:21:17 -0500 |
---|---|---|
committer | Mark Wiebe <mwiebe@enthought.com> | 2011-05-25 10:21:17 -0500 |
commit | a106c2932c9350420a395bd2681ef8f17e4b1e36 (patch) | |
tree | bab36c076d6d0bcbfb93bd742966727b3c5a5728 | |
parent | 6b8ad91154f90e26fb3428f023dab98e858c2b72 (diff) | |
download | numpy-a106c2932c9350420a395bd2681ef8f17e4b1e36.tar.gz |
ENH: datetime: Tests and fixes for datetime64 <-> object roundtripping
-rw-r--r-- | numpy/core/src/multiarray/arraytypes.c.src | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/datetime.c | 43 | ||||
-rw-r--r-- | numpy/core/src/multiarray/methods.c | 2 | ||||
-rw-r--r-- | numpy/core/tests/test_datetime.py | 36 |
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]') |