-
Bug
-
Resolution: Not an Issue
-
P3
-
None
-
9
-
generic
-
generic
FULL PRODUCT VERSION :
java version "9"
Java(TM) SE Runtime Environment (build 9+176)
Java HotSpot(TM) 64-Bit Server VM (build 9+176, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
macOS 10.12.5
A DESCRIPTION OF THE PROBLEM :
getLong(ChronoField.INSTANT_SECONDS) of the TemporalAccessor returned by DateTimeFormatter.parse(String) returns the wrong value.
It appears that getLong(ChronoField.OFFSET_SECONDS) is subtracted from that value erroneously.
The code below worked as expected in Java 8 but produces invalid values in Java 9.
I'd appreciate any hints about how to write code that works with both Java 8 and Java 9 if this is not a bug.
REGRESSION. Last worked in version 8u131
ADDITIONAL REGRESSION INFORMATION:
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
- Compile the code in the "Source code for an executable test case" field with Java 8.
- Execute "java Java9TimeBug" using Java 8. This produces the "Expected Result".
- Execute "java Java9TimeBug" using Java 9. This produces the "Actual Result".
Compiling the code with Java 9 does not make a difference regarding "Actual Result".
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00.000+0100".
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00.000+01:00".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000+0000".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000+00:00".
instantSeconds: 1258243200
offsetSeconds: -28800
Everything fine for "2009-11-15T00:00:00.000-0800".
instantSeconds: 1258243200
offsetSeconds: -28800
Everything fine for "2009-11-15T00:00:00.000-08:00".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000Z".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00Z".
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00.017+0100".
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00.017+01:00".
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00+0100".
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00+01:00".
ACTUAL -
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00.000+0100" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-15T01:00:00.000+00:00"!
Input "2009-11-15T00:00:00.000+0100" returned 1258243200000 instead of 1258246800000!
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00.000+01:00" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-15T01:00:00.000+00:00"!
Input "2009-11-15T00:00:00.000+01:00" returned 1258243200000 instead of 1258246800000!
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000+0000".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000+00:00".
instantSeconds: 1258272000
offsetSeconds: -28800
Input "2009-11-15T00:00:00.000-0800" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-14T16:00:00.000+00:00"!
Input "2009-11-15T00:00:00.000-0800" returned 1258243200000 instead of 1258214400000!
instantSeconds: 1258272000
offsetSeconds: -28800
Input "2009-11-15T00:00:00.000-08:00" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-14T16:00:00.000+00:00"!
Input "2009-11-15T00:00:00.000-08:00" returned 1258243200000 instead of 1258214400000!
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000Z".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00Z".
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00.017+0100" returned "2009-11-15T00:00:00.017+00:00" instead of "2009-11-15T01:00:00.017+00:00"!
Input "2009-11-15T00:00:00.017+0100" returned 1258243200017 instead of 1258246800017!
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00.017+01:00" returned "2009-11-15T00:00:00.017+00:00" instead of "2009-11-15T01:00:00.017+00:00"!
Input "2009-11-15T00:00:00.017+01:00" returned 1258243200017 instead of 1258246800017!
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00+0100" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-15T01:00:00.000+00:00"!
Input "2009-11-15T00:00:00+0100" returned 1258243200000 instead of 1258246800000!
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00+01:00" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-15T01:00:00.000+00:00"!
Input "2009-11-15T00:00:00+01:00" returned 1258243200000 instead of 1258246800000!
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.text.ParseException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Java9TimeBug {
public static class DateTimeFormatter {
private static final String TIMEZONE_DATE_FORMAT_PATTERN = ".*([+-]\\d{2})(\\d{2})$";
private static final int TIMEZONE_DATE_FORMAT_LENGTH = 5;
private static final java.time.format.DateTimeFormatter ISO_DATE_TIME_PARSER =
new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.appendValue(ChronoField.HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR, 2)
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE, 2)
.optionalStart()
.appendFraction(ChronoField.MILLI_OF_SECOND, 3, 3, true)
.optionalEnd()
.appendOffset("+HH:MM", "Z")
.toFormatter()
.withZone(ZoneOffset.UTC);
private static final java.time.format.DateTimeFormatter ISO_DATE_TIME_FORMATTER_WITH_MILLIS =
new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.appendValue(ChronoField.HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR, 2)
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE, 2)
.appendFraction(ChronoField.MILLI_OF_SECOND, 3, 3, true)
.appendOffset("+HH:MM", "+00:00")
.toFormatter()
.withZone(ZoneOffset.UTC);
private final Pattern javaTimezonePattern = Pattern.compile(TIMEZONE_DATE_FORMAT_PATTERN);
/**
* This method parses a given string containing a dateTime in ISO8601 notation into a date.
*
* It can handle an optional millisecond fraction as well as timezone with either explicit '+/-HH:MM' or 'Z' UTC designator.
*
* @param dateTime a string containing a dateTime in ISO8601 notation.
* @return the parsed date
* @throws ParseException If the dateTime string is invalid.
*/
public Date parse(String dateTime)
throws ParseException {
Matcher matcher = javaTimezonePattern.matcher(dateTime);
if(matcher.matches()) {
// correct +/-hhmm to +/-hh:mm
String hh = matcher.group(1);
String mm = matcher.group(2);
dateTime = dateTime.substring(0, dateTime.length() - TIMEZONE_DATE_FORMAT_LENGTH) + hh + ":" + mm;
}
TemporalAccessor temporal = ISO_DATE_TIME_PARSER.parse(dateTime);
long instantSeconds = temporal.getLong(ChronoField.INSTANT_SECONDS);
long offsetSeconds = temporal.getLong(ChronoField.OFFSET_SECONDS);
System.out.println("instantSeconds: "+instantSeconds);
System.out.println("offsetSeconds: "+offsetSeconds);
long seconds = instantSeconds + offsetSeconds;
long millis = seconds * 1000 + temporal.getLong(ChronoField.MILLI_OF_SECOND);
return new Date(millis);
}
/**
* Returns a simplified ISO8601 datetime string in UTC.
*
* It will always contain a three-number millisecond field regardless if it is "needed"
* (i.e. MILLI_OF_SECOND != 0) or not. The timezone of the date is always UTC but isn't using
* the UTC designator 'Z'. Instead, it's using an explicit '+00:00'.
*
* That way a date formatted by this method will always have the same number of characters while creating output
* that less intelligent date-parsing frameworks (incapable of the 'Z' notation) are still able to process.
*
* @param date the date to be formatted.
* @return a simplified ISO8601 datetime string in UTC.
*/
public String format(Date date) {
Instant instant = Instant.ofEpochMilli(date.getTime());
ZonedDateTime zoned = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
return ISO_DATE_TIME_FORMATTER_WITH_MILLIS.format(zoned);
}
}
public static void main(String[] args) throws Exception {
DateTimeFormatter formatter = new DateTimeFormatter();
testcases(formatter);
}
public static void testcases(DateTimeFormatter formatter) throws Exception {
final String[] inputs = new String[]{
"2009-11-15T00:00:00.000+0100",
"2009-11-15T00:00:00.000+01:00",
"2009-11-15T00:00:00.000+0000",
"2009-11-15T00:00:00.000+00:00",
"2009-11-15T00:00:00.000-0800",
"2009-11-15T00:00:00.000-08:00",
"2009-11-15T00:00:00.000Z",
"2009-11-15T00:00:00Z",
"2009-11-15T00:00:00.017+0100",
"2009-11-15T00:00:00.017+01:00",
"2009-11-15T00:00:00+0100",
"2009-11-15T00:00:00+01:00",
};
final long[] expectedMillis = new long[] {
1258246800000L,
1258246800000L,
1258243200000L,
1258243200000L,
1258214400000L,
1258214400000L,
1258243200000L,
1258243200000L,
1258246800017L,
1258246800017L,
1258246800000L,
1258246800000L,
};
final String[] expectedResults = new String[]{
"2009-11-15T01:00:00.000+00:00",
"2009-11-15T01:00:00.000+00:00",
"2009-11-15T00:00:00.000+00:00",
"2009-11-15T00:00:00.000+00:00",
"2009-11-14T16:00:00.000+00:00",
"2009-11-14T16:00:00.000+00:00",
"2009-11-15T00:00:00.000+00:00",
"2009-11-15T00:00:00.000+00:00",
"2009-11-15T01:00:00.017+00:00",
"2009-11-15T01:00:00.017+00:00",
"2009-11-15T01:00:00.000+00:00",
"2009-11-15T01:00:00.000+00:00",
};
for(int i=0;i<inputs.length;i++) {
Date parsedDate = formatter.parse(inputs[i]);
String result = formatter.format(parsedDate);
check(inputs[i], result, expectedResults[i], parsedDate.getTime(), expectedMillis[i]);
}
}
public static void check(String input, String result, String expectedResult, long resultMillis, long expectedMillis) {
if(result.equals(expectedResult)) {
System.out.println("Everything fine for \""+input+"\".\n");
} else {
System.out.println("Input \""+input+"\" returned \""+result+"\" instead of \""+expectedResult+"\"!");
System.out.println("Input \""+input+"\" returned "+resultMillis+" instead of "+expectedMillis+"!\n");
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
unknown
java version "9"
Java(TM) SE Runtime Environment (build 9+176)
Java HotSpot(TM) 64-Bit Server VM (build 9+176, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
macOS 10.12.5
A DESCRIPTION OF THE PROBLEM :
getLong(ChronoField.INSTANT_SECONDS) of the TemporalAccessor returned by DateTimeFormatter.parse(String) returns the wrong value.
It appears that getLong(ChronoField.OFFSET_SECONDS) is subtracted from that value erroneously.
The code below worked as expected in Java 8 but produces invalid values in Java 9.
I'd appreciate any hints about how to write code that works with both Java 8 and Java 9 if this is not a bug.
REGRESSION. Last worked in version 8u131
ADDITIONAL REGRESSION INFORMATION:
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
- Compile the code in the "Source code for an executable test case" field with Java 8.
- Execute "java Java9TimeBug" using Java 8. This produces the "Expected Result".
- Execute "java Java9TimeBug" using Java 9. This produces the "Actual Result".
Compiling the code with Java 9 does not make a difference regarding "Actual Result".
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00.000+0100".
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00.000+01:00".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000+0000".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000+00:00".
instantSeconds: 1258243200
offsetSeconds: -28800
Everything fine for "2009-11-15T00:00:00.000-0800".
instantSeconds: 1258243200
offsetSeconds: -28800
Everything fine for "2009-11-15T00:00:00.000-08:00".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000Z".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00Z".
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00.017+0100".
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00.017+01:00".
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00+0100".
instantSeconds: 1258243200
offsetSeconds: 3600
Everything fine for "2009-11-15T00:00:00+01:00".
ACTUAL -
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00.000+0100" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-15T01:00:00.000+00:00"!
Input "2009-11-15T00:00:00.000+0100" returned 1258243200000 instead of 1258246800000!
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00.000+01:00" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-15T01:00:00.000+00:00"!
Input "2009-11-15T00:00:00.000+01:00" returned 1258243200000 instead of 1258246800000!
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000+0000".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000+00:00".
instantSeconds: 1258272000
offsetSeconds: -28800
Input "2009-11-15T00:00:00.000-0800" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-14T16:00:00.000+00:00"!
Input "2009-11-15T00:00:00.000-0800" returned 1258243200000 instead of 1258214400000!
instantSeconds: 1258272000
offsetSeconds: -28800
Input "2009-11-15T00:00:00.000-08:00" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-14T16:00:00.000+00:00"!
Input "2009-11-15T00:00:00.000-08:00" returned 1258243200000 instead of 1258214400000!
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00.000Z".
instantSeconds: 1258243200
offsetSeconds: 0
Everything fine for "2009-11-15T00:00:00Z".
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00.017+0100" returned "2009-11-15T00:00:00.017+00:00" instead of "2009-11-15T01:00:00.017+00:00"!
Input "2009-11-15T00:00:00.017+0100" returned 1258243200017 instead of 1258246800017!
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00.017+01:00" returned "2009-11-15T00:00:00.017+00:00" instead of "2009-11-15T01:00:00.017+00:00"!
Input "2009-11-15T00:00:00.017+01:00" returned 1258243200017 instead of 1258246800017!
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00+0100" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-15T01:00:00.000+00:00"!
Input "2009-11-15T00:00:00+0100" returned 1258243200000 instead of 1258246800000!
instantSeconds: 1258239600
offsetSeconds: 3600
Input "2009-11-15T00:00:00+01:00" returned "2009-11-15T00:00:00.000+00:00" instead of "2009-11-15T01:00:00.000+00:00"!
Input "2009-11-15T00:00:00+01:00" returned 1258243200000 instead of 1258246800000!
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.text.ParseException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Java9TimeBug {
public static class DateTimeFormatter {
private static final String TIMEZONE_DATE_FORMAT_PATTERN = ".*([+-]\\d{2})(\\d{2})$";
private static final int TIMEZONE_DATE_FORMAT_LENGTH = 5;
private static final java.time.format.DateTimeFormatter ISO_DATE_TIME_PARSER =
new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.appendValue(ChronoField.HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR, 2)
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE, 2)
.optionalStart()
.appendFraction(ChronoField.MILLI_OF_SECOND, 3, 3, true)
.optionalEnd()
.appendOffset("+HH:MM", "Z")
.toFormatter()
.withZone(ZoneOffset.UTC);
private static final java.time.format.DateTimeFormatter ISO_DATE_TIME_FORMATTER_WITH_MILLIS =
new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.appendValue(ChronoField.HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR, 2)
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE, 2)
.appendFraction(ChronoField.MILLI_OF_SECOND, 3, 3, true)
.appendOffset("+HH:MM", "+00:00")
.toFormatter()
.withZone(ZoneOffset.UTC);
private final Pattern javaTimezonePattern = Pattern.compile(TIMEZONE_DATE_FORMAT_PATTERN);
/**
* This method parses a given string containing a dateTime in ISO8601 notation into a date.
*
* It can handle an optional millisecond fraction as well as timezone with either explicit '+/-HH:MM' or 'Z' UTC designator.
*
* @param dateTime a string containing a dateTime in ISO8601 notation.
* @return the parsed date
* @throws ParseException If the dateTime string is invalid.
*/
public Date parse(String dateTime)
throws ParseException {
Matcher matcher = javaTimezonePattern.matcher(dateTime);
if(matcher.matches()) {
// correct +/-hhmm to +/-hh:mm
String hh = matcher.group(1);
String mm = matcher.group(2);
dateTime = dateTime.substring(0, dateTime.length() - TIMEZONE_DATE_FORMAT_LENGTH) + hh + ":" + mm;
}
TemporalAccessor temporal = ISO_DATE_TIME_PARSER.parse(dateTime);
long instantSeconds = temporal.getLong(ChronoField.INSTANT_SECONDS);
long offsetSeconds = temporal.getLong(ChronoField.OFFSET_SECONDS);
System.out.println("instantSeconds: "+instantSeconds);
System.out.println("offsetSeconds: "+offsetSeconds);
long seconds = instantSeconds + offsetSeconds;
long millis = seconds * 1000 + temporal.getLong(ChronoField.MILLI_OF_SECOND);
return new Date(millis);
}
/**
* Returns a simplified ISO8601 datetime string in UTC.
*
* It will always contain a three-number millisecond field regardless if it is "needed"
* (i.e. MILLI_OF_SECOND != 0) or not. The timezone of the date is always UTC but isn't using
* the UTC designator 'Z'. Instead, it's using an explicit '+00:00'.
*
* That way a date formatted by this method will always have the same number of characters while creating output
* that less intelligent date-parsing frameworks (incapable of the 'Z' notation) are still able to process.
*
* @param date the date to be formatted.
* @return a simplified ISO8601 datetime string in UTC.
*/
public String format(Date date) {
Instant instant = Instant.ofEpochMilli(date.getTime());
ZonedDateTime zoned = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
return ISO_DATE_TIME_FORMATTER_WITH_MILLIS.format(zoned);
}
}
public static void main(String[] args) throws Exception {
DateTimeFormatter formatter = new DateTimeFormatter();
testcases(formatter);
}
public static void testcases(DateTimeFormatter formatter) throws Exception {
final String[] inputs = new String[]{
"2009-11-15T00:00:00.000+0100",
"2009-11-15T00:00:00.000+01:00",
"2009-11-15T00:00:00.000+0000",
"2009-11-15T00:00:00.000+00:00",
"2009-11-15T00:00:00.000-0800",
"2009-11-15T00:00:00.000-08:00",
"2009-11-15T00:00:00.000Z",
"2009-11-15T00:00:00Z",
"2009-11-15T00:00:00.017+0100",
"2009-11-15T00:00:00.017+01:00",
"2009-11-15T00:00:00+0100",
"2009-11-15T00:00:00+01:00",
};
final long[] expectedMillis = new long[] {
1258246800000L,
1258246800000L,
1258243200000L,
1258243200000L,
1258214400000L,
1258214400000L,
1258243200000L,
1258243200000L,
1258246800017L,
1258246800017L,
1258246800000L,
1258246800000L,
};
final String[] expectedResults = new String[]{
"2009-11-15T01:00:00.000+00:00",
"2009-11-15T01:00:00.000+00:00",
"2009-11-15T00:00:00.000+00:00",
"2009-11-15T00:00:00.000+00:00",
"2009-11-14T16:00:00.000+00:00",
"2009-11-14T16:00:00.000+00:00",
"2009-11-15T00:00:00.000+00:00",
"2009-11-15T00:00:00.000+00:00",
"2009-11-15T01:00:00.017+00:00",
"2009-11-15T01:00:00.017+00:00",
"2009-11-15T01:00:00.000+00:00",
"2009-11-15T01:00:00.000+00:00",
};
for(int i=0;i<inputs.length;i++) {
Date parsedDate = formatter.parse(inputs[i]);
String result = formatter.format(parsedDate);
check(inputs[i], result, expectedResults[i], parsedDate.getTime(), expectedMillis[i]);
}
}
public static void check(String input, String result, String expectedResult, long resultMillis, long expectedMillis) {
if(result.equals(expectedResult)) {
System.out.println("Everything fine for \""+input+"\".\n");
} else {
System.out.println("Input \""+input+"\" returned \""+result+"\" instead of \""+expectedResult+"\"!");
System.out.println("Input \""+input+"\" returned "+resultMillis+" instead of "+expectedMillis+"!\n");
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
unknown
- relates to
-
JDK-8066982 ZonedDateTime.parse() returns wrong ZoneOffset around DST fall transition
-
- Resolved
-