diff --git a/hypersistence-utils-hibernate-62/src/main/java/io/hypersistence/utils/hibernate/type/range/PostgreSQLRangeType.java b/hypersistence-utils-hibernate-62/src/main/java/io/hypersistence/utils/hibernate/type/range/PostgreSQLRangeType.java
index 4ea38fee0..1c24c78fa 100644
--- a/hypersistence-utils-hibernate-62/src/main/java/io/hypersistence/utils/hibernate/type/range/PostgreSQLRangeType.java
+++ b/hypersistence-utils-hibernate-62/src/main/java/io/hypersistence/utils/hibernate/type/range/PostgreSQLRangeType.java
@@ -16,23 +16,21 @@
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.ZonedDateTime;
+import java.time.*;
import java.util.Properties;
/**
* Maps a {@link Range} object type to a PostgreSQL range
* column type.
*
- * Supported range types:
+ * Supported PostgreSQL range types:
*
- * - int4range
- * - int8range
- * - numrange
- * - tsrange
- * - tstzrange
- * - daterange
+ * - {@code int4range}. Use with Java type {@code Range}.
+ * - {@code int8range}. Use with Java type {@code Range}.
+ * - {@code numrange}. Use with Java type {@code Range}.
+ * - {@code tsrange}. Use with Java type {@code Range}.
+ * - {@code tstzrange}. Use with Java type {@code Range}, {@code Range} or {@code Range}.
+ * - {@code daterange}. Use with Java type {@code Range}.
*
*
* For more details about how to use it,
@@ -69,10 +67,11 @@ protected Range get(ResultSet rs, int position, SharedSessionContractImplementor
return null;
}
- String type = ReflectionUtils.invokeGetter(pgObject, "type");
+ String colType = ReflectionUtils.invokeGetter(pgObject, "type");
String value = ReflectionUtils.invokeGetter(pgObject, "value");
- switch (type) {
+ Class> rangeClass = rangeClass();
+ switch (colType) {
case "int4range":
return Range.integerRange(value);
case "int8range":
@@ -81,13 +80,25 @@ protected Range get(ResultSet rs, int position, SharedSessionContractImplementor
return Range.bigDecimalRange(value);
case "tsrange":
return Range.localDateTimeRange(value);
- case "tstzrange":
- return Range.zonedDateTimeRange(value);
+ case "tstzrange": {
+ if (rangeClass != null && Instant.class.isAssignableFrom(rangeClass)) {
+ return Range.instantRange(value);
+ }
+ if (rangeClass != null && OffsetDateTime.class.isAssignableFrom(rangeClass)) {
+ return Range.offsetDateTimeRange(value);
+ }
+ if (rangeClass != null && ZonedDateTime.class.isAssignableFrom(rangeClass)) {
+ return Range.zonedDateTimeRange(value);
+ }
+ throw new HibernateException(
+ new IllegalStateException("The database column type [" + colType + "] must be mapped to one of Java types: Range, Range or Range.")
+ );
+ }
case "daterange":
return Range.localDateRange(value);
default:
throw new HibernateException(
- new IllegalStateException("The range type [" + type + "] is not supported!")
+ new IllegalStateException("The database column type [" + colType + "] is not supported!")
);
}
}
@@ -116,6 +127,10 @@ private static String determineRangeType(Range> range) {
return "numrange";
} else if (clazz.equals(LocalDateTime.class)) {
return "tsrange";
+ } else if (clazz.equals(Instant.class)) {
+ return "tstzrange";
+ } else if (clazz.equals(OffsetDateTime.class)) {
+ return "tstzrange";
} else if (clazz.equals(ZonedDateTime.class)) {
return "tstzrange";
} else if (clazz.equals(LocalDate.class)) {
@@ -160,6 +175,12 @@ public Range fromStringValue(CharSequence sequence) throws HibernateException {
if(LocalDateTime.class.isAssignableFrom(clazz)) {
return Range.localDateTimeRange(stringValue);
}
+ if(Instant.class.isAssignableFrom(clazz)) {
+ return Range.instantRange(stringValue);
+ }
+ if(OffsetDateTime.class.isAssignableFrom(clazz)) {
+ return Range.offsetDateTimeRange(stringValue);
+ }
if(ZonedDateTime.class.isAssignableFrom(clazz)) {
return Range.zonedDateTimeRange(stringValue);
}
diff --git a/hypersistence-utils-hibernate-62/src/main/java/io/hypersistence/utils/hibernate/type/range/Range.java b/hypersistence-utils-hibernate-62/src/main/java/io/hypersistence/utils/hibernate/type/range/Range.java
index 75f94c65e..1496b46f9 100644
--- a/hypersistence-utils-hibernate-62/src/main/java/io/hypersistence/utils/hibernate/type/range/Range.java
+++ b/hypersistence-utils-hibernate-62/src/main/java/io/hypersistence/utils/hibernate/type/range/Range.java
@@ -40,6 +40,7 @@ public final class Range> implements Serializabl
public static final String INFINITY = "infinity";
+ // Text pattern for 'TIMESTAMP' as used by the database
private static final DateTimeFormatter LOCAL_DATE_TIME = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm:ss")
.optionalStart()
@@ -48,12 +49,10 @@ public final class Range> implements Serializabl
.optionalEnd()
.toFormatter();
- private static final DateTimeFormatter ZONE_DATE_TIME = new DateTimeFormatterBuilder()
- .appendPattern("yyyy-MM-dd HH:mm:ss")
- .optionalStart()
- .appendPattern(".")
- .appendFraction(ChronoField.NANO_OF_SECOND, 1, 6, false)
- .optionalEnd()
+ // Text pattern for 'TIMESTAMP WITH TIMEZONE' as used by the database when values are retrieved
+ // from the database.
+ private static final DateTimeFormatter OFFSET_DATE_TIME = new DateTimeFormatterBuilder()
+ .append(LOCAL_DATE_TIME)
.appendOffset("+HH:mm", "Z")
.toFormatter();
@@ -68,7 +67,7 @@ private Range(T lower, T upper, int mask, Class clazz) {
this.mask = mask;
this.clazz = clazz;
- if (isBounded() && lower != null && upper != null && lower.compareTo(upper) > 0) {
+ if (isBounded() && lower != null && upper != null && compare(lower, upper, true) > 0) {
throw new IllegalArgumentException("The lower bound is greater then upper!");
}
}
@@ -465,6 +464,66 @@ public static Range zonedDateTimeRange(String rangeStr) {
return range;
}
+ /**
+ * Creates the {@code OffsetDateTime} range from provided string:
+ * {@code
+ * Range closed = Range.offsetDateTimeRange("[2007-12-03T10:15:30+01:00\",\"2008-12-03T10:15:30+01:00]");
+ * Range quoted = Range.offsetDateTimeRange("[\"2007-12-03T10:15:30+01:00\",\"2008-12-03T10:15:30+01:00\"]");
+ * Range iso = Range.offsetDateTimeRange("[2011-12-03T10:15:30+01:00, 2012-12-03T10:15:30+01:00]");
+ * }
+ *
+ * The valid formats for bounds are:
+ *
+ * - yyyy-MM-dd HH:mm:ss[.SSSSSS]X
+ * - yyyy-MM-dd'T'HH:mm:ss[.SSSSSS]X
+ *
+ *
+ * @param rangeStr The range string, for example {@literal "[2011-12-03T10:15:30+01:00,2012-12-03T10:15:30+01:00]"}.
+ *
+ * @return The range of {@code ZonedDateTime}s.
+ *
+ * @throws DateTimeParseException when one of the bounds are invalid.
+ * @throws IllegalArgumentException when bounds time zones are different.
+ */
+ public static Range offsetDateTimeRange(String rangeStr) {
+ Range range = ofString(rangeStr, parseOffsetDateTime().compose(unquote()), OffsetDateTime.class);
+ if (range.hasLowerBound() && range.hasUpperBound() && !EMPTY.equals(rangeStr)) {
+ ZoneOffset lowerOffset = range.lower.getOffset();
+ ZoneOffset upperOffset = range.upper.getOffset();
+ if (!Objects.equals(lowerOffset, upperOffset)) {
+ throw new IllegalArgumentException("The upper and lower bounds must be in same time zone!");
+ }
+ }
+ return range;
+ }
+
+ /**
+ * Creates the {@code Instant} range from provided string:
+ * {@code
+ * Range closed1 = Range.instantRange("[2007-12-03T10:15:30Z\",\"2008-12-03T10:15:30Z]");
+ * Range closed2 = Range.instantRange("[2007-12-03T10:15:30+01:00\",\"2008-12-03T10:15:30+01:00]");
+ * Range quoted = Range.instantRange("[\"2007-12-03T10:15:30+01:00\",\"2008-12-03T10:15:30+01:00\"]");
+ * Range iso = Range.instantRange("[2011-12-03T10:15:30+01:00, 2012-12-03T10:15:30+01:00]");
+ * }
+ *
+ * The valid formats for bounds are:
+ *
+ * - yyyy-MM-dd HH:mm:ss[.SSSSSS]X
+ * - yyyy-MM-dd'T'HH:mm:ss[.SSSSSS]X
+ *
+ *
+ *
+ * As can be seen, for convenience, offset based string formats are supported too. This is because {@code OffsetDateTime}
+ * has a direct and unambiguous conversion to {@code Instant}.
+ *
+ * @param rangeStr The range string, for example {@literal "[2011-12-03T10:15:30+01:00,2012-12-03T10:15:30+01:00]"}.
+ * @return The range of {@code ZonedDateTime}s.
+ * @throws DateTimeParseException when one of the bounds are invalid.
+ */
+ public static Range instantRange(String rangeStr) {
+ return ofString(rangeStr, parseInstant().compose(unquote()), Instant.class);
+ }
+
private static Function parseLocalDateTime() {
return s -> {
try {
@@ -475,10 +534,30 @@ private static Function parseLocalDateTime() {
};
}
+ private static Function parseInstant() {
+ return s -> {
+ try {
+ return OffsetDateTime.parse(s, OFFSET_DATE_TIME).toInstant();
+ } catch (DateTimeParseException e) {
+ return OffsetDateTime.parse(s).toInstant();
+ }
+ };
+ }
+
+ private static Function parseOffsetDateTime() {
+ return s -> {
+ try {
+ return OffsetDateTime.parse(s, OFFSET_DATE_TIME);
+ } catch (DateTimeParseException e) {
+ return OffsetDateTime.parse(s);
+ }
+ };
+ }
+
private static Function parseZonedDateTime() {
return s -> {
try {
- return ZonedDateTime.parse(s, ZONE_DATE_TIME);
+ return ZonedDateTime.parse(s, OFFSET_DATE_TIME);
} catch (DateTimeParseException e) {
return ZonedDateTime.parse(s);
}
@@ -515,6 +594,36 @@ public int hashCode() {
return Objects.hash(lower, upper, mask, clazz);
}
+ /**
+ * Indicates if another range, {@code o}, is equal to this one.
+ * This method produces the same result as method {@link #equals(Object)} except for
+ * {@code OffsetDateTime}-ranges and {@code ZonedDateTime}-ranges where this method performs
+ * comparison based on Instant equivalents, rather than comparing {@code OffsetDateTime}/{@code ZonedDateTime}
+ * directly.
+ *
+ *
+ * Consider the following two OffsetDateTime or ZonedDateTime ranges:
+ *
+ * ['2007-12-03T09:30.00Z',)
+ * ['2007-12-03T10:30.00+01:00',)
+ *
+ *
+ * As can be seen both timestamp values refer to the same Instant in time. This method returns
+ * {@code true} for such comparison while {@link #equals(Object)} returns {@code false}.
+ *
+ *
+ * @param o other Range
+ * @return true if equal
+ */
+ public boolean equalsInValue(Range o) {
+ if (this == o) return true;
+ if (o == null) return false;
+ return mask == o.mask &&
+ (compare(lower, o.lower, true) == 0) &&
+ (compare(upper, o.upper, true) == 0) &&
+ Objects.equals(clazz, o.clazz);
+ }
+
@Override
public String toString() {
return "Range{" + "lower=" + lower +
@@ -567,22 +676,39 @@ public T upper() {
*
* For example:
*
{@code
- * assertTrue(integerRange("[1,2]").contains(1))
- * assertTrue(integerRange("[1,2]").contains(2))
- * assertTrue(integerRange("[-1,1]").contains(0))
- * assertTrue(infinity(Integer.class).contains(Integer.MAX_VALUE))
- * assertTrue(infinity(Integer.class).contains(Integer.MIN_VALUE))
- *
- * assertFalse(integerRange("(1,2]").contains(1))
- * assertFalse(integerRange("(1,2]").contains(3))
- * assertFalse(integerRange("[-1,1]").contains(0))
+ * assertTrue(integerRange("[1,2]").contains(1, true))
+ * assertTrue(integerRange("[1,2]").contains(2, true))
+ * assertTrue(integerRange("[-1,1]").contains(0, true))
+ * assertTrue(infinity(Integer.class).contains(Integer.MAX_VALUE, true))
+ * assertTrue(infinity(Integer.class).contains(Integer.MIN_VALUE, true))
+ *
+ * assertFalse(integerRange("(1,2]").contains(1, true))
+ * assertFalse(integerRange("(1,2]").contains(3, true))
+ * assertFalse(integerRange("[-1,1]").contains(0, true))
* }
*
- * @param point The point to check.
+ *
+ * For {@code OffsetDateTime}-ranges and {@code ZonedDateTime}-ranges: The {@code ic} parameter determines
+ * how values are compared. Consider the following two OffsetDateTime or ZonedDateTime values:
+ *
+ * - '2007-12-03T09:30.00Z'
+ * - '2007-12-03T10:30.00+01:00'
+ *
+ * As can be seen both values refer to the same instant in time. This type of jitter it likely to happen
+ * with databases: you persist the value (1) but when you later read it back from the database, it may have morphed into
+ * (2) depending on the time zone of your JVM. With standard comparison ({@code ic == false}) one of them would
+ * be evaluated as larger than the other one. This is likely to give unexpected results from this method. By contrast,
+ * if {@code ic == false}, then the two values would be evaluated as equals: none is larger or smaller than the other.
+ *
+ * It is recommended to always use {@code ic = true} when range type is {@code OffsetDateTime} or {@code ZonedDateTime}.
+ *
*
+ * @param point The point to check.
+ * @param ic {@code true} if comparison based on Instant values should be performed. Ignored unless
+ * range type is {@code OffsetDateTime} or {@code ZonedDateTime}.
* @return Whether {@code point} in this range or not.
*/
- public boolean contains(T point) {
+ public boolean contains(T point, boolean ic) {
if (isEmpty()) {
return false;
}
@@ -591,20 +717,84 @@ public boolean contains(T point) {
boolean u = hasUpperBound();
if (l && u) {
- boolean inLower = hasMask(LOWER_INCLUSIVE) ? lower.compareTo(point) <= 0 : lower.compareTo(point) < 0;
- boolean inUpper = hasMask(UPPER_INCLUSIVE) ? upper.compareTo(point) >= 0 : upper.compareTo(point) > 0;
+ boolean inLower = hasMask(LOWER_INCLUSIVE) ? compare(lower, point, ic) <= 0 : compare(lower, point, ic) < 0;
+ boolean inUpper = hasMask(UPPER_INCLUSIVE) ? compare(upper, point, ic) >= 0 : compare(upper, point, ic)> 0;
return inLower && inUpper;
} else if (l) {
- return hasMask(LOWER_INCLUSIVE) ? lower.compareTo(point) <= 0 : lower.compareTo(point) < 0;
+ return hasMask(LOWER_INCLUSIVE) ? compare(lower, point, ic)<= 0 : compare(lower, point, ic) < 0;
} else if (u) {
- return hasMask(UPPER_INCLUSIVE) ? upper.compareTo(point) >= 0 : upper.compareTo(point) > 0;
+ return hasMask(UPPER_INCLUSIVE) ? compare(upper, point, ic) >= 0 : compare(upper, point, ic) > 0;
}
// INFINITY
return true;
}
+
+ /**
+ * Determines whether this range contains this point or not. This method is equivalent
+ * to {@link #contains(Comparable, boolean) contains(point, true)}-
+ *
+ * For example:
+ *
{@code
+ * assertTrue(integerRange("[1,2]").contains(1))
+ * assertTrue(integerRange("[1,2]").contains(2))
+ * assertTrue(integerRange("[-1,1]").contains(0))
+ * assertTrue(infinity(Integer.class).contains(Integer.MAX_VALUE))
+ * assertTrue(infinity(Integer.class).contains(Integer.MIN_VALUE))
+ *
+ * assertFalse(integerRange("(1,2]").contains(1))
+ * assertFalse(integerRange("(1,2]").contains(3))
+ * assertFalse(integerRange("[-1,1]").contains(0))
+ * }
+ *
+ *
+ * For ranges of type {@code OffsetDateTime} or {@code ZonedDateTime} you probably
+ * want to use method {@link #contains(Comparable, boolean) contains(point, true)} instead.
+ *
+ * @see #contains(Comparable, boolean)
+ * @param point The point to check.
+ * @return Whether {@code point} in this range or not.
+ */
+ public boolean contains(T point) {
+ return contains(point, false);
+ }
+
+ private int compare(T t1, T t2, boolean instantComparison) {
+
+ if (instantComparison) {
+ if (t1 instanceof OffsetDateTime && t2 instanceof OffsetDateTime) {
+ OffsetDateTime t1x = (OffsetDateTime) t1;
+ OffsetDateTime t2x = (OffsetDateTime) t2;
+ if (t1x.isEqual(t2x)) {
+ return 0;
+ }
+ if (t1x.isBefore(t2x)) {
+ return -1;
+ }
+ if (t1x.isAfter(t2x)) {
+ return 1;
+ }
+ }
+ if (t1 instanceof ZonedDateTime && t2 instanceof ZonedDateTime) {
+ ZonedDateTime t1x = (ZonedDateTime) t1;
+ ZonedDateTime t2x = (ZonedDateTime) t2;
+ if (t1x.isEqual(t2x)) {
+ return 0;
+ }
+ if (t1x.isBefore(t2x)) {
+ return -1;
+ }
+ if (t1x.isAfter(t2x)) {
+ return 1;
+ }
+ }
+ }
+ return t1.compareTo(t2);
+ }
+
+
/**
* Determines whether this range contains this range or not.
*
@@ -618,11 +808,10 @@ public boolean contains(T point) {
* }
*
* @param range The range to check.
- *
* @return Whether {@code range} in this range or not.
*/
public boolean contains(Range range) {
- return !isEmpty() && (!range.hasLowerBound() || contains(range.lower)) && (!range.hasUpperBound() || contains(range.upper));
+ return !isEmpty() && (!range.hasLowerBound() || contains(range.lower, true)) && (!range.hasUpperBound() || contains(range.upper, true));
}
/**
@@ -641,7 +830,7 @@ public boolean isEmpty() {
public boolean hasEqualBounds() {
return lower == null && upper == null
- || lower != null && upper != null && lower.compareTo(upper) == 0;
+ || lower != null && upper != null && compare(lower, upper, true) == 0;
}
public boolean isBoundedOpen() {
@@ -667,7 +856,15 @@ public String asString() {
private Function boundToString() {
return t -> {
if (clazz.equals(ZonedDateTime.class)) {
- return ZONE_DATE_TIME.format((ZonedDateTime) t);
+ // Let Java do the conversion from ZonedDateTime to OffsetDateTime.
+ // (For PostgreSQL: we could let database do the conversion instead, but better let Java handle it)
+ return OFFSET_DATE_TIME.format(((ZonedDateTime) t).toOffsetDateTime());
+ }
+ if (clazz.equals(OffsetDateTime.class)) {
+ return OFFSET_DATE_TIME.format((OffsetDateTime) t);
+ }
+ if (clazz.equals(Instant.class)) {
+ return OFFSET_DATE_TIME.format(((Instant) t).atOffset(ZoneOffset.UTC));
}
return t.toString();
diff --git a/hypersistence-utils-hibernate-62/src/test/java/io/hypersistence/utils/hibernate/type/range/PostgreSQLRangeTypeTest.java b/hypersistence-utils-hibernate-62/src/test/java/io/hypersistence/utils/hibernate/type/range/PostgreSQLRangeTypeTest.java
index ca5ba6ebe..0bdcad415 100644
--- a/hypersistence-utils-hibernate-62/src/test/java/io/hypersistence/utils/hibernate/type/range/PostgreSQLRangeTypeTest.java
+++ b/hypersistence-utils-hibernate-62/src/test/java/io/hypersistence/utils/hibernate/type/range/PostgreSQLRangeTypeTest.java
@@ -6,13 +6,9 @@
import org.junit.Test;
import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
+import java.time.*;
-import static io.hypersistence.utils.hibernate.type.range.Range.infinite;
-import static io.hypersistence.utils.hibernate.type.range.Range.zonedDateTimeRange;
+import static io.hypersistence.utils.hibernate.type.range.Range.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -33,7 +29,11 @@ public class PostgreSQLRangeTypeTest extends AbstractPostgreSQLIntegrationTest {
private final Range localDateTimeRange = Range.localDateTimeRange("[2014-04-28 16:00:49,2015-04-28 16:00:49]");
- private final Range tsTz = zonedDateTimeRange("[\"2007-12-03T10:15:30+01:00\",\"2008-12-03T10:15:30+01:00\"]");
+ private final Range tsTzZdt = zonedDateTimeRange("[\"2007-12-03T10:15:30+01:00\",\"2008-12-03T10:15:30+01:00\"]");
+
+ private final Range tsTzIns = instantRange("[\"2007-12-03T10:15:30+01:00\",\"2008-12-03T10:15:30+01:00\"]");
+
+ private final Range tsTzOdt = offsetDateTimeRange("[\"2007-12-03T10:15:30+01:00\",\"2008-12-03T10:15:30+01:00\"]");
private final Range tsTzEmpty = zonedDateTimeRange("empty");
@@ -60,7 +60,9 @@ public void test() {
restriction.setRangeLong(int8Range);
restriction.setRangeBigDecimal(numeric);
restriction.setRangeLocalDateTime(localDateTimeRange);
- restriction.setRangeZonedDateTime(tsTz);
+ restriction.setRangeZonedDateTime(tsTzZdt);
+ restriction.setRangeInstant(tsTzIns);
+ restriction.setRangeOffsetDateTime(tsTzOdt);
restriction.setRangeZonedDateTimeInfinity(infinityTsTz);
restriction.setRangeZonedDateTimeEmpty(tsTzEmpty);
restriction.setRangeLocalDate(dateRange);
@@ -82,12 +84,14 @@ public void test() {
ZoneId zone = restriction.getRangeZonedDateTime().lower().getZone();
- ZonedDateTime lower = tsTz.lower().withZoneSameInstant(zone);
- ZonedDateTime upper = tsTz.upper().withZoneSameInstant(zone);
+ ZonedDateTime lower = tsTzZdt.lower().withZoneSameInstant(zone);
+ ZonedDateTime upper = tsTzZdt.upper().withZoneSameInstant(zone);
assertEquals(restriction.getRangeZonedDateTime(), Range.closed(lower, upper));
lower = infinityTsTz.lower().withZoneSameInstant(zone);
assertEquals(restriction.getRangeZonedDateTimeInfinity(), Range.closedInfinite(lower));
+
+
});
}
@@ -149,9 +153,17 @@ public static class Restriction {
private Range rangeLocalDateTime;
@Type(PostgreSQLRangeType.class)
- @Column(name = "r_ts_tz", columnDefinition = "tstzrange")
+ @Column(name = "r_ts_tz_zdt", columnDefinition = "tstzrange")
private Range rangeZonedDateTime;
+ @Type(PostgreSQLRangeType.class)
+ @Column(name = "r_ts_tz_ins", columnDefinition = "tstzrange")
+ private Range rangeInstant;
+
+ @Type(PostgreSQLRangeType.class)
+ @Column(name = "r_ts_tz_odt", columnDefinition = "tstzrange")
+ private Range rangeOffsetDateTime;
+
@Type(PostgreSQLRangeType.class)
@Column(name = "r_ts_tz_infinity", columnDefinition = "tstzrange")
private Range rangeZonedDateTimeInfinity;
@@ -224,6 +236,22 @@ public void setRangeZonedDateTime(Range rangeZonedDateTime) {
this.rangeZonedDateTime = rangeZonedDateTime;
}
+ public Range getRangeInstant() {
+ return rangeInstant;
+ }
+
+ public void setRangeInstant(Range rangeInstant) {
+ this.rangeInstant = rangeInstant;
+ }
+
+ public Range getRangeOffsetDateTime() {
+ return rangeOffsetDateTime;
+ }
+
+ public void setRangeOffsetDateTime(Range rangeOffsetDateTime) {
+ this.rangeOffsetDateTime = rangeOffsetDateTime;
+ }
+
public Range getRangeZonedDateTimeInfinity() {
return rangeZonedDateTimeInfinity;
}
diff --git a/hypersistence-utils-hibernate-62/src/test/java/io/hypersistence/utils/hibernate/type/range/RangeTest.java b/hypersistence-utils-hibernate-62/src/test/java/io/hypersistence/utils/hibernate/type/range/RangeTest.java
index a1ed25ce9..06ed40d2c 100644
--- a/hypersistence-utils-hibernate-62/src/test/java/io/hypersistence/utils/hibernate/type/range/RangeTest.java
+++ b/hypersistence-utils-hibernate-62/src/test/java/io/hypersistence/utils/hibernate/type/range/RangeTest.java
@@ -85,6 +85,27 @@ public void zonedDateTimeTest() {
assertNotNull(Range.zonedDateTimeRange("[2019-03-27 16:33:10.123456-06,infinity)"));
}
+ public void instantTest() {
+ assertNotNull(Range.instantRange("[2019-03-27 16:33:10.1-06,)"));
+ assertNotNull(Range.instantRange("[2019-03-27 16:33:10.12-06,)"));
+ assertNotNull(Range.instantRange("[2019-03-27 16:33:10.123-06,)"));
+ assertNotNull(Range.instantRange("[2019-03-27 16:33:10.1234-06,)"));
+ assertNotNull(Range.instantRange("[2019-03-27 16:33:10.12345-06,)"));
+ assertNotNull(Range.instantRange("[2019-03-27 16:33:10.123456-06,)"));
+ assertNotNull(Range.instantRange("[2019-03-27 16:33:10.123456+05:30,)"));
+ assertNotNull(Range.instantRange("[2019-03-27 16:33:10.123456-06,infinity)"));
+ }
+
+ public void offsetDateTimeTest() {
+ assertNotNull(Range.offsetDateTimeRange("[2019-03-27 16:33:10.1-06,)"));
+ assertNotNull(Range.offsetDateTimeRange("[2019-03-27 16:33:10.12-06,)"));
+ assertNotNull(Range.offsetDateTimeRange("[2019-03-27 16:33:10.123-06,)"));
+ assertNotNull(Range.offsetDateTimeRange("[2019-03-27 16:33:10.1234-06,)"));
+ assertNotNull(Range.offsetDateTimeRange("[2019-03-27 16:33:10.12345-06,)"));
+ assertNotNull(Range.offsetDateTimeRange("[2019-03-27 16:33:10.123456-06,)"));
+ assertNotNull(Range.offsetDateTimeRange("[2019-03-27 16:33:10.123456+05:30,)"));
+ assertNotNull(Range.offsetDateTimeRange("[2019-03-27 16:33:10.123456-06,infinity)"));
+ }
@Test
public void emptyInfinityEquality() {