Skip to content

Commit 90c542e

Browse files
fix: Fix DST issue on UTC conversion
1 parent ce86181 commit 90c542e

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

src/main/java/com/google/cloud/spanner/jdbc/JdbcTypeConverter.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.util.Arrays;
4444
import java.util.Calendar;
4545
import java.util.List;
46+
import java.util.TimeZone;
4647
import java.util.concurrent.TimeUnit;
4748

4849
/** Convenience class for converting values between Java, JDBC and Cloud Spanner. */
@@ -496,10 +497,18 @@ private static java.sql.Timestamp getOrSetTimestampInCalendar(
496497
Calendar newCal = Calendar.getInstance(cal.getTimeZone());
497498
// set the millisecond time on this calendar from the timestamp
498499
newCal.setTimeInMillis(sqlTs.getTime());
499-
newCal.set(Calendar.MILLISECOND, 0);
500+
501+
TimeZone timeZone = newCal.getTimeZone();
502+
long totalMillis = newCal.getTimeInMillis();
503+
// to calculate the offset for DST correctly, we need to add DST savings and check if
504+
// given epoch milli is in daylight savings time.
505+
if (getOrSet == GetOrSetTimestampInCalendar.GET) {
506+
totalMillis += timeZone.getRawOffset() + timeZone.getDSTSavings();
507+
}
508+
500509
// then shift the time of the calendar by the difference between UTC and the timezone of the
501510
// given calendar
502-
int offset = newCal.getTimeZone().getOffset(newCal.getTimeInMillis());
511+
int offset = newCal.getTimeZone().getOffset(totalMillis);
503512
newCal.add(
504513
Calendar.MILLISECOND, getOrSet == GetOrSetTimestampInCalendar.GET ? offset : -offset);
505514
// then use that to create a sql timestamp

src/test/java/com/google/cloud/spanner/jdbc/JdbcTypeConverterTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
import java.sql.Time;
5252
import java.sql.Timestamp;
5353
import java.text.DecimalFormat;
54+
import java.time.ZoneId;
55+
import java.time.ZonedDateTime;
5456
import java.util.ArrayList;
5557
import java.util.Arrays;
5658
import java.util.Calendar;
@@ -959,6 +961,31 @@ public void testDateToSqlTimestampWithCalendar() {
959961
.toSqlTimestamp());
960962
}
961963

964+
@Test
965+
public void testDateToSqlTimestampWithCalendarWithStartOfDST() {
966+
TimeZone timeZone = TimeZone.getTimeZone("Europe/Oslo");
967+
968+
List<ZonedDateTime> zonedDateTimes =
969+
Arrays.asList(
970+
ZonedDateTime.of(2018, 3, 25, 2, 0, 0, 0, ZoneId.of("+01:00")),
971+
ZonedDateTime.of(2018, 10, 28, 2, 0, 0, 0, ZoneId.of("+01:00")));
972+
973+
zonedDateTimes.forEach(
974+
expected -> {
975+
Timestamp expectedTimestamp = Timestamp.from(expected.toInstant());
976+
Calendar cal = Calendar.getInstance(timeZone);
977+
Timestamp storeTimestamp =
978+
JdbcTypeConverter.setTimestampInCalendar(expectedTimestamp, cal);
979+
980+
Timestamp resultTimestamp = JdbcTypeConverter.getTimestampInCalendar(storeTimestamp, cal);
981+
ZonedDateTime actual = resultTimestamp.toInstant().atZone(timeZone.toZoneId());
982+
983+
assertThat(actual).isEqualTo(expected.withZoneSameInstant(timeZone.toZoneId()));
984+
});
985+
986+
TimeZone.setDefault(TimeZone.getDefault());
987+
}
988+
962989
@Test
963990
public void testParseSqlTimeWithCalendar() {
964991
assertThat(

0 commit comments

Comments
 (0)