rok commented on code in PR #12528:
URL: https://github.com/apache/arrow/pull/12528#discussion_r865137124


##########
cpp/src/arrow/compute/kernels/temporal_internal.h:
##########
@@ -119,19 +152,93 @@ struct ZonedLocalizer {
     return tz->to_local(sys_time<Duration>(Duration{t}));
   }
 
-  template <typename Duration>
-  Duration ConvertLocalToSys(Duration t, Status* st) const {
+  template <typename Duration, typename Unit>
+  Duration FloorTimePoint(const int64_t t, const RoundTemporalOptions* 
options) const {
+    local_time<Duration> lt = tz->to_local(sys_time<Duration>(Duration{t}));
+    const Unit d = floor<Unit>(lt).time_since_epoch();
+    Unit d2;
+
+    if (options->multiple == 1) {
+      d2 = d;
+    } else {
+      const Unit unit = Unit{options->multiple};
+      d2 = (d.count() >= 0) ? d / unit * unit : (d - unit + Unit{1}) / unit * 
unit;
+    }
+
     try {
-      return zoned_time<Duration>{tz, local_time<Duration>(t)}
+      return zoned_time<Duration>(tz, 
local_time<Duration>(duration_cast<Duration>(d2)))
           .get_sys_time()
           .time_since_epoch();
-    } catch (const arrow_vendored::date::nonexistent_local_time& e) {
-      *st = Status::Invalid("Local time does not exist: ", e.what());
-      return Duration{0};
-    } catch (const arrow_vendored::date::ambiguous_local_time& e) {
-      *st = Status::Invalid("Local time is ambiguous: ", e.what());
-      return Duration{0};
+    } catch (const arrow_vendored::date::ambiguous_local_time&) {
+      // In case we hit an ambiguous period we round to a time multiple just 
prior,
+      // convert to UTC and add the time unit we're rounding to.
+      const arrow_vendored::date::local_info li =
+          tz->get_info(local_time<Duration>(duration_cast<Duration>(d2)));
+
+      const Duration t2 =
+          zoned_time<Duration>(
+              tz, local_time<Duration>(duration_cast<Duration>(d2 - 
li.second.offset)))
+              .get_sys_time()
+              .time_since_epoch();
+      const Unit unit = Unit{options->multiple};
+      const Unit t3 =
+          (t2.count() >= 0) ? t2 / unit * unit : (t2 - unit + Unit{1}) / unit 
* unit;
+      const Duration t4 = duration_cast<Duration>(t3 + li.first.offset);
+      if (t < t4.count()) {
+        return duration_cast<Duration>(t3 + li.second.offset);
+      }
+      return duration_cast<Duration>(t4);
+    } catch (const arrow_vendored::date::nonexistent_local_time&) {
+      // In case we hit a nonexistent period we calculate the duration between 
the
+      // start of nonexistent period and rounded to moment in UTC 
(nonexistent_offset).
+      // We then floor the beginning of the nonexisting period in local time 
and add
+      // nonexistent_offset to that time point in UTC.
+      const arrow_vendored::date::local_info li =
+          tz->get_info(local_time<Duration>(duration_cast<Duration>(d2)));
+
+      const Duration t2 =
+          zoned_time<Duration>(tz, 
local_time<Duration>(duration_cast<Duration>(d2)),
+                               arrow_vendored::date::choose::earliest)
+              .get_sys_time()
+              .time_since_epoch();
+      const Duration nonexistent_offset = duration_cast<Duration>(t2 - d2);
+
+      const Unit unit = Unit{options->multiple};
+      const Unit t3 =
+          (t2.count() >= 0) ? t2 / unit * unit : (t2 - unit + Unit{1}) / unit 
* unit;
+      return duration_cast<Duration>(t3 + li.second.offset) + 
nonexistent_offset;
+    }
+  }
+
+  template <typename Duration, typename Unit>
+  Duration CeilTimePoint(const int64_t t, const RoundTemporalOptions* options) 
const {
+    const Duration d = FloorTimePoint<Duration, Unit>(t, options);
+    if (d.count() == t) {
+      return d;
+    }
+    return FloorTimePoint<Duration, Unit>(
+        t + duration_cast<Duration>(Unit{options->multiple}).count(), options);

Review Comment:
   There definitely is a more efficient way however this PR doesn't change the 
current situation and I optimisation more logically fits into scope of 
https://github.com/apache/arrow/pull/13043. 



-- 
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