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

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


The following commit(s) were added to refs/heads/master by this push:
     new b3eaf0c6cb API, Core: Move micros and days conversions to DateTimeUtil 
(#6199)
b3eaf0c6cb is described below

commit b3eaf0c6cb9cf6357a925c7443baadd54515a971
Author: Anton Okolnychyi <[email protected]>
AuthorDate: Wed Nov 16 23:42:01 2022 -0800

    API, Core: Move micros and days conversions to DateTimeUtil (#6199)
---
 .../java/org/apache/iceberg/transforms/Dates.java  | 27 ++++-------
 .../org/apache/iceberg/transforms/Timestamps.java  | 32 +++++--------
 .../java/org/apache/iceberg/util/DateTimeUtil.java | 55 ++++++++++++++++++++++
 .../org/apache/iceberg/util/TestDateTimeUtil.java  |  0
 4 files changed, 77 insertions(+), 37 deletions(-)

diff --git a/api/src/main/java/org/apache/iceberg/transforms/Dates.java 
b/api/src/main/java/org/apache/iceberg/transforms/Dates.java
index 0543a0c891..9128f6c53f 100644
--- a/api/src/main/java/org/apache/iceberg/transforms/Dates.java
+++ b/api/src/main/java/org/apache/iceberg/transforms/Dates.java
@@ -18,9 +18,6 @@
  */
 package org.apache.iceberg.transforms;
 
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.ZoneOffset;
 import java.time.temporal.ChronoUnit;
 import org.apache.iceberg.expressions.BoundPredicate;
 import org.apache.iceberg.expressions.BoundTransform;
@@ -30,6 +27,7 @@ import org.apache.iceberg.expressions.UnboundPredicate;
 import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
 import org.apache.iceberg.types.Type;
 import org.apache.iceberg.types.Types;
+import org.apache.iceberg.util.DateTimeUtil;
 import org.apache.iceberg.util.SerializableFunction;
 
 enum Dates implements Transform<Integer, Integer> {
@@ -50,24 +48,19 @@ enum Dates implements Transform<Integer, Integer> {
         return null;
       }
 
-      if (granularity == ChronoUnit.DAYS) {
-        return days;
-      }
-
-      if (days >= 0) {
-        LocalDate date = EPOCH.plusDays(days);
-        return (int) granularity.between(EPOCH, date);
-      } else {
-        // add 1 day to the value to account for the case where there is 
exactly 1 unit between the
-        // date and epoch because the result will always be decremented.
-        LocalDate date = EPOCH.plusDays(days + 1);
-        return (int) granularity.between(EPOCH, date) - 1;
+      switch (granularity) {
+        case YEARS:
+          return DateTimeUtil.daysToYears(days);
+        case MONTHS:
+          return DateTimeUtil.daysToMonths(days);
+        case DAYS:
+          return days;
+        default:
+          throw new UnsupportedOperationException("Unsupported time unit: " + 
granularity);
       }
     }
   }
 
-  private static final LocalDate EPOCH =
-      Instant.ofEpochSecond(0).atOffset(ZoneOffset.UTC).toLocalDate();
   private final ChronoUnit granularity;
   private final String name;
   private final Apply apply;
diff --git a/api/src/main/java/org/apache/iceberg/transforms/Timestamps.java 
b/api/src/main/java/org/apache/iceberg/transforms/Timestamps.java
index e63ee39ac1..b148c23a5a 100644
--- a/api/src/main/java/org/apache/iceberg/transforms/Timestamps.java
+++ b/api/src/main/java/org/apache/iceberg/transforms/Timestamps.java
@@ -18,9 +18,6 @@
  */
 package org.apache.iceberg.transforms;
 
-import java.time.Instant;
-import java.time.OffsetDateTime;
-import java.time.ZoneOffset;
 import java.time.temporal.ChronoUnit;
 import org.apache.iceberg.expressions.BoundPredicate;
 import org.apache.iceberg.expressions.BoundTransform;
@@ -30,6 +27,7 @@ import org.apache.iceberg.expressions.UnboundPredicate;
 import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
 import org.apache.iceberg.types.Type;
 import org.apache.iceberg.types.Types;
+import org.apache.iceberg.util.DateTimeUtil;
 import org.apache.iceberg.util.SerializableFunction;
 
 enum Timestamps implements Transform<Long, Integer> {
@@ -51,27 +49,21 @@ enum Timestamps implements Transform<Long, Integer> {
         return null;
       }
 
-      if (timestampMicros >= 0) {
-        OffsetDateTime timestamp =
-            Instant.ofEpochSecond(
-                    Math.floorDiv(timestampMicros, 1_000_000),
-                    Math.floorMod(timestampMicros, 1_000_000) * 1000)
-                .atOffset(ZoneOffset.UTC);
-        return (int) granularity.between(EPOCH, timestamp);
-      } else {
-        // add 1 micro to the value to account for the case where there is 
exactly 1 unit between
-        // the timestamp and epoch because the result will always be 
decremented.
-        OffsetDateTime timestamp =
-            Instant.ofEpochSecond(
-                    Math.floorDiv(timestampMicros, 1_000_000),
-                    Math.floorMod(timestampMicros + 1, 1_000_000) * 1000)
-                .atOffset(ZoneOffset.UTC);
-        return (int) granularity.between(EPOCH, timestamp) - 1;
+      switch (granularity) {
+        case YEARS:
+          return DateTimeUtil.microsToYears(timestampMicros);
+        case MONTHS:
+          return DateTimeUtil.microsToMonths(timestampMicros);
+        case DAYS:
+          return DateTimeUtil.microsToDays(timestampMicros);
+        case HOURS:
+          return DateTimeUtil.microsToHours(timestampMicros);
+        default:
+          throw new UnsupportedOperationException("Unsupported time unit: " + 
granularity);
       }
     }
   }
 
-  private static final OffsetDateTime EPOCH = 
Instant.ofEpochSecond(0).atOffset(ZoneOffset.UTC);
   private final ChronoUnit granularity;
   private final String name;
   private final SerializableFunction<Long, Integer> apply;
diff --git a/core/src/main/java/org/apache/iceberg/util/DateTimeUtil.java 
b/api/src/main/java/org/apache/iceberg/util/DateTimeUtil.java
similarity index 70%
rename from core/src/main/java/org/apache/iceberg/util/DateTimeUtil.java
rename to api/src/main/java/org/apache/iceberg/util/DateTimeUtil.java
index 29214ff883..a2f5301f44 100644
--- a/core/src/main/java/org/apache/iceberg/util/DateTimeUtil.java
+++ b/api/src/main/java/org/apache/iceberg/util/DateTimeUtil.java
@@ -34,6 +34,7 @@ public class DateTimeUtil {
   public static final OffsetDateTime EPOCH = 
Instant.ofEpochSecond(0).atOffset(ZoneOffset.UTC);
   public static final LocalDate EPOCH_DAY = EPOCH.toLocalDate();
   public static final long MICROS_PER_MILLIS = 1000L;
+  public static final long MICROS_PER_SECOND = 1_000_000L;
 
   public static LocalDate dateFromDays(int daysFromEpoch) {
     return ChronoUnit.DAYS.addTo(EPOCH_DAY, daysFromEpoch);
@@ -133,4 +134,58 @@ public class DateTimeUtil {
     return microsFromTimestamp(
         LocalDateTime.parse(timestampString, 
DateTimeFormatter.ISO_LOCAL_DATE_TIME));
   }
+
+  public static int daysToYears(int days) {
+    return convertDays(days, ChronoUnit.YEARS);
+  }
+
+  public static int daysToMonths(int days) {
+    return convertDays(days, ChronoUnit.MONTHS);
+  }
+
+  private static int convertDays(int days, ChronoUnit granularity) {
+    if (days >= 0) {
+      LocalDate date = EPOCH_DAY.plusDays(days);
+      return (int) granularity.between(EPOCH_DAY, date);
+    } else {
+      // add 1 day to the value to account for the case where there is exactly 
1 unit between the
+      // date and epoch because the result will always be decremented.
+      LocalDate date = EPOCH_DAY.plusDays(days + 1);
+      return (int) granularity.between(EPOCH_DAY, date) - 1;
+    }
+  }
+
+  public static int microsToYears(long micros) {
+    return convertMicros(micros, ChronoUnit.YEARS);
+  }
+
+  public static int microsToMonths(long micros) {
+    return convertMicros(micros, ChronoUnit.MONTHS);
+  }
+
+  public static int microsToDays(long micros) {
+    return convertMicros(micros, ChronoUnit.DAYS);
+  }
+
+  public static int microsToHours(long micros) {
+    return convertMicros(micros, ChronoUnit.HOURS);
+  }
+
+  private static int convertMicros(long micros, ChronoUnit granularity) {
+    if (micros >= 0) {
+      long epochSecond = Math.floorDiv(micros, MICROS_PER_SECOND);
+      long nanoAdjustment = Math.floorMod(micros, MICROS_PER_SECOND) * 1000;
+      return (int) granularity.between(EPOCH, toOffsetDateTime(epochSecond, 
nanoAdjustment));
+    } else {
+      // add 1 micro to the value to account for the case where there is 
exactly 1 unit between
+      // the timestamp and epoch because the result will always be decremented.
+      long epochSecond = Math.floorDiv(micros, MICROS_PER_SECOND);
+      long nanoAdjustment = Math.floorMod(micros + 1, MICROS_PER_SECOND) * 
1000;
+      return (int) granularity.between(EPOCH, toOffsetDateTime(epochSecond, 
nanoAdjustment)) - 1;
+    }
+  }
+
+  private static OffsetDateTime toOffsetDateTime(long epochSecond, long 
nanoAdjustment) {
+    return Instant.ofEpochSecond(epochSecond, 
nanoAdjustment).atOffset(ZoneOffset.UTC);
+  }
 }
diff --git a/core/src/test/java/org/apache/iceberg/util/TestDateTimeUtil.java 
b/api/src/test/java/org/apache/iceberg/util/TestDateTimeUtil.java
similarity index 100%
rename from core/src/test/java/org/apache/iceberg/util/TestDateTimeUtil.java
rename to api/src/test/java/org/apache/iceberg/util/TestDateTimeUtil.java

Reply via email to