You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by li...@apache.org on 2022/04/05 14:37:49 UTC

[arrow] branch master updated: ARROW-16060: [C++] subtract_checked support for timestamp("s") and date32

This is an automated email from the ASF dual-hosted git repository.

lidavidm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new 8eaa995f0e ARROW-16060: [C++] subtract_checked support for timestamp("s") and date32
8eaa995f0e is described below

commit 8eaa995f0e8de2ebc0f2b09648ef033f01f9f959
Author: Rok <ro...@mihevc.org>
AuthorDate: Tue Apr 5 10:37:27 2022 -0400

    ARROW-16060: [C++] subtract_checked support for timestamp("s") and date32
    
    This is to resolve [ARROW-16060](https://issues.apache.org/jira/browse/ARROW-16060).
    
    Closes #12774 from rok/ARROW-16060
    
    Authored-by: Rok <ro...@mihevc.org>
    Signed-off-by: David Li <li...@gmail.com>
---
 cpp/src/arrow/compute/kernels/codegen_internal.cc  | 24 ++++--
 cpp/src/arrow/compute/kernels/codegen_internal.h   |  3 +-
 .../arrow/compute/kernels/codegen_internal_test.cc | 98 ++++++++++++++--------
 cpp/src/arrow/compute/kernels/scalar_arithmetic.cc | 10 +--
 .../arrow/compute/kernels/scalar_temporal_test.cc  | 78 +++++++++++++++++
 5 files changed, 165 insertions(+), 48 deletions(-)

diff --git a/cpp/src/arrow/compute/kernels/codegen_internal.cc b/cpp/src/arrow/compute/kernels/codegen_internal.cc
index 26c12ebf59..b31ef408b1 100644
--- a/cpp/src/arrow/compute/kernels/codegen_internal.cc
+++ b/cpp/src/arrow/compute/kernels/codegen_internal.cc
@@ -214,45 +214,53 @@ std::shared_ptr<DataType> CommonNumeric(const ValueDescr* begin, size_t count) {
   return int8();
 }
 
-TimeUnit::type CommonTemporalResolution(const ValueDescr* begin, size_t count) {
-  TimeUnit::type finest_unit = TimeUnit::SECOND;
+bool CommonTemporalResolution(const ValueDescr* begin, size_t count,
+                              TimeUnit::type* finest_unit) {
+  bool is_time_unit = false;
+  *finest_unit = TimeUnit::SECOND;
   const ValueDescr* end = begin + count;
   for (auto it = begin; it != end; it++) {
     auto id = it->type->id();
     switch (id) {
       case Type::DATE32: {
         // Date32's unit is days, but the coarsest we have is seconds
+        is_time_unit = true;
         continue;
       }
       case Type::DATE64: {
-        finest_unit = std::max(finest_unit, TimeUnit::MILLI);
+        *finest_unit = std::max(*finest_unit, TimeUnit::MILLI);
+        is_time_unit = true;
         continue;
       }
       case Type::TIMESTAMP: {
         const auto& ty = checked_cast<const TimestampType&>(*it->type);
-        finest_unit = std::max(finest_unit, ty.unit());
+        *finest_unit = std::max(*finest_unit, ty.unit());
+        is_time_unit = true;
         continue;
       }
       case Type::DURATION: {
         const auto& ty = checked_cast<const DurationType&>(*it->type);
-        finest_unit = std::max(finest_unit, ty.unit());
+        *finest_unit = std::max(*finest_unit, ty.unit());
+        is_time_unit = true;
         continue;
       }
       case Type::TIME32: {
         const auto& ty = checked_cast<const Time32Type&>(*it->type);
-        finest_unit = std::max(finest_unit, ty.unit());
+        *finest_unit = std::max(*finest_unit, ty.unit());
+        is_time_unit = true;
         continue;
       }
       case Type::TIME64: {
         const auto& ty = checked_cast<const Time64Type&>(*it->type);
-        finest_unit = std::max(finest_unit, ty.unit());
+        *finest_unit = std::max(*finest_unit, ty.unit());
+        is_time_unit = true;
         continue;
       }
       default:
         continue;
     }
   }
-  return finest_unit;
+  return is_time_unit;
 }
 
 std::shared_ptr<DataType> CommonTemporal(const ValueDescr* begin, size_t count) {
diff --git a/cpp/src/arrow/compute/kernels/codegen_internal.h b/cpp/src/arrow/compute/kernels/codegen_internal.h
index ff7b9161fe..fa50427bc3 100644
--- a/cpp/src/arrow/compute/kernels/codegen_internal.h
+++ b/cpp/src/arrow/compute/kernels/codegen_internal.h
@@ -1394,7 +1394,8 @@ ARROW_EXPORT
 std::shared_ptr<DataType> CommonTemporal(const ValueDescr* begin, size_t count);
 
 ARROW_EXPORT
-TimeUnit::type CommonTemporalResolution(const ValueDescr* begin, size_t count);
+bool CommonTemporalResolution(const ValueDescr* begin, size_t count,
+                              TimeUnit::type* finest_unit);
 
 ARROW_EXPORT
 std::shared_ptr<DataType> CommonBinary(const ValueDescr* begin, size_t count);
diff --git a/cpp/src/arrow/compute/kernels/codegen_internal_test.cc b/cpp/src/arrow/compute/kernels/codegen_internal_test.cc
index 46d31c8ae4..6fb84cf55b 100644
--- a/cpp/src/arrow/compute/kernels/codegen_internal_test.cc
+++ b/cpp/src/arrow/compute/kernels/codegen_internal_test.cc
@@ -137,6 +137,8 @@ TEST(TestDispatchBest, CommonTemporal) {
   args = {timestamp(TimeUnit::SECOND, "UTC"), timestamp(TimeUnit::NANO, "UTC")};
   AssertTypeEqual(timestamp(TimeUnit::NANO, "UTC"),
                   CommonTemporal(args.data(), args.size()));
+  args = {timestamp(TimeUnit::SECOND), date32()};
+  AssertTypeEqual(timestamp(TimeUnit::SECOND), CommonTemporal(args.data(), args.size()));
   args = {date32(), timestamp(TimeUnit::NANO)};
   AssertTypeEqual(timestamp(TimeUnit::NANO), CommonTemporal(args.data(), args.size()));
   args = {date64(), timestamp(TimeUnit::SECOND)};
@@ -161,53 +163,80 @@ TEST(TestDispatchBest, CommonTemporal) {
 TEST(TestDispatchBest, CommonTemporalResolution) {
   std::vector<ValueDescr> args;
   std::string tz = "Pacific/Marquesas";
+  TimeUnit::type ty;
 
   args = {date32(), date32()};
-  ASSERT_EQ(TimeUnit::SECOND, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::SECOND, ty);
   args = {date32(), date64()};
-  ASSERT_EQ(TimeUnit::MILLI, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MILLI, ty);
+  args = {date32(), timestamp(TimeUnit::SECOND)};
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::SECOND, ty);
   args = {time32(TimeUnit::MILLI), date32()};
-  ASSERT_EQ(TimeUnit::MILLI, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MILLI, ty);
   args = {time32(TimeUnit::MILLI), time32(TimeUnit::SECOND)};
-  ASSERT_EQ(TimeUnit::MILLI, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MILLI, ty);
   args = {time32(TimeUnit::MILLI), time64(TimeUnit::MICRO)};
-  ASSERT_EQ(TimeUnit::MICRO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MICRO, ty);
   args = {time64(TimeUnit::NANO), time64(TimeUnit::MICRO)};
-  ASSERT_EQ(TimeUnit::NANO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::NANO, ty);
   args = {duration(TimeUnit::MILLI), duration(TimeUnit::MICRO)};
-  ASSERT_EQ(TimeUnit::MICRO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MICRO, ty);
   args = {duration(TimeUnit::MILLI), date32()};
-  ASSERT_EQ(TimeUnit::MILLI, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MILLI, ty);
   args = {date64(), duration(TimeUnit::SECOND)};
-  ASSERT_EQ(TimeUnit::MILLI, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MILLI, ty);
   args = {duration(TimeUnit::SECOND), time32(TimeUnit::SECOND)};
-  ASSERT_EQ(TimeUnit::SECOND, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::SECOND, ty);
   args = {duration(TimeUnit::SECOND), time64(TimeUnit::NANO)};
-  ASSERT_EQ(TimeUnit::NANO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::NANO, ty);
   args = {time64(TimeUnit::MICRO), duration(TimeUnit::NANO)};
-  ASSERT_EQ(TimeUnit::NANO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::NANO, ty);
   args = {timestamp(TimeUnit::SECOND, tz), timestamp(TimeUnit::MICRO)};
-  ASSERT_EQ(TimeUnit::MICRO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MICRO, ty);
   args = {date32(), timestamp(TimeUnit::MICRO, tz)};
-  ASSERT_EQ(TimeUnit::MICRO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MICRO, ty);
   args = {timestamp(TimeUnit::MICRO, tz), date64()};
-  ASSERT_EQ(TimeUnit::MICRO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MICRO, ty);
   args = {time32(TimeUnit::MILLI), timestamp(TimeUnit::MICRO, tz)};
-  ASSERT_EQ(TimeUnit::MICRO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MICRO, ty);
   args = {timestamp(TimeUnit::MICRO, tz), time64(TimeUnit::NANO)};
-  ASSERT_EQ(TimeUnit::NANO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::NANO, ty);
   args = {timestamp(TimeUnit::SECOND, tz), duration(TimeUnit::MILLI)};
-  ASSERT_EQ(TimeUnit::MILLI, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MILLI, ty);
   args = {timestamp(TimeUnit::SECOND, "UTC"), timestamp(TimeUnit::SECOND, tz)};
-  ASSERT_EQ(TimeUnit::SECOND, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::SECOND, ty);
   args = {time32(TimeUnit::MILLI), duration(TimeUnit::SECOND)};
-  ASSERT_EQ(TimeUnit::MILLI, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MILLI, ty);
   args = {time64(TimeUnit::MICRO), duration(TimeUnit::NANO)};
-  ASSERT_EQ(TimeUnit::NANO, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::NANO, ty);
   args = {duration(TimeUnit::SECOND), int64()};
-  ASSERT_EQ(TimeUnit::SECOND, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::SECOND, ty);
   args = {duration(TimeUnit::MILLI), timestamp(TimeUnit::SECOND, tz)};
-  ASSERT_EQ(TimeUnit::MILLI, CommonTemporalResolution(args.data(), args.size()));
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ASSERT_EQ(TimeUnit::MILLI, ty);
 }
 
 TEST(TestDispatchBest, ReplaceTemporalTypes) {
@@ -216,67 +245,68 @@ TEST(TestDispatchBest, ReplaceTemporalTypes) {
   TimeUnit::type ty;
 
   args = {date32(), date32()};
-  ty = CommonTemporalResolution(args.data(), args.size());
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
   ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, timestamp(TimeUnit::SECOND));
   AssertTypeEqual(args[1].type, timestamp(TimeUnit::SECOND));
 
   args = {date64(), time32(TimeUnit::SECOND)};
-  ty = CommonTemporalResolution(args.data(), args.size());
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
   ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, timestamp(TimeUnit::MILLI));
   AssertTypeEqual(args[1].type, time32(TimeUnit::MILLI));
 
   args = {duration(TimeUnit::SECOND), date64()};
-  ty = CommonTemporalResolution(args.data(), args.size());
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
   ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, duration(TimeUnit::MILLI));
   AssertTypeEqual(args[1].type, timestamp(TimeUnit::MILLI));
 
   args = {timestamp(TimeUnit::MICRO, tz), timestamp(TimeUnit::NANO)};
-  ty = CommonTemporalResolution(args.data(), args.size());
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
   ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, timestamp(TimeUnit::NANO, tz));
   AssertTypeEqual(args[1].type, timestamp(TimeUnit::NANO));
 
   args = {timestamp(TimeUnit::MICRO, tz), time64(TimeUnit::NANO)};
-  ty = CommonTemporalResolution(args.data(), args.size());
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
   ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, timestamp(TimeUnit::NANO, tz));
   AssertTypeEqual(args[1].type, time64(TimeUnit::NANO));
 
   args = {timestamp(TimeUnit::SECOND, tz), date64()};
-  ty = CommonTemporalResolution(args.data(), args.size());
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
   ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, timestamp(TimeUnit::MILLI, tz));
   AssertTypeEqual(args[1].type, timestamp(TimeUnit::MILLI));
 
   args = {timestamp(TimeUnit::SECOND, "UTC"), timestamp(TimeUnit::SECOND, tz)};
