From 4b172ed8431d5d0c26c3d4c71ecc1474c3466185 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 29 Apr 2024 21:04:13 +0200 Subject: [PATCH] HHH-18036 Truncate time-related milliseconds when creating a java.sql.Date --- .../descriptor/java/JdbcDateJavaType.java | 31 +++++++++++++------ .../java/JdbcDateJavaTypeDescriptorTest.java | 17 ++++++++++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcDateJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcDateJavaType.java index 3ddf89bec7..a10b208106 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcDateJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcDateJavaType.java @@ -145,7 +145,7 @@ public class JdbcDateJavaType extends AbstractTemporalJavaType { } if ( java.sql.Timestamp.class.isAssignableFrom( type ) ) { - return new java.sql.Timestamp( value.getTime() ); + return new java.sql.Timestamp( unwrapDateEpoch( value ) ); } if ( java.sql.Time.class.isAssignableFrom( type ) ) { @@ -158,18 +158,31 @@ public class JdbcDateJavaType extends AbstractTemporalJavaType { private LocalDate unwrapLocalDate(Date value) { return value instanceof java.sql.Date ? ( (java.sql.Date) value ).toLocalDate() - : new java.sql.Date( value.getTime() ).toLocalDate(); + : new java.sql.Date( unwrapDateEpoch( value ) ).toLocalDate(); } private java.sql.Date unwrapSqlDate(Date value) { - return value instanceof java.sql.Date - ? (java.sql.Date) value - : new java.sql.Date( value.getTime() ); + if ( value instanceof java.sql.Date ) { + final java.sql.Date sqlDate = (java.sql.Date) value; + final long dateEpoch = toDateEpoch( sqlDate.getTime() ); + return dateEpoch == sqlDate.getTime() ? sqlDate : new java.sql.Date( dateEpoch ); + } + return new java.sql.Date( unwrapDateEpoch( value ) ); } private static long unwrapDateEpoch(Date value) { - return value.getTime(); + return toDateEpoch( value.getTime() ); + } + + private static long toDateEpoch(long value) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis( value ); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.clear(Calendar.MINUTE); + calendar.clear(Calendar.SECOND); + calendar.clear(Calendar.MILLISECOND); + return calendar.getTimeInMillis(); } @Override @@ -183,15 +196,15 @@ public class JdbcDateJavaType extends AbstractTemporalJavaType { } if ( value instanceof Long ) { - return new java.sql.Date( (Long) value ); + return new java.sql.Date( toDateEpoch( (Long) value ) ); } if ( value instanceof Calendar ) { - return new java.sql.Date( ( (Calendar) value ).getTimeInMillis() ); + return new java.sql.Date( toDateEpoch( ( (Calendar) value ).getTimeInMillis() ) ); } if ( value instanceof Date ) { - return new java.sql.Date( ( (Date) value ).getTime() ); + return unwrapSqlDate( (Date) value ); } if ( value instanceof LocalDate ) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/descriptor/java/JdbcDateJavaTypeDescriptorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/descriptor/java/JdbcDateJavaTypeDescriptorTest.java index 5045f408d0..de72436d39 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/descriptor/java/JdbcDateJavaTypeDescriptorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/descriptor/java/JdbcDateJavaTypeDescriptorTest.java @@ -1,10 +1,13 @@ package org.hibernate.orm.test.type.descriptor.java; import java.sql.Date; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import org.hibernate.type.descriptor.java.JdbcDateJavaType; import org.hibernate.testing.orm.junit.BaseUnitTest; +import org.hibernate.testing.orm.junit.JiraKey; import org.junit.jupiter.api.Test; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; @@ -32,6 +35,7 @@ public class JdbcDateJavaTypeDescriptorTest { } @Test + @JiraKey("HHH-18036") public void testWrap() { final JdbcDateJavaType javaType = JdbcDateJavaType.INSTANCE; @@ -42,5 +46,18 @@ public class JdbcDateJavaTypeDescriptorTest { final java.util.Date utilDate = new java.util.Date( 0 ); final java.util.Date wrappedUtilDate = javaType.wrap( utilDate, null ); assertThat( wrappedUtilDate ).isInstanceOf( java.sql.Date.class ); + + final java.util.Date utilDateWithTime = java.util.Date.from( ZonedDateTime.of( + 2000, + 1, + 1, + 12, + 0, + 0, + 0, + ZoneOffset.UTC + ).toInstant() ); + final java.util.Date wrappedUtilDateWithTime = javaType.wrap( utilDateWithTime, null ); + assertThat( wrappedUtilDateWithTime ).isEqualTo( java.sql.Date.valueOf( "2000-01-01" ) ); } }