summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2016-01-14 10:22:51 -0700
committerCharles Harris <charlesr.harris@gmail.com>2016-01-14 10:22:51 -0700
commit8fa6e3bef26a6d4a2c92f2824129aa4409be2590 (patch)
tree754b8bdc2fb5ebd27847edc84458127322bb5e78 /numpy
parent51d2ecdc7a0aad61e250f9c67a040b0ecae086c3 (diff)
parent33adec24a1403df5c47afe235ac1869a8f489489 (diff)
downloadnumpy-8fa6e3bef26a6d4a2c92f2824129aa4409be2590.tar.gz
Merge pull request #6465 from shoyer/datetime64-NaT-casting
BUG: fix casting rules for generic datetime64/timedelta64 dtypes
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/datetime.c22
-rw-r--r--numpy/core/tests/test_datetime.py21
2 files changed, 35 insertions, 8 deletions
diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c
index 9e4e00e9c..264178d30 100644
--- a/numpy/core/src/multiarray/datetime.c
+++ b/numpy/core/src/multiarray/datetime.c
@@ -1232,12 +1232,18 @@ datetime_metadata_divides(
{
npy_uint64 num1, num2;
- /* Generic units divide into anything */
- if (divisor->base == NPY_FR_GENERIC) {
+ /*
+ * Any unit can always divide into generic units. In other words, we
+ * should be able to convert generic units into any more specific unit.
+ */
+ if (dividend->base == NPY_FR_GENERIC) {
return 1;
}
- /* Non-generic units never divide into generic units */
- else if (dividend->base == NPY_FR_GENERIC) {
+ /*
+ * However, generic units cannot always divide into more specific units.
+ * We cannot safely convert datetimes with units back into generic units.
+ */
+ else if (divisor->base == NPY_FR_GENERIC) {
return 0;
}
@@ -1330,7 +1336,7 @@ can_cast_datetime64_units(NPY_DATETIMEUNIT src_unit,
*/
case NPY_SAME_KIND_CASTING:
if (src_unit == NPY_FR_GENERIC || dst_unit == NPY_FR_GENERIC) {
- return src_unit == dst_unit;
+ return src_unit == NPY_FR_GENERIC;
}
else {
return (src_unit <= NPY_FR_D && dst_unit <= NPY_FR_D) ||
@@ -1344,7 +1350,7 @@ can_cast_datetime64_units(NPY_DATETIMEUNIT src_unit,
*/
case NPY_SAFE_CASTING:
if (src_unit == NPY_FR_GENERIC || dst_unit == NPY_FR_GENERIC) {
- return src_unit == dst_unit;
+ return src_unit == NPY_FR_GENERIC;
}
else {
return (src_unit <= dst_unit) &&
@@ -1380,7 +1386,7 @@ can_cast_timedelta64_units(NPY_DATETIMEUNIT src_unit,
*/
case NPY_SAME_KIND_CASTING:
if (src_unit == NPY_FR_GENERIC || dst_unit == NPY_FR_GENERIC) {
- return src_unit == dst_unit;
+ return src_unit == NPY_FR_GENERIC;
}
else {
return (src_unit <= NPY_FR_M && dst_unit <= NPY_FR_M) ||
@@ -1394,7 +1400,7 @@ can_cast_timedelta64_units(NPY_DATETIMEUNIT src_unit,
*/
case NPY_SAFE_CASTING:
if (src_unit == NPY_FR_GENERIC || dst_unit == NPY_FR_GENERIC) {
- return src_unit == dst_unit;
+ return src_unit == NPY_FR_GENERIC;
}
else {
return (src_unit <= dst_unit) &&
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index 8a8eafee8..360463d38 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -114,6 +114,27 @@ class TestDateTime(TestCase):
# Can cast safely if the integer multiplier does divide
assert_(np.can_cast('M8[6h]', 'M8[3h]', casting='safe'))
+ # We can always cast types with generic units (corresponding to NaT) to
+ # more specific types
+ assert_(np.can_cast('m8', 'm8[h]', casting='same_kind'))
+ assert_(np.can_cast('m8', 'm8[h]', casting='safe'))
+ assert_(np.can_cast('M8', 'M8[h]', casting='same_kind'))
+ assert_(np.can_cast('M8', 'M8[h]', casting='safe'))
+ # but not the other way around
+ assert_(not np.can_cast('m8[h]', 'm8', casting='same_kind'))
+ assert_(not np.can_cast('m8[h]', 'm8', casting='safe'))
+ assert_(not np.can_cast('M8[h]', 'M8', casting='same_kind'))
+ assert_(not np.can_cast('M8[h]', 'M8', casting='safe'))
+
+ def test_compare_generic_nat(self):
+ # regression tests for GH6452
+ assert_equal(np.datetime64('NaT'),
+ np.datetime64('2000') + np.timedelta64('NaT'))
+ # nb. we may want to make NaT != NaT true in the future; this test
+ # verifies the existing behavior (and that it should not warn)
+ assert_(np.datetime64('NaT') == np.datetime64('NaT', 'us'))
+ assert_(np.datetime64('NaT', 'us') == np.datetime64('NaT'))
+
def test_datetime_scalar_construction(self):
# Construct with different units
assert_equal(np.datetime64('1950-03-12', 'D'),