-  ty = CommonTemporalResolution(args.data(), args.size());
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
   ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, timestamp(TimeUnit::SECOND, "UTC"));
   AssertTypeEqual(args[1].type, timestamp(TimeUnit::SECOND, tz));
 
   args = {time32(TimeUnit::SECOND), duration(TimeUnit::SECOND)};
-  ty = CommonTemporalResolution(args.data(), args.size());
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
   ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, time32(TimeUnit::SECOND));
   AssertTypeEqual(args[1].type, duration(TimeUnit::SECOND));
 
   args = {time64(TimeUnit::MICRO), duration(TimeUnit::SECOND)};
-  ty = CommonTemporalResolution(args.data(), args.size());
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
   ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, time64(TimeUnit::MICRO));
   AssertTypeEqual(args[1].type, duration(TimeUnit::MICRO));
 
   args = {time32(TimeUnit::SECOND), duration(TimeUnit::NANO)};
-  ty = CommonTemporalResolution(args.data(), args.size());
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
   ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, time64(TimeUnit::NANO));
   AssertTypeEqual(args[1].type, duration(TimeUnit::NANO));
 
   args = {duration(TimeUnit::SECOND), int64()};
-  ReplaceTemporalTypes(CommonTemporalResolution(args.data(), args.size()), &args);
+  ASSERT_TRUE(CommonTemporalResolution(args.data(), args.size(), &ty));
+  ReplaceTemporalTypes(ty, &args);
   AssertTypeEqual(args[0].type, duration(TimeUnit::SECOND));
   AssertTypeEqual(args[1].type, int64());
 }
