#2264 - Use of default timezone for OffsetDateTime offsets problematic for unit tests and presentation layer

This commit is contained in:
rbygrave
2021-07-15 17:14:22 +12:00
parent 4d15535381
commit 7408483a43
5 changed files with 109 additions and 18 deletions
@@ -750,12 +750,15 @@ public final class DefaultTypeManager implements TypeManager {
}
private void initialiseJavaTimeTypes(DatabaseConfig config) {
ZoneId zoneId = getZoneId(config);
typeMap.put(java.nio.file.Path.class, new ScalarTypePath());
addType(java.time.Period.class, new ScalarTypePeriod());
addType(java.time.LocalDate.class, new ScalarTypeLocalDate(jsonDate));
addType(java.time.LocalDateTime.class, new ScalarTypeLocalDateTime(jsonDateTime));
addType(OffsetDateTime.class, new ScalarTypeOffsetDateTime(jsonDateTime));
addType(ZonedDateTime.class, new ScalarTypeZonedDateTime(jsonDateTime));
addType(OffsetDateTime.class, new ScalarTypeOffsetDateTime(jsonDateTime, zoneId));
addType(ZonedDateTime.class, new ScalarTypeZonedDateTime(jsonDateTime, zoneId));
addType(Instant.class, new ScalarTypeInstant(jsonDateTime));
addType(DayOfWeek.class, new ScalarTypeDayOfWeek());
addType(Month.class, new ScalarTypeMonth());
@@ -771,6 +774,11 @@ public final class DefaultTypeManager implements TypeManager {
addType(Duration.class, (durationNanos) ? new ScalarTypeDurationWithNanos() : new ScalarTypeDuration());
}
private ZoneId getZoneId(DatabaseConfig config) {
final String dataTimeZone = config.getDataTimeZone();
return (dataTimeZone == null) ? ZoneOffset.systemDefault() : TimeZone.getTimeZone(dataTimeZone).toZoneId();
}
private void addType(Class<?> clazz, ScalarType<?> scalarType) {
typeMap.put(clazz, scalarType);
logicalMap.putIfAbsent(clazz.getSimpleName(), scalarType);
@@ -15,8 +15,11 @@ import static io.ebeaninternal.server.type.IsoJsonDateTimeParser.formatIso;
*/
public class ScalarTypeOffsetDateTime extends ScalarTypeBaseDateTime<OffsetDateTime> {
public ScalarTypeOffsetDateTime(JsonConfig.DateTime mode) {
private final ZoneId zoneId;
public ScalarTypeOffsetDateTime(JsonConfig.DateTime mode, ZoneId zoneId) {
super(mode, OffsetDateTime.class, false, Types.TIMESTAMP);
this.zoneId = zoneId;
}
@Override
@@ -46,7 +49,7 @@ public class ScalarTypeOffsetDateTime extends ScalarTypeBaseDateTime<OffsetDateT
@Override
public OffsetDateTime convertFromInstant(Instant ts) {
return OffsetDateTime.ofInstant(ts, ZoneId.systemDefault());
return OffsetDateTime.ofInstant(ts, zoneId);
}
@Override
@@ -13,8 +13,11 @@ import java.time.ZonedDateTime;
*/
public class ScalarTypeZonedDateTime extends ScalarTypeBaseDateTime<ZonedDateTime> {
public ScalarTypeZonedDateTime(JsonConfig.DateTime mode) {
private final ZoneId zoneId;
public ScalarTypeZonedDateTime(JsonConfig.DateTime mode, ZoneId zoneId) {
super(mode, ZonedDateTime.class, false, Types.TIMESTAMP);
this.zoneId = zoneId;
}
@Override
@@ -44,7 +47,7 @@ public class ScalarTypeZonedDateTime extends ScalarTypeBaseDateTime<ZonedDateTim
@Override
public ZonedDateTime convertFromInstant(Instant ts) {
return ZonedDateTime.ofInstant(ts, ZoneId.systemDefault());
return ZonedDateTime.ofInstant(ts, zoneId);
}
@Override
@@ -5,6 +5,8 @@ import org.junit.Test;
import java.sql.Timestamp;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.TimeZone;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
@@ -14,12 +16,12 @@ import static org.junit.Assert.assertTrue;
public class ScalarTypeOffsetDateTimeTest {
ScalarTypeOffsetDateTime type = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.MILLIS);
ScalarTypeOffsetDateTime type = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.MILLIS, ZoneOffset.systemDefault());
OffsetDateTime warmUp = OffsetDateTime.now();
@Test
public void testConvertToMillis() throws Exception {
public void testConvertToMillis() {
warmUp.hashCode();
@@ -30,7 +32,43 @@ public class ScalarTypeOffsetDateTimeTest {
}
@Test
public void testConvertFromTimestamp() throws Exception {
public void convertFromInstant_with_UTC_expect_matchingZoneOffset() {
final TimeZone timeZoneToUse = TimeZone.getTimeZone("UTC");
final ZoneOffset expectedZoneOffset = ZoneOffset.UTC;
convertFromInstantWithConfiguredTimeZone(timeZoneToUse, expectedZoneOffset);
}
@Test
public void convertFromInstant_with_EST_expect_matchingZoneOffset() {
final TimeZone timeZoneToUse = TimeZone.getTimeZone("EST");
final ZoneOffset expectedOffset = OffsetDateTime.now(timeZoneToUse.toZoneId()).getOffset();
convertFromInstantWithConfiguredTimeZone(timeZoneToUse, expectedOffset);
}
private void convertFromInstantWithConfiguredTimeZone(TimeZone timeZoneToUse, ZoneOffset expectedZoneOffset) {
TimeZone previous = TimeZone.getDefault();
try {
OffsetDateTime dateTime = OffsetDateTime.parse("2021-01-01T00:00:00+11:00");
// test ScalarTypeOffsetDateTime with the configured timeZone to use
ScalarTypeOffsetDateTime type = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.MILLIS, timeZoneToUse.toZoneId());
// effectively we desire to ignore the system timezone and use the configured one
TimeZone.setDefault(timeZoneToUse);
final OffsetDateTime offsetDateTime = type.convertFromInstant(dateTime.toInstant());
assertEquals(expectedZoneOffset, offsetDateTime.getOffset());
} finally {
TimeZone.setDefault(previous);
}
}
@Test
public void testConvertFromTimestamp() {
Timestamp now = new Timestamp(System.currentTimeMillis());
@@ -69,11 +107,11 @@ public class ScalarTypeOffsetDateTimeTest {
JsonTester<OffsetDateTime> jsonTester = new JsonTester<>(type);
jsonTester.test(now);
ScalarTypeOffsetDateTime typeNanos = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.NANOS);
ScalarTypeOffsetDateTime typeNanos = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.NANOS, ZoneOffset.systemDefault());
jsonTester = new JsonTester<>(typeNanos);
jsonTester.test(now);
ScalarTypeOffsetDateTime typeIso = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.ISO8601);
ScalarTypeOffsetDateTime typeIso = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.ISO8601, ZoneOffset.systemDefault());
jsonTester = new JsonTester<>(typeIso);
jsonTester.test(now);
}
@@ -81,7 +119,7 @@ public class ScalarTypeOffsetDateTimeTest {
@Test
public void isoJsonFormatParse() {
ScalarTypeOffsetDateTime typeIso = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.ISO8601);
ScalarTypeOffsetDateTime typeIso = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.ISO8601, ZoneOffset.systemDefault());
OffsetDateTime now = OffsetDateTime.now();
String asJson = typeIso.toJsonISO8601(now);
@@ -4,7 +4,11 @@ import io.ebean.config.JsonConfig;
import org.junit.Test;
import java.sql.Timestamp;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.TimeZone;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
@@ -12,12 +16,12 @@ import static org.junit.Assert.*;
public class ScalarTypeZonedDateTimeTest {
ScalarTypeZonedDateTime type = new ScalarTypeZonedDateTime(JsonConfig.DateTime.MILLIS);
ScalarTypeZonedDateTime type = new ScalarTypeZonedDateTime(JsonConfig.DateTime.MILLIS, ZoneId.systemDefault());
ZonedDateTime warmUp = ZonedDateTime.now();
@Test
public void testConvertToMillis() throws Exception {
public void testConvertToMillis() {
warmUp.hashCode();
@@ -29,7 +33,7 @@ public class ScalarTypeZonedDateTimeTest {
}
@Test
public void testConvertFromTimestamp() throws Exception {
public void testConvertFromTimestamp() {
Timestamp now = new Timestamp(System.currentTimeMillis());
@@ -39,6 +43,41 @@ public class ScalarTypeZonedDateTimeTest {
assertEquals(now, timestamp);
}
@Test
public void convertFromInstant_with_UTC_expect_matchingZoneOffset() {
final TimeZone timeZoneToUse = TimeZone.getTimeZone("UTC");
final ZoneOffset expectedZoneOffset = ZoneOffset.UTC;
convertFromInstantWithConfiguredTimeZone(timeZoneToUse, expectedZoneOffset);
}
@Test
public void convertFromInstant_with_EST_expect_matchingZoneOffset() {
final TimeZone timeZoneToUse = TimeZone.getTimeZone("EST");
final ZoneOffset expectedOffset = OffsetDateTime.now(timeZoneToUse.toZoneId()).getOffset();
convertFromInstantWithConfiguredTimeZone(timeZoneToUse, expectedOffset);
}
private void convertFromInstantWithConfiguredTimeZone(TimeZone timeZoneToUse, ZoneOffset expectedZoneOffset) {
TimeZone previous = TimeZone.getDefault();
try {
OffsetDateTime dateTime = OffsetDateTime.parse("2021-01-01T00:00:00+11:00");
// test ScalarTypeOffsetDateTime with the configured timeZone to use
ScalarTypeZonedDateTime type = new ScalarTypeZonedDateTime(JsonConfig.DateTime.MILLIS, timeZoneToUse.toZoneId());
// effectively we desire to ignore the system timezone and use the configured one
TimeZone.setDefault(timeZoneToUse);
final ZonedDateTime zonedDateTime = type.convertFromInstant(dateTime.toInstant());
assertEquals(expectedZoneOffset, zonedDateTime.getOffset());
} finally {
TimeZone.setDefault(previous);
}
}
@Test
public void testToJdbcType() throws Exception {
@@ -68,11 +107,11 @@ public class ScalarTypeZonedDateTimeTest {
JsonTester<ZonedDateTime> jsonTester = new JsonTester<>(type);
jsonTester.test(now);
ScalarTypeZonedDateTime typeNanos = new ScalarTypeZonedDateTime(JsonConfig.DateTime.NANOS);
ScalarTypeZonedDateTime typeNanos = new ScalarTypeZonedDateTime(JsonConfig.DateTime.NANOS, ZoneId.systemDefault());
jsonTester = new JsonTester<>(typeNanos);
jsonTester.test(now);
ScalarTypeZonedDateTime typeIso = new ScalarTypeZonedDateTime(JsonConfig.DateTime.ISO8601);
ScalarTypeZonedDateTime typeIso = new ScalarTypeZonedDateTime(JsonConfig.DateTime.ISO8601, ZoneId.systemDefault());
jsonTester = new JsonTester<>(typeIso);
jsonTester.test(now);
}
@@ -80,7 +119,7 @@ public class ScalarTypeZonedDateTimeTest {
@Test
public void toJsonISO8601() {
ScalarTypeZonedDateTime typeIso = new ScalarTypeZonedDateTime(JsonConfig.DateTime.ISO8601);
ScalarTypeZonedDateTime typeIso = new ScalarTypeZonedDateTime(JsonConfig.DateTime.ISO8601, ZoneId.systemDefault());
ZonedDateTime now = ZonedDateTime.now();
String asJson = typeIso.toJsonISO8601(now);