Skip to content

Commit fe7d708

Browse files
committed
8272473: Parsing epoch seconds at a DST transition with a non-UTC parser is wrong
Reviewed-by: joehw, rriggs, iris, lancea, scolebourne
1 parent 845e1ce commit fe7d708

File tree

2 files changed

+14
-6
lines changed

2 files changed

+14
-6
lines changed

src/java.base/share/classes/java/time/format/Parsed.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -354,10 +354,11 @@ private void resolveInstantFields() {
354354
}
355355

356356
private void resolveInstantFields0(ZoneId selectedZone) {
357-
Instant instant = Instant.ofEpochSecond(fieldValues.remove(INSTANT_SECONDS));
357+
Instant instant = Instant.ofEpochSecond(fieldValues.get(INSTANT_SECONDS));
358358
ChronoZonedDateTime<?> zdt = chrono.zonedDateTime(instant, selectedZone);
359359
updateCheckConflict(zdt.toLocalDate());
360360
updateCheckConflict(INSTANT_SECONDS, SECOND_OF_DAY, (long) zdt.toLocalTime().toSecondOfDay());
361+
updateCheckConflict(INSTANT_SECONDS, OFFSET_SECONDS, (long) zdt.getOffset().getTotalSeconds());
361362
}
362363

363364
//-----------------------------------------------------------------------
@@ -641,9 +642,9 @@ private void resolveFractional() {
641642
}
642643

643644
private void resolveInstant() {
644-
// add instant seconds if we have date, time and zone
645+
// add instant seconds (if not present) if we have date, time and zone
645646
// Offset (if present) will be given priority over the zone.
646-
if (date != null && time != null) {
647+
if (!fieldValues.containsKey(INSTANT_SECONDS) && date != null && time != null) {
647648
Long offsetSecs = fieldValues.get(OFFSET_SECONDS);
648649
if (offsetSecs != null) {
649650
ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue());

test/jdk/java/time/test/java/time/format/TestDateTimeParsing.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -88,11 +88,12 @@
8888
/**
8989
* @test
9090
* @summary Test parsing of edge cases.
91-
* @bug 8223773
91+
* @bug 8223773 8272473
9292
*/
9393
public class TestDateTimeParsing {
9494

9595
private static final ZoneId PARIS = ZoneId.of("Europe/Paris");
96+
private static final ZoneId NEW_YORK = ZoneId.of("America/New_York");
9697
private static final ZoneOffset OFFSET_0230 = ZoneOffset.ofHoursMinutes(2, 30);
9798

9899
private static final DateTimeFormatter LOCALFIELDS = new DateTimeFormatterBuilder()
@@ -107,6 +108,7 @@ public class TestDateTimeParsing {
107108
.appendInstant().toFormatter();
108109
private static final DateTimeFormatter INSTANT_WITH_PARIS = INSTANT.withZone(PARIS);
109110
private static final DateTimeFormatter INSTANT_WITH_0230 = INSTANT.withZone(OFFSET_0230);
111+
private static final DateTimeFormatter INSTANT_WITH_NEW_YORK = INSTANT.withZone(NEW_YORK);
110112
private static final DateTimeFormatter INSTANT_OFFSETID = new DateTimeFormatterBuilder()
111113
.appendInstant().appendLiteral(' ').appendOffsetId().toFormatter();
112114
private static final DateTimeFormatter INSTANT_OFFSETSECONDS = new DateTimeFormatterBuilder()
@@ -119,6 +121,7 @@ public class TestDateTimeParsing {
119121
private static final DateTimeFormatter INSTANTSECONDS_NOS_WITH_PARIS = INSTANTSECONDS_NOS.withZone(PARIS);
120122
private static final DateTimeFormatter INSTANTSECONDS_OFFSETSECONDS = new DateTimeFormatterBuilder()
121123
.appendValue(INSTANT_SECONDS).appendLiteral(' ').appendValue(OFFSET_SECONDS).toFormatter();
124+
private static final DateTimeFormatter INSTANTSECONDS_WITH_NEW_YORK = INSTANTSECONDS.withZone(NEW_YORK);
122125

123126
private static final String DTPE_MESSAGE =
124127
"Invalid value for HourOfAmPm (valid values 0 - 11): 12";
@@ -133,11 +136,15 @@ Object[][] data_instantZones() {
133136
{LOCALFIELDS_WITH_0230, "2014-06-30 01:02:03", ZonedDateTime.of(2014, 6, 30, 1, 2, 3, 0, OFFSET_0230)},
134137
{INSTANT_WITH_PARIS, "2014-06-30T01:02:03Z", ZonedDateTime.of(2014, 6, 30, 1, 2, 3, 0, ZoneOffset.UTC).withZoneSameInstant(PARIS)},
135138
{INSTANT_WITH_0230, "2014-06-30T01:02:03Z", ZonedDateTime.of(2014, 6, 30, 1, 2, 3, 0, ZoneOffset.UTC).withZoneSameInstant(OFFSET_0230)},
139+
{INSTANT_WITH_NEW_YORK, "2020-11-01T05:00:00Z", ZonedDateTime.of(2020, 11, 1, 5, 0, 0, 0, ZoneOffset.UTC).withZoneSameInstant(NEW_YORK)},
140+
{INSTANT_WITH_NEW_YORK, "2020-11-01T06:00:00Z", ZonedDateTime.of(2020, 11, 1, 6, 0, 0, 0, ZoneOffset.UTC).withZoneSameInstant(NEW_YORK)},
136141
{INSTANT_OFFSETID, "2014-06-30T01:02:03Z +02:30", ZonedDateTime.of(2014, 6, 30, 1, 2, 3, 0, ZoneOffset.UTC).withZoneSameInstant(OFFSET_0230)},
137142
{INSTANT_OFFSETSECONDS, "2014-06-30T01:02:03Z 9000", ZonedDateTime.of(2014, 6, 30, 1, 2, 3, 0, ZoneOffset.UTC).withZoneSameInstant(OFFSET_0230)},
138143
{INSTANTSECONDS_WITH_PARIS, "86402", Instant.ofEpochSecond(86402).atZone(PARIS)},
139144
{INSTANTSECONDS_NOS_WITH_PARIS, "86402.123456789", Instant.ofEpochSecond(86402, 123456789).atZone(PARIS)},
140145
{INSTANTSECONDS_OFFSETSECONDS, "86402 9000", Instant.ofEpochSecond(86402).atZone(OFFSET_0230)},
146+
{INSTANTSECONDS_WITH_NEW_YORK, "1604206800", Instant.ofEpochSecond(1604206800).atZone(NEW_YORK)}, // 2020-11-01T05:00:00 UTC
147+
{INSTANTSECONDS_WITH_NEW_YORK, "1604210400", Instant.ofEpochSecond(1604210400).atZone(NEW_YORK)}, // 2020-11-01T06:00:00 UTC
141148
};
142149
}
143150

0 commit comments

Comments
 (0)