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