Fix temporal round in tests and render calendar with milliseconds precision

This commit is contained in:
Christian Beikov 2022-12-08 12:29:42 +01:00
parent 7376a1cdfb
commit a9be2e1584
17 changed files with 248 additions and 86 deletions

View File

@ -94,6 +94,7 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* A {@linkplain Dialect SQL dialect} for CockroachDB.
@ -646,7 +647,7 @@ public class CockroachLegacyDialect extends Dialect {
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:

View File

@ -106,6 +106,7 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* A legacy {@linkplain Dialect SQL dialect} for H2.
@ -536,7 +537,7 @@ public class H2LegacyDialect extends Dialect {
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:

View File

@ -133,6 +133,7 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* A {@linkplain Dialect SQL dialect} for PostgreSQL 8 and above.
@ -1119,7 +1120,7 @@ public class PostgreSQLLegacyDialect extends Dialect {
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:

View File

@ -86,6 +86,7 @@ import static org.hibernate.type.SqlTypes.*;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* A dialect for Microsoft SQL Server 2000 and above
@ -924,7 +925,7 @@ public class SQLServerLegacyDialect extends AbstractTransactSQLDialect {
break;
case TIMESTAMP:
appender.appendSql( "cast('" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( "' as datetime2)" );
break;
default:

View File

@ -83,6 +83,7 @@ import static org.hibernate.type.SqlTypes.VARBINARY;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* An SQL dialect for SQLite.
@ -713,7 +714,7 @@ public class SQLiteDialect extends Dialect {
break;
case TIMESTAMP:
appender.appendSql( "datetime(" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( ')' );
break;
default:

View File

@ -104,6 +104,7 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* A {@linkplain Dialect SQL dialect} for CockroachDB.
@ -664,7 +665,7 @@ public class CockroachDialect extends Dialect {
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:

View File

@ -229,6 +229,7 @@ import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIME
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* Represents a dialect of SQL implemented by a particular RDBMS. Every
@ -4380,7 +4381,7 @@ public abstract class Dialect implements ConversionContext {
break;
case TIMESTAMP:
appender.appendSql( JDBC_ESCAPE_START_TIMESTAMP );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( JDBC_ESCAPE_END );
break;
default:

View File

@ -96,6 +96,7 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* A {@linkplain Dialect SQL dialect} for H2.
@ -514,7 +515,7 @@ public class H2Dialect extends Dialect {
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:

View File

@ -119,6 +119,7 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* A {@linkplain Dialect SQL dialect} for PostgreSQL 8 and above.
@ -1104,7 +1105,7 @@ public class PostgreSQLDialect extends Dialect {
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:

View File

@ -103,6 +103,7 @@ import static org.hibernate.type.SqlTypes.VARCHAR;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* A dialect for Microsoft SQL Server 2008 and above
@ -932,7 +933,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
break;
case TIMESTAMP:
appender.appendSql( "cast('" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( "' as datetime2)" );
break;
default:

View File

@ -14,12 +14,14 @@ import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import org.hibernate.dialect.Dialect;
import org.hibernate.sql.ast.spi.SqlAppender;
import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE;
@ -41,8 +43,10 @@ public final class DateTimeUtils {
public static final String FORMAT_STRING_TIMESTAMP = "yyyy-MM-dd HH:mm:ss";
public static final String FORMAT_STRING_TIMESTAMP_WITH_MILLIS = FORMAT_STRING_TIMESTAMP + ".SSS";
public static final String FORMAT_STRING_TIMESTAMP_WITH_MICROS = FORMAT_STRING_TIMESTAMP + ".SSSSSS";
public static final String FORMAT_STRING_TIMESTAMP_WITH_NANOS = FORMAT_STRING_TIMESTAMP + ".SSSSSSSSS";
public static final String FORMAT_STRING_TIMESTAMP_WITH_MILLIS_AND_OFFSET = FORMAT_STRING_TIMESTAMP_WITH_MILLIS + "XXX";
public static final String FORMAT_STRING_TIMESTAMP_WITH_MICROS_AND_OFFSET = FORMAT_STRING_TIMESTAMP_WITH_MICROS + "XXX";
public static final String FORMAT_STRING_TIMESTAMP_WITH_NANOS_AND_OFFSET = FORMAT_STRING_TIMESTAMP_WITH_NANOS + "XXX";
public static final DateTimeFormatter DATE_TIME_FORMATTER_DATE = DateTimeFormatter.ofPattern( FORMAT_STRING_DATE, Locale.ENGLISH );
public static final DateTimeFormatter DATE_TIME_FORMATTER_TIME_WITH_OFFSET = DateTimeFormatter.ofPattern( FORMAT_STRING_TIME_WITH_OFFSET, Locale.ENGLISH );
@ -55,6 +59,10 @@ public final class DateTimeUtils {
FORMAT_STRING_TIMESTAMP_WITH_MICROS,
Locale.ENGLISH
);
public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_NANOS = DateTimeFormatter.ofPattern(
FORMAT_STRING_TIMESTAMP_WITH_NANOS,
Locale.ENGLISH
);
public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS_AND_OFFSET = DateTimeFormatter.ofPattern(
FORMAT_STRING_TIMESTAMP_WITH_MILLIS_AND_OFFSET,
Locale.ENGLISH
@ -63,6 +71,10 @@ public final class DateTimeUtils {
FORMAT_STRING_TIMESTAMP_WITH_MICROS_AND_OFFSET,
Locale.ENGLISH
);
public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_NANOS_AND_OFFSET = DateTimeFormatter.ofPattern(
FORMAT_STRING_TIMESTAMP_WITH_NANOS_AND_OFFSET,
Locale.ENGLISH
);
public static final String JDBC_ESCAPE_START_DATE = "{d '";
public static final String JDBC_ESCAPE_START_TIME = "{t '";
@ -96,12 +108,6 @@ public final class DateTimeUtils {
Locale.ENGLISH
)
);
private static final ThreadLocal<SimpleDateFormat> TIMESTAMP_WITH_MICROS_FORMAT = ThreadLocal.withInitial(
() -> new SimpleDateFormat(
FORMAT_STRING_TIMESTAMP_WITH_MICROS,
Locale.ENGLISH
)
);
/**
* Pattern used for parsing literal offset datetimes in HQL.
@ -120,45 +126,34 @@ public final class DateTimeUtils {
.appendOffset("+HH:mm", "+00")
.toFormatter();
public static void appendAsTimestampWithNanos(
SqlAppender appender,
TemporalAccessor temporalAccessor,
boolean supportsOffset,
TimeZone jdbcTimeZone) {
appendAsTimestamp(
appender,
temporalAccessor,
supportsOffset,
jdbcTimeZone,
DATE_TIME_FORMATTER_TIMESTAMP_WITH_NANOS,
DATE_TIME_FORMATTER_TIMESTAMP_WITH_NANOS_AND_OFFSET
);
}
public static void appendAsTimestampWithMicros(
SqlAppender appender,
TemporalAccessor temporalAccessor,
boolean supportsOffset,
TimeZone jdbcTimeZone) {
if ( temporalAccessor.isSupported( ChronoField.OFFSET_SECONDS ) ) {
if ( supportsOffset ) {
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET.formatTo( temporalAccessor, appender );
}
else {
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.formatTo(
LocalDateTime.ofInstant(
Instant.from( temporalAccessor ),
jdbcTimeZone.toZoneId()
),
appender
);
}
}
else if ( temporalAccessor instanceof Instant ) {
if ( supportsOffset ) {
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET.formatTo(
( (Instant) temporalAccessor ).atZone( jdbcTimeZone.toZoneId() ),
appender
);
}
else {
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.formatTo(
LocalDateTime.ofInstant(
(Instant) temporalAccessor,
jdbcTimeZone.toZoneId()
),
appender
);
}
}
else {
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.formatTo( temporalAccessor, appender );
}
appendAsTimestamp(
appender,
temporalAccessor,
supportsOffset,
jdbcTimeZone,
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS,
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET
);
}
public static void appendAsTimestampWithMillis(
@ -166,12 +161,29 @@ public final class DateTimeUtils {
TemporalAccessor temporalAccessor,
boolean supportsOffset,
TimeZone jdbcTimeZone) {
appendAsTimestamp(
appender,
temporalAccessor,
supportsOffset,
jdbcTimeZone,
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS,
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS_AND_OFFSET
);
}
private static void appendAsTimestamp(
SqlAppender appender,
TemporalAccessor temporalAccessor,
boolean supportsOffset,
TimeZone jdbcTimeZone,
DateTimeFormatter format,
DateTimeFormatter formatWithOffset) {
if ( temporalAccessor.isSupported( ChronoField.OFFSET_SECONDS ) ) {
if ( supportsOffset ) {
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS_AND_OFFSET.formatTo( temporalAccessor, appender );
formatWithOffset.formatTo( temporalAccessor, appender );
}
else {
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS.formatTo(
format.formatTo(
LocalDateTime.ofInstant(
Instant.from( temporalAccessor ),
jdbcTimeZone.toZoneId()
@ -182,13 +194,13 @@ public final class DateTimeUtils {
}
else if ( temporalAccessor instanceof Instant ) {
if ( supportsOffset ) {
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS_AND_OFFSET.formatTo(
formatWithOffset.formatTo(
( (Instant) temporalAccessor ).atZone( jdbcTimeZone.toZoneId() ),
appender
);
}
else {
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS.formatTo(
format.formatTo(
LocalDateTime.ofInstant(
(Instant) temporalAccessor,
jdbcTimeZone.toZoneId()
@ -198,7 +210,7 @@ public final class DateTimeUtils {
}
}
else {
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS.formatTo( temporalAccessor, appender );
format.formatTo( temporalAccessor, appender );
}
}
@ -241,22 +253,54 @@ public final class DateTimeUtils {
}
public static void appendAsTimestampWithMicros(SqlAppender appender, Date date, TimeZone jdbcTimeZone) {
final SimpleDateFormat simpleDateFormat;
if ( date instanceof Timestamp ) {
// java.sql.Timestamp supports micro sec
simpleDateFormat = TIMESTAMP_WITH_MICROS_FORMAT.get();
// java.sql.Timestamp supports nano sec
appendAsTimestamp(
appender,
date.toInstant().atZone( jdbcTimeZone.toZoneId() ),
false,
jdbcTimeZone,
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS,
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET
);
}
else {
// java.util.Date supports only milli sec
simpleDateFormat = TIMESTAMP_WITH_MILLIS_FORMAT.get();
final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MILLIS_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
appender.appendSql( simpleDateFormat.format( date ) );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
}
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
appender.appendSql( simpleDateFormat.format( date ) );
}
public static void appendAsTimestampWithNanos(SqlAppender appender, Date date, TimeZone jdbcTimeZone) {
if ( date instanceof Timestamp ) {
// java.sql.Timestamp supports nano sec
appendAsTimestamp(
appender,
date.toInstant().atZone( jdbcTimeZone.toZoneId() ),
false,
jdbcTimeZone,
DATE_TIME_FORMATTER_TIMESTAMP_WITH_NANOS,
DATE_TIME_FORMATTER_TIMESTAMP_WITH_NANOS_AND_OFFSET
);
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
else {
// java.util.Date supports only milli sec
final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MILLIS_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
appender.appendSql( simpleDateFormat.format( date ) );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
}
}
@ -303,6 +347,12 @@ public final class DateTimeUtils {
}
}
/**
* Calendar has no microseconds.
*
* @deprecated use {@link #appendAsTimestampWithMillis(SqlAppender, Calendar, TimeZone)} instead
*/
@Deprecated(forRemoval = true)
public static void appendAsTimestampWithMicros(SqlAppender appender, Calendar calendar, TimeZone jdbcTimeZone) {
// it is possible to use micro sec resolution with java.util.Date
final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MILLIS_FORMAT.get();
@ -352,4 +402,45 @@ public final class DateTimeUtils {
appender.appendSql( LOCAL_TIME_FORMAT.get().format( calendar.getTime() ) );
}
/**
* Do the same conversion that databases do when they encounter a timestamp with a higher precision
* than what is supported by a column, which is to round the excess fractions.
*/
public static <T extends Temporal> T roundToDefaultPrecision(T temporal, Dialect d) {
final int defaultTimestampPrecision = d.getDefaultTimestampPrecision();
if ( defaultTimestampPrecision >= 9 || !temporal.isSupported( ChronoField.NANO_OF_SECOND ) ) {
return temporal;
}
final int precisionMask = pow10( 9 - defaultTimestampPrecision );
final int nano = temporal.get( ChronoField.NANO_OF_SECOND );
final int nanosToRound = nano % precisionMask;
final int finalNano = nano - nanosToRound + ( nanosToRound >= ( precisionMask >> 1 ) ? precisionMask : 0 );
//noinspection unchecked
return (T) temporal.with( ChronoField.NANO_OF_SECOND, finalNano );
}
private static int pow10(int exponent) {
switch ( exponent ) {
case 0:
return 1;
case 1:
return 10;
case 2:
return 100;
case 3:
return 1000;
case 4:
return 10000;
case 5:
return 100000;
case 6:
return 1000000;
case 7:
return 10000000;
case 8:
return 100000000;
default:
return (int) Math.pow( 10, exponent );
}
}
}

View File

@ -4,7 +4,10 @@ import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.type.descriptor.DateTimeUtils;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -37,14 +40,21 @@ public class AutoZonedTest {
});
scope.inSession( s -> {
Zoned z = s.find(Zoned.class, id);
if ( scope.getSessionFactory().getJdbcServices().getDialect() instanceof SybaseDialect) {
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
if ( dialect instanceof SybaseDialect ) {
// Sybase with jTDS driver has 1/300th sec precision
assertEquals( nowZoned.toInstant().truncatedTo(ChronoUnit.SECONDS), z.zonedDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS) );
assertEquals( nowOffset.toInstant().truncatedTo(ChronoUnit.SECONDS), z.offsetDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS) );
}
else {
assertEquals( nowZoned.toInstant(), z.zonedDateTime.toInstant() );
assertEquals( nowOffset.toInstant(), z.offsetDateTime.toInstant() );
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowZoned.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.zonedDateTime.toInstant(), dialect )
);
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowOffset.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.offsetDateTime.toInstant(), dialect )
);
}
assertEquals( nowZoned.toOffsetDateTime().getOffset(), z.zonedDateTime.toOffsetDateTime().getOffset() );
assertEquals( nowOffset.getOffset(), z.offsetDateTime.getOffset() );

View File

@ -4,7 +4,10 @@ import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.type.descriptor.DateTimeUtils;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -37,14 +40,21 @@ public class ColumnZonedTest {
});
scope.inSession( s -> {
Zoned z = s.find(Zoned.class, id);
if ( scope.getSessionFactory().getJdbcServices().getDialect() instanceof SybaseDialect) {
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
if ( dialect instanceof SybaseDialect) {
// Sybase with jTDS driver has 1/300th sec precision
assertEquals( nowZoned.toInstant().truncatedTo(ChronoUnit.SECONDS), z.zonedDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS) );
assertEquals( nowOffset.toInstant().truncatedTo(ChronoUnit.SECONDS), z.offsetDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS) );
}
else {
assertEquals( nowZoned.toInstant(), z.zonedDateTime.toInstant() );
assertEquals( nowOffset.toInstant(), z.offsetDateTime.toInstant() );
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowZoned.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.zonedDateTime.toInstant(), dialect )
);
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowOffset.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.offsetDateTime.toInstant(), dialect )
);
}
assertEquals( nowZoned.toOffsetDateTime().getOffset(), z.zonedDateTime.toOffsetDateTime().getOffset() );
assertEquals( nowOffset.getOffset(), z.offsetDateTime.getOffset() );

View File

@ -3,8 +3,12 @@ package org.hibernate.orm.test.timezones;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.dialect.TimeZoneSupport;
import org.hibernate.type.descriptor.DateTimeUtils;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
@ -34,16 +38,23 @@ public class DefaultZonedTest {
});
scope.inSession( s -> {
Zoned z = s.find(Zoned.class, id);
if ( scope.getSessionFactory().getJdbcServices().getDialect() instanceof SybaseDialect) {
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
if ( dialect instanceof SybaseDialect) {
// Sybase with jTDS driver has 1/300th sec precision
assertEquals( nowZoned.toInstant().truncatedTo(ChronoUnit.SECONDS), z.zonedDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS) );
assertEquals( nowOffset.toInstant().truncatedTo(ChronoUnit.SECONDS), z.offsetDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS) );
}
else {
assertEquals( nowZoned.toInstant(), z.zonedDateTime.toInstant() );
assertEquals( nowOffset.toInstant(), z.offsetDateTime.toInstant() );
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowZoned.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.zonedDateTime.toInstant(), dialect )
);
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowOffset.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.offsetDateTime.toInstant(), dialect )
);
}
if ( scope.getSessionFactory().getJdbcServices().getDialect().getTimeZoneSupport() == TimeZoneSupport.NATIVE ) {
if ( dialect.getTimeZoneSupport() == TimeZoneSupport.NATIVE ) {
assertEquals( nowZoned.toOffsetDateTime().getOffset(), z.zonedDateTime.toOffsetDateTime().getOffset() );
assertEquals( nowOffset.getOffset(), z.offsetDateTime.getOffset() );
}

View File

@ -4,7 +4,10 @@ import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.type.descriptor.DateTimeUtils;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -29,7 +32,7 @@ public class JDBCTimeZoneZonedTest {
@Test void test(SessionFactoryScope scope) {
ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") );
OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) );
OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3) );
long id = scope.fromTransaction( s-> {
Zoned z = new Zoned();
z.zonedDateTime = nowZoned;
@ -41,14 +44,21 @@ public class JDBCTimeZoneZonedTest {
Zoned z = s.find(Zoned.class, id);
ZoneId systemZone = ZoneId.systemDefault();
ZoneOffset systemOffset = systemZone.getRules().getOffset( Instant.now() );
if ( scope.getSessionFactory().getJdbcServices().getDialect() instanceof SybaseDialect) {
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
if ( dialect instanceof SybaseDialect) {
// Sybase with jTDS driver has 1/300th sec precision
assertEquals( nowZoned.toInstant().truncatedTo(ChronoUnit.SECONDS), z.zonedDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS));
assertEquals( nowOffset.toInstant().truncatedTo(ChronoUnit.SECONDS), z.offsetDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS));
}
else {
assertEquals( nowZoned.withZoneSameInstant(systemZone), z.zonedDateTime );
assertEquals( nowOffset.withOffsetSameInstant(systemOffset), z.offsetDateTime );
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowZoned.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.zonedDateTime.toInstant(), dialect )
);
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowOffset.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.offsetDateTime.toInstant(), dialect )
);
}
assertEquals( systemZone, z.zonedDateTime.getZone() );
assertEquals( systemOffset, z.offsetDateTime.getOffset() );

