lidavidm commented on a change in pull request #10960:
URL: https://github.com/apache/arrow/pull/10960#discussion_r710133559



##########
File path: cpp/src/arrow/compute/kernels/scalar_temporal.cc
##########
@@ -830,6 +897,167 @@ struct ISOCalendar {
   }
 };
 
+// ----------------------------------------------------------------------
+// Compute boundary crossings between two timestamps
+
+template <typename Duration, typename Localizer>
+struct YearsBetween {
+  YearsBetween(const FunctionOptions* options, Localizer&& localizer)
+      : localizer_(std::move(localizer)) {}
+
+  template <typename T, typename Arg0, typename Arg1>
+  T Call(KernelContext*, Arg0 arg0, Arg1 arg1, Status*) const {
+    year_month_day from(
+        floor<days>(localizer_.template ConvertTimePoint<Duration>(arg0)));
+    year_month_day to(floor<days>(localizer_.template 
ConvertTimePoint<Duration>(arg1)));
+    return static_cast<T>((to.year() - from.year()).count());
+  }
+
+  Localizer localizer_;
+};
+
+template <typename Duration, typename Localizer>
+struct QuartersBetween {
+  QuartersBetween(const FunctionOptions* options, Localizer&& localizer)
+      : localizer_(std::move(localizer)) {}
+
+  static int64_t GetQuarters(const year_month_day& ymd) {
+    return static_cast<int64_t>(static_cast<int32_t>(ymd.year())) * 4 +
+           (static_cast<uint32_t>(ymd.month()) - 1) / 3;
+  }
+
+  template <typename T, typename Arg0, typename Arg1>
+  T Call(KernelContext*, Arg0 arg0, Arg1 arg1, Status*) const {
+    year_month_day from_ymd(
+        floor<days>(localizer_.template ConvertTimePoint<Duration>(arg0)));
+    year_month_day to_ymd(
+        floor<days>(localizer_.template ConvertTimePoint<Duration>(arg1)));
+    int64_t from_quarters = GetQuarters(from_ymd);
+    int64_t to_quarters = GetQuarters(to_ymd);
+    return static_cast<T>(to_quarters - from_quarters);
+  }
+
+  Localizer localizer_;
+};
+
+template <typename Duration, typename Localizer>
+struct MonthsBetween {
+  MonthsBetween(const FunctionOptions* options, Localizer&& localizer)
+      : localizer_(std::move(localizer)) {}
+
+  template <typename T, typename Arg0, typename Arg1>
+  T Call(KernelContext*, Arg0 arg0, Arg1 arg1, Status*) const {
+    year_month_day from(
+        floor<days>(localizer_.template ConvertTimePoint<Duration>(arg0)));
+    year_month_day to(floor<days>(localizer_.template 
ConvertTimePoint<Duration>(arg1)));
+    return static_cast<T>(
+        (year_month(to.year(), to.month()) - year_month(from.year(), 
from.month()))
+            .count());
+  }
+
+  Localizer localizer_;
+};
+
+template <typename Duration, typename Localizer>
+struct WeeksBetween {
+  WeeksBetween(const DayOfWeekOptions* options, Localizer&& localizer)
+      : week_start_(options->week_start), localizer_(std::move(localizer)) {}
+
+  template <typename T, typename Arg0, typename Arg1>
+  T Call(KernelContext*, Arg0 arg0, Arg1 arg1, Status*) const {
+    auto from = floor<days>(localizer_.template 
ConvertTimePoint<Duration>(arg0));
+    auto to = floor<days>(localizer_.template 
ConvertTimePoint<Duration>(arg1));
+    const T days_between = static_cast<T>((to - from).count());
+    const T whole_weeks = days_between / 7;
+    const T days_remainder = days_between % 7;
+    // We are counting week boundaries, so there may be one extra week
+    if (days_remainder > 0) {
+      const weekday from_dow(from);
+      const weekday start_of_week(week_start_);
+      const int64_t days = (start_of_week - from_dow).count();
+      if (days > 0 && days <= days_remainder) {
+        return whole_weeks + 1;
+      }
+    } else if (days_remainder < 0) {
+      const weekday from_dow(to);
+      const weekday start_of_week(week_start_);
+      const int64_t days = (start_of_week - from_dow).count();
+      if (days > 0 && days <= -days_remainder) {
+        return whole_weeks - 1;
+      }
+    }
+    return whole_weeks;
+  }
+
+  // Monday = 1, Sunday = 7
+  uint32_t week_start_;
+  Localizer localizer_;
+};
+
+template <typename Duration, typename Localizer>
+struct DayTimeBetween {
+  DayTimeBetween(const FunctionOptions* options, Localizer&& localizer)
+      : localizer_(std::move(localizer)) {}
+
+  template <typename T, typename Arg0, typename Arg1>
+  T Call(KernelContext*, Arg0 arg0, Arg1 arg1, Status*) const {
+    static_assert(std::is_same<T, 
DayTimeIntervalType::DayMilliseconds>::value, "");
+    auto from = localizer_.template ConvertTimePoint<Duration>(arg0);
+    auto to = localizer_.template ConvertTimePoint<Duration>(arg1);
+    const int32_t num_days =
+        static_cast<int32_t>((floor<days>(to) - floor<days>(from)).count());
+    auto from_time = static_cast<int32_t>(
+        std::chrono::duration_cast<std::chrono::milliseconds>(from - 
floor<days>(from))
+            .count());
+    auto to_time = static_cast<int32_t>(
+        std::chrono::duration_cast<std::chrono::milliseconds>(to - 
floor<days>(to))
+            .count());
+    const int32_t num_millis = to_time - from_time;
+    return DayTimeIntervalType::DayMilliseconds{num_days, num_millis};

Review comment:
       You mean, why didn't I add kernels for MonthsBetween and MonthDayNano 
between? I can add those.

##########
File path: cpp/src/arrow/compute/kernels/scalar_temporal.cc
##########
@@ -192,6 +195,60 @@ struct TemporalComponentExtract
   }
 };
 
+Status CheckTimezones(const ExecBatch& batch) {
+  const auto& timezone = GetInputTimezone(batch.values[0]);
+  for (int i = 1; i < batch.num_values(); i++) {
+    const auto& other_timezone = GetInputTimezone(batch.values[i]);
+    if (other_timezone != timezone) {
+      return Status::TypeError("Got differing time zone '", other_timezone,
+                               "' for argument ", i + 1, "; expected '", 
timezone, "'");
+    }

Review comment:
       What would it mean to find the difference between two timestamps in 
different timezones? I suppose we could compute the difference in UTC, but then 
you'd get different results (as compared to working with local timestamps) if 
you had a DST transition in the covered time.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to