diff --git a/cpp/src/arrow/compute/kernels/codegen_internal.cc b/cpp/src/arrow/compute/kernels/codegen_internal.cc index 1e06a364509..26c12ebf591 100644 --- a/cpp/src/arrow/compute/kernels/codegen_internal.cc +++ b/cpp/src/arrow/compute/kernels/codegen_internal.cc @@ -120,7 +120,14 @@ void ReplaceTemporalTypes(const TimeUnit::type unit, std::vector* de continue; } case Type::TIME32: - case Type::TIME64: + case Type::TIME64: { + if (unit > TimeUnit::MILLI) { + it->type = time64(unit); + } else { + it->type = time32(unit); + } + continue; + } case Type::DURATION: { it->type = duration(unit); continue; diff --git a/cpp/src/arrow/compute/kernels/codegen_internal_test.cc b/cpp/src/arrow/compute/kernels/codegen_internal_test.cc index 6b68632ceb3..c2e17e377f2 100644 --- a/cpp/src/arrow/compute/kernels/codegen_internal_test.cc +++ b/cpp/src/arrow/compute/kernels/codegen_internal_test.cc @@ -198,6 +198,10 @@ TEST(TestDispatchBest, CommonTemporalResolution) { ASSERT_EQ(TimeUnit::MILLI, CommonTemporalResolution(args.data(), args.size())); args = {timestamp(TimeUnit::SECOND, "UTC"), timestamp(TimeUnit::SECOND, tz)}; ASSERT_EQ(TimeUnit::SECOND, CommonTemporalResolution(args.data(), args.size())); + args = {time32(TimeUnit::MILLI), duration(TimeUnit::SECOND)}; + ASSERT_EQ(TimeUnit::MILLI, CommonTemporalResolution(args.data(), args.size())); + args = {time64(TimeUnit::MICRO), duration(TimeUnit::NANO)}; + ASSERT_EQ(TimeUnit::NANO, CommonTemporalResolution(args.data(), args.size())); } TEST(TestDispatchBest, ReplaceTemporalTypes) { @@ -215,7 +219,7 @@ TEST(TestDispatchBest, ReplaceTemporalTypes) { ty = CommonTemporalResolution(args.data(), args.size()); ReplaceTemporalTypes(ty, &args); AssertTypeEqual(args[0].type, timestamp(TimeUnit::MILLI)); - AssertTypeEqual(args[1].type, duration(TimeUnit::MILLI)); + AssertTypeEqual(args[1].type, time32(TimeUnit::MILLI)); args = {duration(TimeUnit::SECOND), date64()}; ty = CommonTemporalResolution(args.data(), args.size()); @@ -233,7 +237,7 @@ TEST(TestDispatchBest, ReplaceTemporalTypes) { ty = CommonTemporalResolution(args.data(), args.size()); ReplaceTemporalTypes(ty, &args); AssertTypeEqual(args[0].type, timestamp(TimeUnit::NANO, tz)); - AssertTypeEqual(args[1].type, duration(TimeUnit::NANO)); + AssertTypeEqual(args[1].type, time64(TimeUnit::NANO)); args = {timestamp(TimeUnit::SECOND, tz), date64()}; ty = CommonTemporalResolution(args.data(), args.size()); diff --git a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc index b8dae54b67a..dd0476584fc 100644 --- a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc +++ b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc @@ -2481,6 +2481,20 @@ void RegisterScalarArithmetic(FunctionRegistry* registry) { std::move(exec))); } + // Add subtract(time32, time32) -> duration + for (auto unit : {TimeUnit::SECOND, TimeUnit::MILLI}) { + InputType in_type(match::Time32TypeUnit(unit)); + auto exec = ScalarBinaryEqualTypes::Exec; + DCHECK_OK(subtract->AddKernel({in_type, in_type}, duration(unit), std::move(exec))); + } + + // Add subtract(time64, time64) -> duration + for (auto unit : {TimeUnit::MICRO, TimeUnit::NANO}) { + InputType in_type(match::Time64TypeUnit(unit)); + auto exec = ScalarBinaryEqualTypes::Exec; + DCHECK_OK(subtract->AddKernel({in_type, in_type}, duration(unit), std::move(exec))); + } + // Add subtract(date32, date32) -> duration(TimeUnit::SECOND) InputType in_type_date_32(date32()); auto exec_date_32 = ScalarBinaryEqualTypes::Exec; @@ -2533,6 +2547,22 @@ void RegisterScalarArithmetic(FunctionRegistry* registry) { duration(TimeUnit::MILLI), std::move(exec_date_64_checked))); + // Add subtract_checked(time32, time32) -> duration + for (auto unit : {TimeUnit::SECOND, TimeUnit::MILLI}) { + InputType in_type(match::Time32TypeUnit(unit)); + auto exec = ScalarBinaryEqualTypes::Exec; + DCHECK_OK( + subtract_checked->AddKernel({in_type, in_type}, duration(unit), std::move(exec))); + } + + // Add subtract_checked(time64, time64) -> duration + for (auto unit : {TimeUnit::MICRO, TimeUnit::NANO}) { + InputType in_type(match::Time64TypeUnit(unit)); + auto exec = ScalarBinaryEqualTypes::Exec; + DCHECK_OK( + subtract_checked->AddKernel({in_type, in_type}, duration(unit), std::move(exec))); + } + DCHECK_OK(registry->AddFunction(std::move(subtract_checked))); // ---------------------------------------------------------------------- diff --git a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc index 67a5a8b57f0..7b7a31422bf 100644 --- a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc +++ b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc @@ -1117,6 +1117,45 @@ TEST_F(ScalarTemporalTest, TestTemporalSubtractTimestamp) { } } +TEST_F(ScalarTemporalTest, TestTemporalSubtractTime) { + for (auto op : {"subtract", "subtract_checked"}) { + auto arr_s = ArrayFromJSON(time32(TimeUnit::SECOND), times_s); + auto arr_s2 = ArrayFromJSON(time32(TimeUnit::SECOND), times_s2); + auto arr_ms = ArrayFromJSON(time32(TimeUnit::MILLI), times_ms); + auto arr_ms2 = ArrayFromJSON(time32(TimeUnit::MILLI), times_ms2); + auto arr_us = ArrayFromJSON(time64(TimeUnit::MICRO), times_us); + auto arr_us2 = ArrayFromJSON(time64(TimeUnit::MICRO), times_us2); + auto arr_ns = ArrayFromJSON(time64(TimeUnit::NANO), times_ns); + auto arr_ns2 = ArrayFromJSON(time64(TimeUnit::NANO), times_ns2); + + CheckScalarBinary(op, arr_s2, arr_s, + ArrayFromJSON(duration(TimeUnit::SECOND), seconds_between_time)); + CheckScalarBinary( + op, arr_ms2, arr_ms, + ArrayFromJSON(duration(TimeUnit::MILLI), milliseconds_between_time)); + CheckScalarBinary( + op, arr_us2, arr_us, + ArrayFromJSON(duration(TimeUnit::MICRO), microseconds_between_time)); + CheckScalarBinary(op, arr_ns2, arr_ns, + ArrayFromJSON(duration(TimeUnit::NANO), nanoseconds_between_time)); + + CheckScalarBinary(op, arr_s, arr_s, ArrayFromJSON(duration(TimeUnit::SECOND), zeros)); + CheckScalarBinary(op, arr_ms, arr_ms, + ArrayFromJSON(duration(TimeUnit::MILLI), zeros)); + CheckScalarBinary(op, arr_us, arr_us, + ArrayFromJSON(duration(TimeUnit::MICRO), zeros)); + CheckScalarBinary(op, arr_ns, arr_ns, ArrayFromJSON(duration(TimeUnit::NANO), zeros)); + + auto seconds_3 = ArrayFromJSON(time32(TimeUnit::SECOND), R"([3, null])"); + auto milliseconds_2k = ArrayFromJSON(time32(TimeUnit::MILLI), R"([1999, null])"); + auto milliseconds_1k = ArrayFromJSON(duration(TimeUnit::MILLI), R"([1001, null])"); + auto microseconds_2M = ArrayFromJSON(time64(TimeUnit::MICRO), R"([1999999, null])"); + auto microseconds_1M = ArrayFromJSON(duration(TimeUnit::MICRO), R"([1000001, null])"); + CheckScalarBinary(op, seconds_3, milliseconds_2k, milliseconds_1k); + CheckScalarBinary(op, seconds_3, microseconds_2M, microseconds_1M); + } +} + TEST_F(ScalarTemporalTest, TestTemporalDifferenceWeeks) { auto raw_days = ArrayFromJSON(timestamp(TimeUnit::SECOND), R"([ "2021-08-09", "2021-08-10", "2021-08-11", "2021-08-12", "2021-08-13", "2021-08-14", "2021-08-15",