rok commented on a change in pull request #10960:
URL: https://github.com/apache/arrow/pull/10960#discussion_r710162325
##########
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:
Feels like it would be good for completeness.
--
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]