Skip to content

Commit 6984e99

Browse files
fix: Fix DST issue on UTC conversion
1 parent ce86181 commit 6984e99

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

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

Lines changed: 11 additions & 1 deletion
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. */
@@ -497,9 +498,18 @@ private static java.sql.Timestamp getOrSetTimestampInCalendar(
497498
// set the millisecond time on this calendar from the timestamp
498499
newCal.setTimeInMillis(sqlTs.getTime());
499500
newCal.set(Calendar.MILLISECOND, 0);
501+
502+
TimeZone timeZone = newCal.getTimeZone();
503+
long totalMillis = newCal.getTimeInMillis();
504+
// to calculate the offset for DST correctly, we need to add DST savings and check if
505+
// given epoch milli is in daylight savings time.
506+
if (getOrSet == GetOrSetTimestampInCalendar.GET) {
507+
totalMillis += timeZone.getRawOffset() + timeZone.getDSTSavings();
508+
}
509+
500510
// then shift the time of the calendar by the difference between UTC and the timezone of the
501511
// given calendar
502-
int offset = newCal.getTimeZone().getOffset(newCal.getTimeInMillis());
512+
int offset = newCal.getTimeZone().getOffset(totalMillis);
503513
newCal.add(
504514
Calendar.MILLISECOND, getOrSet == GetOrSetTimestampInCalendar.GET ? offset : -offset);
505515
// then use that to create a sql timestamp

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

Lines changed: 19 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,23 @@ public void testDateToSqlTimestampWithCalendar() {
959961
.toSqlTimestamp());
960962
}
961963

964+
@Test
965+
public void testDateToSqlTimestampWithCalendarWithStartOfDST() {
966+
TimeZone timeZone = TimeZone.getTimeZone("Europe/Oslo");
967+
968+
ZonedDateTime expected = ZonedDateTime.of(2018, 3, 25, 2, 0, 0, 0, ZoneId.of("+01:00"));
969+
Timestamp expectedTimestamp = Timestamp.from(expected.toInstant());
970+
Calendar cal = Calendar.getInstance(timeZone);
971+
Timestamp storeTimestamp = JdbcTypeConverter.setTimestampInCalendar(expectedTimestamp, cal);
972+
973+
Timestamp resultTimestamp = JdbcTypeConverter.getTimestampInCalendar(storeTimestamp, cal);
974+
ZonedDateTime actual = resultTimestamp.toInstant().atZone(timeZone.toZoneId());
975+
976+
assertThat(actual).isEqualTo(expected.withZoneSameInstant(timeZone.toZoneId()));
977+
978+
TimeZone.setDefault(TimeZone.getDefault());
979+
}
980+
962981
@Test
963982
public void testParseSqlTimeWithCalendar() {
964983
assertThat(

0 commit comments

Comments
 (0)