View File

@ -4,7 +4,10 @@ import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.type.descriptor.DateTimeUtils;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -28,7 +31,7 @@ public class PassThruZonedTest {
@Test void test(SessionFactoryScope scope) {
ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") );
OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) );
OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3) );
long id = scope.fromTransaction( s-> {
Zoned z = new Zoned();
z.zonedDateTime = nowZoned;
@ -40,14 +43,21 @@ public class PassThruZonedTest {
Zoned z = s.find(Zoned.class, id);
ZoneId systemZone = ZoneId.systemDefault();
ZoneOffset systemOffset = systemZone.getRules().getOffset( Instant.now() );
if ( scope.getSessionFactory().getJdbcServices().getDialect() instanceof SybaseDialect) {
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
if ( dialect instanceof SybaseDialect) {
// Sybase with jTDS driver has 1/300th sec precision
assertEquals( nowZoned.toInstant().truncatedTo(ChronoUnit.SECONDS), z.zonedDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS));
assertEquals( nowOffset.toInstant().truncatedTo(ChronoUnit.SECONDS), z.offsetDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS));
}
else {
assertEquals( nowZoned.withZoneSameInstant(systemZone), z.zonedDateTime );
assertEquals( nowOffset.withOffsetSameInstant(systemOffset), z.offsetDateTime );
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowZoned.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.zonedDateTime.toInstant(), dialect )
);
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowOffset.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.offsetDateTime.toInstant(), dialect )
);
}
assertEquals( systemZone, z.zonedDateTime.getZone() );
assertEquals( systemOffset, z.offsetDateTime.getOffset() );

