1

I'm in the process of changing our existing SimpleDateFormat based code to use the new Java 8 LocalDateTime and ZonedDateTime classes.

I couldn't find an easy way to convert this piece.

Considering sample date and format.

String testDate = "2012-12-31T10:10:10-06:00";
String testFormat = "yyyy-MM-dd'T'HH:mm:ss";

Existing code,

SimpleDateFormat sdf = new SimpleDateFormat(testFormat);
System.out.println(sdf.parse(testDate));

This piece works for both the date value containing timezone offset like mentioned above or not. It ignores the timezone if provided and in both cases defaults to the system timezone.

However if I replace it with below code,

DateTimeFormatter df = DateTimeFormatter.ofPattern(testFormat);
LocalDateTime ldt = LocalDateTime.parse(testDate, df);
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
System.out.println(zdt.toString());

It fails for the above format. To get it to work, I have to get rid of the timezone bit in the date i.e. convert it to "2012-12-31T10:10:10" or then change the format to include timezone details i.e. 'z'.

So from my initial tests at least it seems the new classes are pretty strict from matching the format to the T unlike SimpleDateFormat. I even tried marking the DateTimeFormater.setLineant(), but that too didn't help. Or maybe there are some other classes which can work in this case, just that I am not aware of them.

To add more details as why i want to have the legacy behavior using the new API's. In our product we expose these API's which end customer can use, so the API in question accepts both the datetime value in string and the format and used "SimpleDateFormat". So i want existing behavior to continue even with the new API's just so that we continue to maintain backward compatibility.

For now the only solution for above example i have come up with is handle it as an exception case,

DateTimeFormatter df = DateTimeFormatter.ofPattern(testFormat);
LocalDateTime ldt = null;
try {
   ldt = LocalDateTime.parse(testDate, df);
} catch (DateTimeParseException dtpException) {
   ldt = ZonedDateTime.parse(testDate).toLocalDateTime();
}
if (ldt != null) zdt = ldt.atZone(ZoneId.systemDefault());

Can someone share some pointers around this use case?

Victor
  • 1,207
  • 2
  • 13
  • 21
  • Your test date is in ISO 8601 format, which is built into Java 8+. So you don’t need `testFormat`. Just use `OffsetDateTime odt = OffsetDateTime.parse(testDate);`. To convert to the JVM’s time zone: `odt.atZoneSameInstant(ZoneId.systemDefault())`. The UTC offset in the string (`-06:00` in your example) is crucial for getting the correct point in time, so you need to parse it too (the one-arg `OffsetDateTime.parse` I just showed you does that, so is fine). – Ole V.V. Jan 04 '19 at 11:38
  • @OleV.V. Its not that i don't need. Our product exposes the api which accepts the datetime in string and the format and uses, SimpleDateFormat. So i want to keep the interface as is plus make sure i continue the backward compatibility with the new API's. Added more details in the description – Victor Jan 04 '19 at 21:39
  • I see. It sounds to me like a great task in programming and testing. I don’t think it will be easy to persuade `DateTimeFormatter` to offer the leneincy of `SImpleDateFormat`. – Ole V.V. Jan 04 '19 at 22:50
  • You can use the two-argument `DateTimeFormatter(parse​(CharSequence, ParsePosition)` for parsing only so much of the string as matches the format. I do however warn against ignoring the offset in the string, you are getting the wrong result that way. The other differences are even harder. Not all pattern letters are the same, for example `u` has unrelated meanings for the two. `SImpleDateFormat` happily parses `9` for month even though you specify `MM`, that is, two digits, `DateTimeFormatter` will not do that. – Ole V.V. Jan 07 '19 at 11:00

0 Answers0