diff --git a/vertx-pg-client/src/main/java/io/vertx/pgclient/data/Interval.java b/vertx-pg-client/src/main/java/io/vertx/pgclient/data/Interval.java index ea3fc1989..2df79576f 100644 --- a/vertx-pg-client/src/main/java/io/vertx/pgclient/data/Interval.java +++ b/vertx-pg-client/src/main/java/io/vertx/pgclient/data/Interval.java @@ -1,7 +1,6 @@ package io.vertx.pgclient.data; -import io.vertx.codegen.annotations.DataObject; -import io.vertx.core.json.JsonObject; +import java.time.Duration; /** * Postgres Interval is date and time based @@ -84,6 +83,35 @@ public static Interval of(int years) { return new Interval(years); } + /** + * Creates an instance from the given {@link Duration}. + *

+ * The conversion algorithm assumes a year last 12 months and a month lasts 30 days, as Postgres does and ISO 8601 suggests. + * + * @param duration the value to convert + * @return a new instance of {@link Interval} + */ + public static Interval of(Duration duration) { + long totalSeconds = duration.getSeconds(); + + int years = (int) (totalSeconds / 31104000); + long remainder = totalSeconds % 31104000; + + int months = (int) (remainder / 2592000); + remainder = totalSeconds % 2592000; + + int days = (int) (remainder / 86400); + remainder = remainder % 86400; + + int hours = (int) (remainder / 3600); + remainder = remainder % 3600; + + int minutes = (int) (remainder / 60); + remainder = remainder % 60; + + return new Interval(years, months, days, hours, minutes, (int) remainder, duration.getNano() / 1000); + } + public Interval years(int years) { this.years = years; return this; @@ -203,7 +231,25 @@ public int hashCode() { @Override public String toString() { - return "Interval( " + years + " years " + months + " months " + days + " days " + hours + " hours " + - minutes + " minutes " + seconds + (microseconds == 0 ? "" : "." + Math.abs(microseconds)) + " seconds )"; + return "Interval( " + + years + " years " + + months + " months " + + days + " days " + + hours + " hours " + + minutes + " minutes " + + seconds + " seconds " + + microseconds + " microseconds )"; + } + + /** + * Convert this interval to an instance of {@link Duration}. + *

+ * The conversion algorithm assumes a year last 12 months and a month lasts 30 days, as Postgres does and ISO 8601 suggests. + * + * @return an instance of {@link Duration} representing the same amount of time as this interval + */ + public Duration toDuration() { + return Duration.ofSeconds(((((years * 12L + months) * 30L + days) * 24L + hours) * 60 + minutes) * 60 + seconds) + .plusNanos(microseconds * 1000L); } } diff --git a/vertx-pg-client/src/test/java/io/vertx/pgclient/data/IntervalTest.java b/vertx-pg-client/src/test/java/io/vertx/pgclient/data/IntervalTest.java new file mode 100644 index 000000000..bf7a89dbd --- /dev/null +++ b/vertx-pg-client/src/test/java/io/vertx/pgclient/data/IntervalTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011-2024 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + */ + +package io.vertx.pgclient.data; + +import org.junit.Test; + +import java.time.Duration; +import java.time.LocalDateTime; + +import static java.time.temporal.ChronoUnit.MICROS; +import static org.junit.Assert.assertEquals; + +public class IntervalTest { + + @Test + public void testFromDuration() { + assertEquals(Interval.of(), Interval.of(Duration.ZERO)); + + assertEquals( + Interval.of(0, 0, 0, 0, 0, -1, 999999), + Interval.of(Duration.ZERO.minus(1, MICROS))); + + assertEquals( + Interval.of(0, 0, -15, 0, -12, -3), + Interval.of(Duration.ofDays(-15) + .minusMinutes(12) + .minusSeconds(3))); + + assertEquals( + Interval.of(1, 3, 14, 3, 55, 5, 463123), + Interval.of(Duration.ofDays(12 * 30 + 3 * 30 + 14) + .plusHours(3) + .plusMinutes(55) + .plusSeconds(5) + .plusNanos(463123 * 1000))); + } + + @Test + public void testToDuration() { + assertEquals(Duration.ZERO, Interval.of().toDuration()); + + assertEquals( + Duration.ZERO.minus(1, MICROS), + Interval.of(0, 0, 0, 0, 0, 0, -1).toDuration()); + + assertEquals( + Duration.ofDays(-15) + .minusMinutes(12) + .minusSeconds(3), + Interval.of(0, 0, -15, 0, -12, -3).toDuration()); + + assertEquals( + Duration.between( + LocalDateTime.of(2024, 2, 1, 13, 30), + LocalDateTime.of(2024, 3, 1, 12, 0)), + Interval.of(0, 0, 29, -1, -30, 0, 0).toDuration()); + } +}