Enviroment
- Joda-Time 2.9.2 - 2.9.4
- TimeZone.getDefault(): sun.util.calendar.ZoneInfo[id="America/Chicago",offset=-21600000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]
- DateTimeZone.getDefault(): America/Chicago
Problem description
It appears that #332 actually made parsing worse as it fails to handle literals after ZoneIds.
2.9.1
2.9.1 is able to round trip (ZonedDateTime.toString()->DateTime->ZonedDateTime) 600 of 617 ZoneIds using a formatter designed to mimic ZonedDateTime's toString scheme (it is defined in the test below, it may not be perfect but worked for ~97% of ZoneIds).
Total Count: 617
Translation success Count: 600
Translation failed Count: 17
The failed ones are listed below:
- Etc/GMT Invalid format: "2016-07-13T19:26:56.352Z[Etc/GMT]" is malformed at "[Etc/GMT]"
- Etc/GMT+1 Invalid format: "2016-07-13T18:26:56.367-01:00[Etc/GMT+1]" is malformed at "[Etc/GMT+1]"
- Etc/GMT-1 Invalid format: "2016-07-13T20:26:56.367+01:00[Etc/GMT-1]" is malformed at "[Etc/GMT-1]"
- GMT Invalid format: "2016-07-13T19:26:56.461Z[GMT]" is malformed at "[GMT]"
- SystemV/AST4 Invalid format: "2016-07-13T15:26:56.508-04:00[SystemV/AST4]" is malformed at "[SystemV/AST4]"
- SystemV/AST4ADT Invalid format: "2016-07-13T16:26:56.508-03:00[SystemV/AST4ADT]" is malformed at "[SystemV/AST4ADT]"
- SystemV/CST6 Invalid format: "2016-07-13T13:26:56.508-06:00[SystemV/CST6]" is malformed at "[SystemV/CST6]"
- SystemV/CST6CDT Invalid format: "2016-07-13T14:26:56.508-05:00[SystemV/CST6CDT]" is malformed at "[SystemV/CST6CDT]"
- SystemV/EST5 Invalid format: "2016-07-13T14:26:56.508-05:00[SystemV/EST5]" is malformed at "[SystemV/EST5]"
- SystemV/EST5EDT Invalid format: "2016-07-13T15:26:56.508-04:00[SystemV/EST5EDT]" is malformed at "[SystemV/EST5EDT]"
- SystemV/HST10 Invalid format: "2016-07-13T09:26:56.508-10:00[SystemV/HST10]" is malformed at "[SystemV/HST10]"
- SystemV/MST7 Invalid format: "2016-07-13T12:26:56.508-07:00[SystemV/MST7]" is malformed at "[SystemV/MST7]"
- SystemV/MST7MDT Invalid format: "2016-07-13T13:26:56.508-06:00[SystemV/MST7MDT]" is malformed at "[SystemV/MST7MDT]"
- SystemV/PST8 Invalid format: "2016-07-13T11:26:56.508-08:00[SystemV/PST8]" is malformed at "[SystemV/PST8]"
- SystemV/PST8PDT Invalid format: "2016-07-13T12:26:56.508-07:00[SystemV/PST8PDT]" is malformed at "[SystemV/PST8PDT]"
- SystemV/YST9 Invalid format: "2016-07-13T10:26:56.508-09:00[SystemV/YST9]" is malformed at "[SystemV/YST9]"
- SystemV/YST9YDT Invalid format: "2016-07-13T11:26:56.508-08:00[SystemV/YST9YDT]" is malformed at "[SystemV/YST9YDT]"
2.9.2 - 2.9.4
Total Count: 617
Translation success Count: 3
Translation failed Count: 614
The 614 fail with errors like this one:
Invalid format: "2016-07-13T23:13:04.160+03:00[Africa/Addis_Ababa]" is malformed at "[Africa/Addis_Ababa]"
Test case
@Test
public void test() {
class Results {
final DateTimeFormatter ZONED_ISO_DATE_TIME_FORMATTER = new DateTimeFormatterBuilder().appendYear(4, 4)
.appendLiteral('-')
.appendMonthOfYear(2)
.appendLiteral('-')
.appendDayOfMonth(2)
.appendLiteral('T')
.appendHourOfDay(2)
.appendLiteral(':')
.appendMinuteOfHour(2)
.appendLiteral(':')
.appendSecondOfMinute(2)
.appendLiteral('.')
.appendFractionOfSecond(0, 9)
.appendTimeZoneOffset("Z", true, 2, 2)
.appendOptional(new DateTimeFormatterBuilder().appendLiteral('[')
.appendTimeZoneId()
.appendLiteral(']')
.toParser())
.toFormatter();
final DateTimeFormatter ZONED_ISO_DATE_TIME_PRINTER = new DateTimeFormatterBuilder().appendYear(4, 4)
.appendLiteral('-')
.appendMonthOfYear(2)
.appendLiteral('-')
.appendDayOfMonth(2)
.appendLiteral('T')
.appendHourOfDay(2)
.appendLiteral(':')
.appendMinuteOfHour(2)
.appendLiteral(':')
.appendSecondOfMinute(2)
.appendLiteral('.')
.appendFractionOfSecond(0, 9)
.appendTimeZoneOffset("Z", true, 2, 2)
.appendLiteral('[')
.appendTimeZoneId()
.appendLiteral(']')
.toFormatter();
final ZoneId zoneId;
final ZonedDateTime zonedDateTime;
final String zonedDateTimeAsString;
DateTime dateTime;
String dateTimeAsString;
String toDateTimeError;
ZonedDateTime zonedDateTimeFromDateTime;
String toZonedDateTimeError;
Boolean roundTripEquals;
Boolean roundTripIsEquals;
Results(ZoneId zoneId) {
this.zoneId = zoneId;
this.zonedDateTime = ZonedDateTime.now(zoneId);
this.zonedDateTimeAsString = this.zonedDateTime.toString();
this.toDateTime();
this.fromDateTime();
}
private void fromDateTime() {
if (this.dateTime != null) {
try {
this.zonedDateTimeFromDateTime = ZonedDateTime.parse(this.dateTimeAsString);
this.roundTripEquals = this.zonedDateTime.equals(this.zonedDateTimeFromDateTime);
this.roundTripIsEquals = this.zonedDateTime.isEqual(this.zonedDateTimeFromDateTime);
} catch (Exception e) {
this.toZonedDateTimeError = e.getMessage();
}
}
}
void toDateTime() {
try {
this.dateTime = this.ZONED_ISO_DATE_TIME_FORMATTER.parseDateTime(this.zonedDateTimeAsString);
this.dateTimeAsString = this.dateTime.toString(this.ZONED_ISO_DATE_TIME_PRINTER);
} catch (Exception e) {
this.toDateTimeError = e.getMessage();
}
}
public boolean failedToTranslation() {
return !(this.toDateTimeError == null && this.toZonedDateTimeError == null);
}
public boolean equalityFailed() {
return !this.failedToTranslation() && (!(this.roundTripEquals || this.roundTripIsEquals));
}
@Override
public String toString() {
return new StringBuilder().append(this.zoneId)
.append('-')
.append('[')
.append(this.failedToTranslation() ? "translation: failed" : "translation: passed")
.append(this.roundTripEquals != null ? this.equalityFailed() ? ", equality: failed"
: ", equality: passed" : "")
.append(']')
.append("\n\n\t")
.append("ZonedDateTime: ")
.append(this.zonedDateTimeAsString)
.append("\n\t")
.append(Optional.ofNullable(this.dateTime)
.map(dt -> "DateTime: " + this.dateTime)
.orElseGet(() -> "ZoneDateTime to DateTime error: " + this.toDateTimeError))
.append(Optional.ofNullable(this.dateTimeAsString)
.map(dts -> "\n\tDateTime As ISO String: " + dts)
.orElse(""))
.append(Optional.ofNullable(this.zonedDateTimeFromDateTime)
.map(rd -> "\n\tZonedDateTime from DateTime: " + rd)
.orElse(""))
.append(Optional.ofNullable(this.roundTripEquals)
.map(b -> "\n\tRound Trip ZonedDateTime equals: " + b)
.orElse(""))
.append(Optional.ofNullable(this.roundTripIsEquals)
.map(b -> "\n\tRound Trip ZonedDateTime isEquals: " + b)
.orElse(""))
.append(Optional.ofNullable(this.toZonedDateTimeError)
.map(err -> "\n\tDateTime to ZonedDateTime error: " + err)
.orElse(""))
.append("\n\n")
.toString();
}
}
List<Results> results = Stream.of(TimeZone.getAvailableIDs())
.map(TimeZone::getTimeZone)
.map(TimeZone::toZoneId)
.map(Results::new)
.collect(Collectors.toList());
System.out.println("Total Count: " + results.stream()
.count());
System.out.println("Translation success Count: " + results.stream()
.filter(r -> !r.failedToTranslation())
.count());
System.out.println("Translation failed Count: " + results.stream()
.filter(r -> r.failedToTranslation())
.count());
System.out.println("Equality success Count: " + results.stream()
.filter(r -> !r.equalityFailed() && !r.failedToTranslation())
.count());
System.out.println("Equality failed Count: " + results.stream()
.filter(r -> r.equalityFailed())
.count());
System.out.println("Failed to translate:\n");
results.stream()
.filter(r -> r.failedToTranslation())
.forEach(System.out::println);
System.out.println("Successfully translated:\n");
results.stream()
.filter(r -> !r.failedToTranslation())
.forEach(System.out::println);
System.out.println("Failed to equality:\n");
results.stream()
.filter(r -> r.equalityFailed())
.forEach(System.out::println);
Enviroment
Problem description
It appears that #332 actually made parsing worse as it fails to handle literals after ZoneIds.
2.9.1
2.9.1 is able to round trip (ZonedDateTime.toString()->DateTime->ZonedDateTime) 600 of 617 ZoneIds using a formatter designed to mimic ZonedDateTime's toString scheme (it is defined in the test below, it may not be perfect but worked for ~97% of ZoneIds).
Total Count: 617
Translation success Count: 600
Translation failed Count: 17
The failed ones are listed below:
2.9.2 - 2.9.4
Total Count: 617
Translation success Count: 3
Translation failed Count: 614
The 614 fail with errors like this one:
Invalid format: "2016-07-13T23:13:04.160+03:00[Africa/Addis_Ababa]" is malformed at "[Africa/Addis_Ababa]"
Test case