View File

@ -4,7 +4,10 @@ import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.type.descriptor.DateTimeUtils;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -37,14 +40,21 @@ public class UTCNormalizedZonedTest {
});
scope.inSession( s-> {
Zoned z = s.find(Zoned.class, id);
if ( scope.getSessionFactory().getJdbcServices().getDialect() instanceof SybaseDialect) {
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
if ( dialect instanceof SybaseDialect) {
// Sybase with jTDS driver has 1/300th sec precision
assertEquals( nowZoned.toInstant().truncatedTo(ChronoUnit.SECONDS), z.zonedDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS) );
assertEquals( nowOffset.toInstant().truncatedTo(ChronoUnit.SECONDS), z.offsetDateTime.toInstant().truncatedTo(ChronoUnit.SECONDS) );
}
else {
assertEquals( nowZoned.toInstant(), z.zonedDateTime.toInstant() );
assertEquals( nowOffset.toInstant(), z.offsetDateTime.toInstant() );
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowZoned.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.zonedDateTime.toInstant(), dialect )
);
assertEquals(
DateTimeUtils.roundToDefaultPrecision( nowOffset.toInstant(), dialect ),
DateTimeUtils.roundToDefaultPrecision( z.offsetDateTime.toInstant(), dialect )
);
}
assertEquals( ZoneId.of("Z"), z.zonedDateTime.getZone() );
assertEquals( ZoneOffset.ofHours(0), z.offsetDateTime.getOffset() );