diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java index e0a0e37ada..f51e2833ce 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java @@ -77,10 +77,10 @@ import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNo import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; import org.hibernate.type.descriptor.jdbc.H2FormatJsonJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.type.descriptor.jdbc.TimeAsTimestampWithTimeZoneJdbcType; import org.hibernate.type.descriptor.jdbc.TimeUtcAsJdbcTimeJdbcType; import org.hibernate.type.descriptor.jdbc.TimeUtcAsOffsetTimeJdbcType; import org.hibernate.type.descriptor.jdbc.TimestampUtcAsInstantJdbcType; -import org.hibernate.type.descriptor.jdbc.TimestampWithTimeZoneJdbcType; import org.hibernate.type.descriptor.jdbc.UUIDJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl; @@ -273,7 +273,7 @@ public class H2LegacyDialect extends Dialect { if ( getVersion().isBefore( 2 ) ) { // Support for TIME_WITH_TIMEZONE was only added in 2.0 - jdbcTypeRegistry.addDescriptor( TIME_WITH_TIMEZONE, TimestampWithTimeZoneJdbcType.INSTANCE ); + jdbcTypeRegistry.addDescriptor( TimeAsTimestampWithTimeZoneJdbcType.INSTANCE ); jdbcTypeRegistry.addDescriptor( TimeUtcAsJdbcTimeJdbcType.INSTANCE ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java index 63c05ab1c0..6501f32912 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -486,6 +486,7 @@ public class DB2Dialect extends Dialect { } public static String timestampdiffPatternV10(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) { + final boolean isTime = fromTemporalType == TemporalType.TIME || toTemporalType == TemporalType.TIME; final String fromExpression; final String toExpression; if ( unit.isDateUnit() ) { @@ -518,20 +519,45 @@ public class DB2Dialect extends Dialect { } switch ( unit ) { case NATIVE: - return "(select (days(t2)-days(t1))*86400+(midnight_seconds(t2)-midnight_seconds(t1))+(microsecond(t2)-microsecond(t1))/1e6 " + - "from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))"; + if ( isTime ) { + return "(midnight_seconds(" + toExpression + ")-midnight_seconds(" + fromExpression + "))"; + } + else { + return "(select (days(t2)-days(t1))*86400+(midnight_seconds(t2)-midnight_seconds(t1))+(microsecond(t2)-microsecond(t1))/1e6 " + + "from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))"; + } case NANOSECOND: - return "(select (days(t2)-days(t1))*86400+(midnight_seconds(t2)-midnight_seconds(t1))*1e9+(microsecond(t2)-microsecond(t1))*1e3 " + - "from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))"; + if ( isTime ) { + return "(midnight_seconds(" + toExpression + ")-midnight_seconds(" + fromExpression + "))*1e9"; + } + else { + return "(select (days(t2)-days(t1))*86400+(midnight_seconds(t2)-midnight_seconds(t1))*1e9+(microsecond(t2)-microsecond(t1))*1e3 " + + "from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))"; + } case SECOND: - return "(select (days(t2)-days(t1))*86400+(midnight_seconds(t2)-midnight_seconds(t1)) " + - "from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))"; + if ( isTime ) { + return "(midnight_seconds(" + toExpression + ")-midnight_seconds(" + fromExpression + "))"; + } + else { + return "(select (days(t2)-days(t1))*86400+(midnight_seconds(t2)-midnight_seconds(t1)) " + + "from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))"; + } case MINUTE: - return "(select (days(t2)-days(t1))*1440+(midnight_seconds(t2)-midnight_seconds(t1))/60 from " + - "lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))"; + if ( isTime ) { + return "(midnight_seconds(" + toExpression + ")-midnight_seconds(" + fromExpression + "))/60"; + } + else { + return "(select (days(t2)-days(t1))*1440+(midnight_seconds(t2)-midnight_seconds(t1))/60 from " + + "lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))"; + } case HOUR: - return "(select (days(t2)-days(t1))*24+(midnight_seconds(t2)-midnight_seconds(t1))/3600 " + - "from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))"; + if ( isTime ) { + return "(midnight_seconds(" + toExpression + ")-midnight_seconds(" + fromExpression + "))/3600"; + } + else { + return "(select (days(t2)-days(t1))*24+(midnight_seconds(t2)-midnight_seconds(t1))/3600 " + + "from lateral(values(" + fromExpression + ',' + toExpression + ")) as temp(t1,t2))"; + } case YEAR: return "(year(" + toExpression + ")-year(" + fromExpression + "))"; // the months_between() function results diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index 6d1b4c67bd..359dc67d7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -69,6 +69,7 @@ import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorH2 import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; import org.hibernate.type.descriptor.jdbc.H2FormatJsonJdbcType; +import org.hibernate.type.descriptor.jdbc.TimeAsTimestampWithTimeZoneJdbcType; import org.hibernate.type.descriptor.jdbc.TimeUtcAsJdbcTimeJdbcType; import org.hibernate.type.descriptor.jdbc.TimestampUtcAsInstantJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; @@ -100,9 +101,7 @@ import static org.hibernate.type.SqlTypes.NCHAR; import static org.hibernate.type.SqlTypes.NUMERIC; import static org.hibernate.type.SqlTypes.NVARCHAR; import static org.hibernate.type.SqlTypes.OTHER; -import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC; import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE; -import static org.hibernate.type.SqlTypes.TIME_UTC; import static org.hibernate.type.SqlTypes.TIME_WITH_TIMEZONE; import static org.hibernate.type.SqlTypes.UUID; import static org.hibernate.type.SqlTypes.VARBINARY; @@ -254,7 +253,7 @@ public class H2Dialect extends Dialect { if ( getVersion().isBefore( 2 ) ) { // Support for TIME_WITH_TIMEZONE was only added in 2.0 - jdbcTypeRegistry.addDescriptor( TIME_WITH_TIMEZONE, TimestampWithTimeZoneJdbcType.INSTANCE ); + jdbcTypeRegistry.addDescriptor( TimeAsTimestampWithTimeZoneJdbcType.INSTANCE ); jdbcTypeRegistry.addDescriptor( TimeUtcAsJdbcTimeJdbcType.INSTANCE ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/TimeAsTimestampWithTimeZoneJdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/TimeAsTimestampWithTimeZoneJdbcType.java new file mode 100644 index 0000000000..19c4b75841 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/TimeAsTimestampWithTimeZoneJdbcType.java @@ -0,0 +1,60 @@ +/* + * 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 . + */ +package org.hibernate.type.descriptor.jdbc; + +import java.sql.Types; +import java.time.OffsetTime; + +import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterTemporal; +import org.hibernate.type.spi.TypeConfiguration; + +import jakarta.persistence.TemporalType; + +/** + * Descriptor for {@link Types#TIMESTAMP_WITH_TIMEZONE TIMESTAMP_WITH_TIMEZONE} handling. + */ +public class TimeAsTimestampWithTimeZoneJdbcType extends TimestampWithTimeZoneJdbcType { + public static final TimeAsTimestampWithTimeZoneJdbcType INSTANCE = new TimeAsTimestampWithTimeZoneJdbcType(); + + public TimeAsTimestampWithTimeZoneJdbcType() { + } + + @Override + public int getJdbcTypeCode() { + return Types.TIMESTAMP_WITH_TIMEZONE; + } + + @Override + public int getDefaultSqlTypeCode() { + return Types.TIME_WITH_TIMEZONE; + } + + @Override + public String getFriendlyName() { + return "TIME_AS_TIMESTAMP_WITH_TIMEZONE"; + } + + @Override + public String toString() { + return "TimeAsTimestampWithTimeZoneDescriptor"; + } + + @Override + public JavaType getJdbcRecommendedJavaTypeMapping( + Integer length, + Integer scale, + TypeConfiguration typeConfiguration) { + return typeConfiguration.getJavaTypeRegistry().getDescriptor( OffsetTime.class ); + } + + @Override + public JdbcLiteralFormatter getJdbcLiteralFormatter(JavaType javaType) { + return new JdbcLiteralFormatterTemporal<>( javaType, TemporalType.TIME ); + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/OffsetTimeMappingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/OffsetTimeMappingTests.java index 6774b3cd3c..3b892b7854 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/OffsetTimeMappingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/OffsetTimeMappingTests.java @@ -43,7 +43,10 @@ public class OffsetTimeMappingTests { final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping("offsetTime"); final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping(); assertThat(jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo(OffsetTime.class)); - assertThat( jdbcMapping.getJdbcType().getJdbcTypeCode(), isOneOf( Types.TIME, Types.TIME_WITH_TIMEZONE)); + assertThat( + jdbcMapping.getJdbcType().getJdbcTypeCode(), + isOneOf( Types.TIME, Types.TIMESTAMP_WITH_TIMEZONE, Types.TIME_WITH_TIMEZONE ) + ); scope.inTransaction( (session) -> { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/TimeZoneStorageMappingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/TimeZoneStorageMappingTests.java index 93630c0a67..e930ad5c9a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/TimeZoneStorageMappingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/TimeZoneStorageMappingTests.java @@ -284,15 +284,15 @@ public class TimeZoneStorageMappingTests { private ZonedDateTime zonedDateTimeNormalized; @TimeZoneStorage(TimeZoneStorageType.NORMALIZE_UTC) - @Column(name = "birthtime_offset_normalized_utc") + @Column(name = "birthtime_offset_utc") private OffsetTime offsetTimeNormalizedUtc; @TimeZoneStorage(TimeZoneStorageType.NORMALIZE_UTC) - @Column(name = "birthday_offset_normalized_utc") + @Column(name = "birthday_offset_utc") private OffsetDateTime offsetDateTimeNormalizedUtc; @TimeZoneStorage(TimeZoneStorageType.NORMALIZE_UTC) - @Column(name = "birthday_zoned_normalized_utc") + @Column(name = "birthday_zoned_utc") private ZonedDateTime zonedDateTimeNormalizedUtc; public TimeZoneStorageEntity() {