diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractTemporalJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractTemporalJavaType.java index 895d471985eb..15001e38cda3 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractTemporalJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractTemporalJavaType.java @@ -4,6 +4,10 @@ */ package org.hibernate.type.descriptor.java; +import java.sql.Time; +import java.time.Instant; +import java.time.LocalTime; +import java.time.ZoneId; import java.util.Comparator; import jakarta.persistence.TemporalType; @@ -60,6 +64,13 @@ private TemporalJavaType forMissingPrecision(TypeConfiguration typeConfig return (TemporalJavaType) this; } + public static Time millisToSqlTime(long millis) { + final LocalTime localTime = Instant.ofEpochMilli( millis ).atZone( ZoneId.systemDefault() ).toLocalTime(); + final Time time = Time.valueOf( localTime ); + time.setTime( time.getTime() + localTime.getNano() / 1_000_000 ); + return time; + } + protected TemporalJavaType forTimestampPrecision(TypeConfiguration typeConfiguration) { throw new UnsupportedOperationException( this + " as `jakarta.persistence.TemporalType.TIMESTAMP` not supported" diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarDateJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarDateJavaType.java index 940c5201a589..6c39e08caeca 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarDateJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarDateJavaType.java @@ -100,7 +100,7 @@ public X unwrap(Calendar value, Class type, WrapperOptions options) { return (X) new java.sql.Date( value.getTimeInMillis() ); } if ( java.sql.Time.class.isAssignableFrom( type ) ) { - return (X) new java.sql.Time( value.getTimeInMillis() % 86_400_000 ); + return (X) millisToSqlTime( value.getTimeInMillis() ); } if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) { return (X) new java.sql.Timestamp( value.getTimeInMillis() ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarJavaType.java index e4d49d274fe4..913aada03221 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarJavaType.java @@ -117,7 +117,7 @@ public X unwrap(Calendar value, Class type, WrapperOptions options) { return (X) new java.sql.Date( value.getTimeInMillis() ); } if ( java.sql.Time.class.isAssignableFrom( type ) ) { - return (X) new java.sql.Time( value.getTimeInMillis() % 86_400_000 ); + return (X) millisToSqlTime( value.getTimeInMillis() ); } if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) { return (X) new java.sql.Timestamp( value.getTimeInMillis() ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarTimeJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarTimeJavaType.java index d480795b7f68..29e3c128c451 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarTimeJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarTimeJavaType.java @@ -102,7 +102,7 @@ public X unwrap(Calendar value, Class type, WrapperOptions options) { return (X) new java.sql.Date( value.getTimeInMillis() ); } if ( java.sql.Time.class.isAssignableFrom( type ) ) { - return (X) new java.sql.Time( value.getTimeInMillis() % 86_400_000 ); + return (X) millisToSqlTime( value.getTimeInMillis() ); } if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) { return (X) new java.sql.Timestamp( value.getTimeInMillis() ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DateJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DateJavaType.java index e9e005a724b6..f1e7905ec001 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DateJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DateJavaType.java @@ -124,7 +124,7 @@ public X unwrap(Date value, Class type, WrapperOptions options) { if ( java.sql.Time.class.isAssignableFrom( type ) ) { final java.sql.Time rtn = value instanceof java.sql.Time ? ( java.sql.Time ) value - : new java.sql.Time( value.getTime() % 86_400_000 ); + : millisToSqlTime( value.getTime() ); return (X) rtn; } if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/InstantJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/InstantJavaType.java index 4d5e80b0bb7f..c9d7d56239c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/InstantJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/InstantJavaType.java @@ -126,7 +126,7 @@ public X unwrap(Instant instant, Class type, WrapperOptions options) { } if ( java.sql.Time.class.isAssignableFrom( type ) ) { - return (X) new java.sql.Time( instant.toEpochMilli() % 86_400_000 ); + return (X) millisToSqlTime( instant.toEpochMilli() ); } if ( Date.class.isAssignableFrom( type ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimeJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimeJavaType.java index bbea289da3b3..15afebd1359f 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimeJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimeJavaType.java @@ -120,7 +120,7 @@ public Object unwrap(Date value, Class type, WrapperOptions options) { if ( LocalTime.class.isAssignableFrom( type ) ) { final Time time = value instanceof java.sql.Time ? ( (java.sql.Time) value ) - : new java.sql.Time( value.getTime() % 86_400_000 ); + : millisToSqlTime( value.getTime() ); final LocalTime localTime = time.toLocalTime(); long millis = time.getTime() % 1000; if ( millis == 0 ) { @@ -135,9 +135,7 @@ public Object unwrap(Date value, Class type, WrapperOptions options) { } if ( Time.class.isAssignableFrom( type ) ) { - return value instanceof Time - ? value - : new Time( value.getTime() % 86_400_000 ); + return millisToSqlTime( value.getTime() ); } if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) { @@ -175,12 +173,8 @@ public Date wrap(Object value, WrapperOptions options) { return null; } - if ( value instanceof Time time ) { - return time; - } - if ( value instanceof Date date ) { - return new Time( date.getTime() % 86_400_000 ); + return millisToSqlTime( date.getTime() ); } if ( value instanceof LocalTime localTime ) { @@ -197,7 +191,7 @@ public Date wrap(Object value, WrapperOptions options) { } if ( value instanceof Calendar calendar ) { - return new Time( calendar.getTimeInMillis() % 86_400_000 ); + return millisToSqlTime( ( calendar.getTimeInMillis() ); } throw unknownWrap( value.getClass() ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimestampJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimestampJavaType.java index 809259d382ef..7648c76757ee 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimestampJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimestampJavaType.java @@ -137,7 +137,7 @@ public Object unwrap(Date value, Class type, WrapperOptions options) { if ( java.sql.Time.class.isAssignableFrom( type ) ) { return value instanceof java.sql.Time ? ( java.sql.Time ) value - : new java.sql.Time( value.getTime() % 86_400_000 ); + : millisToSqlTime( value.getTime() ); } if ( Date.class.isAssignableFrom( type ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/LocalDateTimeJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/LocalDateTimeJavaType.java index 065d9180cbac..37b4daf3f46e 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/LocalDateTimeJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/LocalDateTimeJavaType.java @@ -102,7 +102,7 @@ public X unwrap(LocalDateTime value, Class type, WrapperOptions options) if ( java.sql.Time.class.isAssignableFrom( type ) ) { Instant instant = value.atZone( ZoneId.systemDefault() ).toInstant(); - return (X) new java.sql.Time( instant.toEpochMilli() % 86_400_000 ); + return (X) millisToSqlTime( instant.toEpochMilli() ); } if ( Date.class.isAssignableFrom( type ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/OffsetDateTimeJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/OffsetDateTimeJavaType.java index 76603563e4b5..6d709d5a5d9b 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/OffsetDateTimeJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/OffsetDateTimeJavaType.java @@ -157,7 +157,7 @@ public X unwrap(OffsetDateTime offsetDateTime, Class type, WrapperOptions } if ( java.sql.Time.class.isAssignableFrom( type ) ) { - return (X) new java.sql.Time( offsetDateTime.toInstant().toEpochMilli() % 86_400_000 ); + return (X) millisToSqlTime( offsetDateTime.toInstant().toEpochMilli() ); } if ( Date.class.isAssignableFrom( type ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ZonedDateTimeJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ZonedDateTimeJavaType.java index 9a1f0cd465d7..0352b0bee89b 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ZonedDateTimeJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ZonedDateTimeJavaType.java @@ -124,7 +124,7 @@ public X unwrap(ZonedDateTime zonedDateTime, Class type, WrapperOptions o } if ( java.sql.Time.class.isAssignableFrom( type ) ) { - return (X) new java.sql.Time( zonedDateTime.toInstant().toEpochMilli() % 86_400_000 ); + return (X) millisToSqlTime( zonedDateTime.toInstant().toEpochMilli() ); } if ( Date.class.isAssignableFrom( type ) ) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/DateSubclassesUnwrapTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/DateSubclassesUnwrapTest.java index 1c6103158587..08f937ee7527 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/DateSubclassesUnwrapTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/DateSubclassesUnwrapTest.java @@ -1,8 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.orm.test.mapping.type.java; @@ -17,15 +15,8 @@ import java.time.ZonedDateTime; import java.util.Calendar; import java.util.Date; -import java.util.TimeZone; import org.hibernate.HibernateException; -import org.hibernate.dialect.Dialect; -import org.hibernate.dialect.H2Dialect; -import org.hibernate.engine.jdbc.LobCreator; -import org.hibernate.engine.jdbc.NonContextualLobCreator; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.CalendarDateJavaType; import org.hibernate.type.descriptor.java.CalendarJavaType; @@ -173,7 +164,7 @@ void testOffsetTimeJavaType(SessionFactoryScope scope) { assertInstanceOf( Timestamp.class, javaType.unwrap( time, Timestamp.class, wrapperOptions ) ); assertThrows( IllegalArgumentException.class, - () -> javaType.unwrap( time, java.sql.Date.class, wrapperOptions ) ); + () -> javaType.unwrap( time, java.sql.Date.class, wrapperOptions ) ); assertInstanceOf( Time.class, javaType.unwrap( time, Time.class, wrapperOptions ) ); assertInstanceOf( Date.class, javaType.unwrap( time, Date.class, wrapperOptions ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/GoodBadUglyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/GoodBadUglyTest.java index a42024fc286b..b29e653fd411 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/GoodBadUglyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/GoodBadUglyTest.java @@ -1,3 +1,7 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ package org.hibernate.orm.test.mapping.type.java; import java.sql.Time; @@ -43,7 +47,6 @@ @DomainModel(annotatedClasses = GoodBadUglyTest.Times.class) @SessionFactory @SkipForDialect(dialectClass = InformixDialect.class) -@Disabled public class GoodBadUglyTest { @BeforeEach