diff --git a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc
index bfafb6fcc1..103f8e66c5 100644
--- a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc
+++ b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc
@@ -1818,11 +1818,11 @@ struct ArithmeticFunction : ScalarFunction {
     // Only promote types for binary functions
     if (values->size() == 2) {
       ReplaceNullWithOtherType(values);
-
-      if (auto type = CommonTemporalResolution(values->data(), values->size())) {
-        ReplaceTemporalTypes(type, values);
-      } else if (auto type = CommonNumeric(*values)) {
-        ReplaceTypes(type, values);
+      TimeUnit::type finest_unit;
+      if (CommonTemporalResolution(values->data(), values->size(), &finest_unit)) {
+        ReplaceTemporalTypes(finest_unit, values);
+      } else if (auto numeric_type = CommonNumeric(*values)) {
+        ReplaceTypes(numeric_type, values);
       }
     }
 
diff --git a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc
index f2915951cb..a52d69c36c 100644
--- a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc
+++ b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc
@@ -1234,6 +1234,84 @@ TEST_F(ScalarTemporalTest, TestTemporalSubtractDate) {
   }
 }
 
+TEST_F(ScalarTemporalTest, TestTemporalSubtractTimestampAndDate) {
+  std::string seconds_between_date_and_time =
+      "[59, 84203, 3560, 12800, 3905, 7810, 11715, 15620, "
+      "19525, 23430, 27335, 31240, 35145, 0, 0, 3723, null]";
+  std::string milliseconds_between_date_and_time =
+      "[59000, 84203000, 3560000, 12800000, 3905000, 7810000, 11715000, 15620000, "
+      "19525000, 23430000, 27335000, 31240000, 35145000, 0, 0, 3723000, null]";
+  std::string microseconds_between_date_and_time =
+      "[59000000, 84203000000, 3560000000, 12800000000, 3905000000, 7810000000, "
+      "11715000000, 15620000000, 19525000000, 23430000000, 27335000000, 31240000000, "
+      "35145000000, 0, 0, 3723000000, null]";
+  std::string nanoseconds_between_date_and_time =
+      "[59000000000, 84203000000000, 3560000000000, 12800000000000, 3905000000000, "
+      "7810000000000, 11715000000000, 15620000000000, 19525000000000, 23430000000000, "
+      "27335000000000, 31240000000000, 35145000000000, 0, 0, 3723000000000, null]";
+  std::string seconds_between_date_and_time2 =
+      "[-59, -84203, -3560, -12800, -3905, -7810, -11715, -15620, "
+      "-19525, -23430, -27335, -31240, -35145, 0, 0, -3723, null]";
+  std::string milliseconds_between_date_and_time2 =
+      "[-59000, -84203000, -3560000, -12800000, -3905000, -7810000, -11715000,"
+      "-15620000, -19525000, -23430000, -27335000, -31240000, -35145000, 0, 0, "
+      "-3723000, null]";
+  std::string microseconds_between_date_and_time2 =
+      "[-59000000, -84203000000, -3560000000, -12800000000, -3905000000, -7810000000, "
+      "-11715000000, -15620000000, -19525000000, -23430000000, -27335000000,"
+      "-31240000000, -35145000000, 0, 0, -3723000000, null]";
+  std::string nanoseconds_between_date_and_time2 =
+      "[-59000000000, -84203000000000, -3560000000000, -12800000000000, "
+      "-3905000000000, -7810000000000, -11715000000000, -15620000000000, "
+      "-19525000000000, -23430000000000, -27335000000000, -31240000000000, "
+      "-35145000000000, 0, 0, -3723000000000, null]";
+
+  auto arr_date32s = ArrayFromJSON(date32(), date32s);
+  auto arr_date32s2 = ArrayFromJSON(date32(), date32s2);
+  auto arr_date64s = ArrayFromJSON(date64(), date64s);
+  auto arr_date64s2 = ArrayFromJSON(date64(), date64s2);
+  auto timestamp_s = ArrayFromJSON(timestamp(TimeUnit::SECOND), times_seconds_precision);
+  auto timestamp_ms = ArrayFromJSON(timestamp(TimeUnit::MILLI), times_seconds_precision);
+  auto timestamp_us = ArrayFromJSON(timestamp(TimeUnit::MICRO), times_seconds_precision);
+  auto timestamp_ns = ArrayFromJSON(timestamp(TimeUnit::NANO), times_seconds_precision);
+  auto between_s =
+      ArrayFromJSON(duration(TimeUnit::SECOND), seconds_between_date_and_time);
+  auto between_ms =
+      ArrayFromJSON(duration(TimeUnit::MILLI), milliseconds_between_date_and_time);
+  auto between_us =
+      ArrayFromJSON(duration(TimeUnit::MICRO), microseconds_between_date_and_time);
+  auto between_ns =
+      ArrayFromJSON(duration(TimeUnit::NANO), nanoseconds_between_date_and_time);
+  auto between_s2 =
+      ArrayFromJSON(duration(TimeUnit::SECOND), seconds_between_date_and_time2);
+  auto between_ms2 =
+      ArrayFromJSON(duration(TimeUnit::MILLI), milliseconds_between_date_and_time2);
+  auto between_us2 =
+      ArrayFromJSON(duration(TimeUnit::MICRO), microseconds_between_date_and_time2);
+  auto between_ns2 =
+      ArrayFromJSON(duration(TimeUnit::NANO), nanoseconds_between_date_and_time2);
+
+  for (auto op : {"subtract", "subtract_checked"}) {
+    CheckScalarBinary(op, timestamp_s, arr_date32s, between_s);
+    CheckScalarBinary(op, timestamp_ms, arr_date32s, between_ms);
+    CheckScalarBinary(op, timestamp_us, arr_date32s, between_us);
+    CheckScalarBinary(op, timestamp_ns, arr_date32s, between_ns);
+    CheckScalarBinary(op, timestamp_s, arr_date64s, between_ms);
+    CheckScalarBinary(op, timestamp_ms, arr_date64s, between_ms);
+    CheckScalarBinary(op, timestamp_us, arr_date64s, between_us);
+    CheckScalarBinary(op, timestamp_ns, arr_date64s, between_ns);
+
+    CheckScalarBinary(op, arr_date32s, timestamp_s, between_s2);
+    CheckScalarBinary(op, arr_date32s, timestamp_ms, between_ms2);
+    CheckScalarBinary(op, arr_date32s, timestamp_us, between_us2);
+    CheckScalarBinary(op, arr_date32s, timestamp_ns, between_ns2);
+    CheckScalarBinary(op, arr_date64s, timestamp_s, between_ms2);
+    CheckScalarBinary(op, arr_date64s, timestamp_ms, between_ms2);
+    CheckScalarBinary(op, arr_date64s, timestamp_us, between_us2);
+    CheckScalarBinary(op, arr_date64s, timestamp_ns, between_ns2);
+  }
+}
+
 TEST_F(ScalarTemporalTest, TestTemporalSubtractTimestamp) {
   for (auto op : {"subtract", "subtract_checked"}) {
     for (auto tz : {"", "UTC", "Pacific/Marquesas"}) {