Skip to content

Commit 531249e

Browse files
Lexert19Lexert19
authored andcommitted
[IOTDB-17433] Fix timezone offset bug in DateTimeUtils
1 parent c91688b commit 531249e

2 files changed

Lines changed: 97 additions & 6 deletions

File tree

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DateTimeUtils.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -558,14 +558,14 @@ public static long convertTimestampOrDatetimeStrToLongWithDefaultZone(String tim
558558
public static long convertDatetimeStrToLong(String str, ZoneId zoneId) {
559559
return convertDatetimeStrToLong(
560560
str,
561-
toZoneOffset(zoneId),
561+
toZoneOffset(str, zoneId),
562562
0,
563563
CommonDescriptor.getInstance().getConfig().getTimestampPrecision());
564564
}
565565

566566
public static long convertDatetimeStrToLong(
567567
String str, ZoneId zoneId, String timestampPrecision) {
568-
return convertDatetimeStrToLong(str, toZoneOffset(zoneId), 0, timestampPrecision);
568+
return convertDatetimeStrToLong(str, toZoneOffset(str, zoneId), 0, timestampPrecision);
569569
}
570570

571571
public static long getInstantWithPrecision(String str, String timestampPrecision) {
@@ -821,8 +821,20 @@ public static ZonedDateTime convertToZonedDateTime(long timestamp, ZoneId zoneId
821821
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(timestamp), zoneId);
822822
}
823823

824-
public static ZoneOffset toZoneOffset(ZoneId zoneId) {
825-
return zoneId.getRules().getOffset(Instant.now());
824+
public static ZoneOffset toZoneOffset(String str, ZoneId zoneId) {
825+
if (str.endsWith("Z")) {
826+
return ZoneOffset.UTC;
827+
}
828+
829+
int offsetIndex = Math.max(str.lastIndexOf('+'), str.lastIndexOf('-'));
830+
if (offsetIndex != -1 && str.length() - offsetIndex == 6) {
831+
return ZoneOffset.of(str.substring(offsetIndex));
832+
}
833+
834+
long millis = convertDatetimeStrToLong(str, ZoneOffset.UTC, 0, "ms");
835+
LocalDateTime localDateTime =
836+
LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneOffset.UTC);
837+
return zoneId.getRules().getOffset(localDateTime);
826838
}
827839

828840
public static ZonedDateTime convertMillsecondToZonedDateTime(long millisecond) {

iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/DateTimeUtilsTest.java

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
import org.junit.Ignore;
2828
import org.junit.Test;
2929

30+
import java.time.DateTimeException;
31+
import java.time.Instant;
3032
import java.time.ZoneId;
3133
import java.time.ZoneOffset;
32-
import java.time.ZonedDateTime;
3334
import java.util.TimeZone;
3435

3536
import static org.junit.Assert.assertEquals;
37+
import static org.junit.Assert.assertThrows;
3638
import static org.junit.Assert.fail;
3739

3840
public class DateTimeUtilsTest {
@@ -47,7 +49,7 @@ public class DateTimeUtilsTest {
4749
/** Test convertDatetimeStrToLong() method with different time precision. */
4850
@Test
4951
public void convertDatetimeStrToLongTest1() {
50-
zoneOffset = ZonedDateTime.now().getOffset();
52+
zoneOffset = Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).getOffset();
5153
zoneId = ZoneId.systemDefault();
5254
if (zoneOffset.toString().equals("Z")) {
5355
delta = 8 * 3600000;
@@ -338,4 +340,81 @@ public void testConstructTimeDuration() {
338340
timeDuration = DateTimeUtils.constructTimeDuration("10000000000ms");
339341
Assert.assertEquals(10000000000L, timeDuration.nonMonthDuration);
340342
}
343+
344+
@Test
345+
public void testToZoneOffsetForWinterTime() {
346+
ZoneId zoneId = ZoneId.of("Europe/Warsaw");
347+
ZoneOffset offset = DateTimeUtils.toZoneOffset("2024-01-15 12:00:00", zoneId);
348+
Assert.assertEquals(ZoneOffset.ofHours(1), offset);
349+
}
350+
351+
@Test
352+
public void testToZoneOffsetForSummerTime() {
353+
ZoneId zoneId = ZoneId.of("Europe/Warsaw");
354+
ZoneOffset offset = DateTimeUtils.toZoneOffset("2024-06-15 12:00:00", zoneId);
355+
Assert.assertEquals(ZoneOffset.ofHours(2), offset);
356+
}
357+
358+
@Test
359+
public void testToZoneOffsetJustBeforeSpringDST() {
360+
ZoneId zoneId = ZoneId.of("Europe/Warsaw");
361+
ZoneOffset offset = DateTimeUtils.toZoneOffset("2024-03-31 02:00:00", zoneId);
362+
Assert.assertEquals(ZoneOffset.ofHours(1), offset);
363+
}
364+
365+
@Test
366+
public void testToZoneOffsetJustAfterSpringDST() {
367+
ZoneId zoneId = ZoneId.of("Europe/Warsaw");
368+
ZoneOffset offset = DateTimeUtils.toZoneOffset("2024-03-31 03:00:00", zoneId);
369+
Assert.assertEquals(ZoneOffset.ofHours(2), offset);
370+
}
371+
372+
@Test
373+
public void testToZoneOffsetDuringSpringDSTGap() {
374+
ZoneId zoneId = ZoneId.of("Europe/Warsaw");
375+
ZoneOffset offset = DateTimeUtils.toZoneOffset("2024-03-31 02:30:00", zoneId);
376+
Assert.assertEquals(ZoneOffset.ofHours(1), offset);
377+
}
378+
379+
@Test
380+
public void testToZoneOffsetDuringAutumnDSTTransition() {
381+
ZoneId zoneId = ZoneId.of("Europe/Warsaw");
382+
ZoneOffset offset = DateTimeUtils.toZoneOffset("2024-10-27 02:30:00", zoneId);
383+
Assert.assertEquals(ZoneOffset.ofHours(2), offset);
384+
}
385+
386+
@Test
387+
public void testToZoneOffsetAfterAutumnDST() {
388+
ZoneId zoneId = ZoneId.of("Europe/Warsaw");
389+
ZoneOffset offset = DateTimeUtils.toZoneOffset("2024-10-27 03:00:00", zoneId);
390+
Assert.assertEquals(ZoneOffset.ofHours(1), offset);
391+
}
392+
393+
@Test
394+
public void testToZoneOffsetWithExplicitOffsetInString() {
395+
ZoneId zoneId = ZoneId.of("Europe/Warsaw");
396+
ZoneOffset offset = DateTimeUtils.toZoneOffset("2024-06-15 12:00:00+02:00", zoneId);
397+
Assert.assertEquals(ZoneOffset.ofHours(2), offset);
398+
offset = DateTimeUtils.toZoneOffset("2024-06-15 12:00:00Z", zoneId);
399+
Assert.assertEquals(ZoneOffset.UTC, offset);
400+
offset = DateTimeUtils.toZoneOffset("2024-06-15 12:00:00-08:00", zoneId);
401+
Assert.assertEquals(ZoneOffset.ofHours(-8), offset);
402+
}
403+
404+
@Test
405+
public void testToZoneOffsetWithUTCZoneId() {
406+
ZoneId utc = ZoneId.of("UTC");
407+
Assert.assertEquals(ZoneOffset.UTC, DateTimeUtils.toZoneOffset("2024-06-15 12:00:00", utc));
408+
}
409+
410+
@Test
411+
public void testToZoneOffsetWithBrokenDate() {
412+
ZoneId zoneId = ZoneId.of("Europe/Warsaw");
413+
DateTimeException exception =
414+
assertThrows(
415+
DateTimeException.class,
416+
() -> {
417+
DateTimeUtils.toZoneOffset("2024-12-31 10", zoneId);
418+
});
419+
}
341420
}

0 commit comments

Comments
 (0)