0

This is happening with one (probably more) datetime where the time part is totally wrong in a parse.

The code:

import java.text.*;
import java.util.*;

public class TestTimeParse {
    public static void main(String[] args) {
        SimpleDateFormat dateFmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault());
        dateFmt.applyPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'");
        ParsePosition pos = new ParsePosition(0);
        Date date = dateFmt.parse("2018-11-01T18:07:55.6725292Z", pos);
        System.out.println("Text 2018-11-01T18:07:55.6725292Z parses as " + date);
    }
}

The output:

Text 2018-11-01T18:07:55.6725292Z parses as Thu Nov 01 20:00:00 MDT 2018

What is going on for the time component? The hours is wrong and the minutes & seconds are zeroed out.

David Thielen
  • 28,723
  • 34
  • 119
  • 193
  • Changing the pattern to `"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"` and the input to `"2018-11-01T18:07:55.672Z"` seems to take the problem away. Not sure if it's a bug related to the subseconds value... – ernest_k Feb 11 '19 at 17:04
  • If I may... **Most** of the times, people writing a date format parser with a pattern of `yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'` are actually trying to parse a ISO-8601 date(time). And using such a fixed, string based, timezone unaware pattern is a **terrible idea** to parse ISO 8601 dates. So if it is actually what you are trying to do, look at https://stackoverflow.com/questions/2201925/converting-iso-8601-compliant-string-to-java-util-date – GPI Feb 11 '19 at 17:05
  • java.util.Date can only handle milliseconds. So, the only supported pattern by SimpleDateFormat for this is "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", which means you dates must also be represented with milliseconds. – Luís Silva Feb 11 '19 at 17:09
  • I recommend you don’t use `DateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use `LocalDateTime` and `DateTimeFormatter`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Feb 11 '19 at 17:22
  • @OleV.V. I agree. Unfortunately this is code that was written before java 1.8 and we need to refactor it. But in the meantime, we need to work with it. – David Thielen Feb 11 '19 at 18:16

1 Answers1

1

This is one of the problems with the obsolete Date, Calendar and SimpleDateFormat classes. You shouldn't use it, for it's supplanted by the new Date and Time API in Java 8. It is available in the java.time package.

String str = "2018-11-01T18:07:55.6725292Z";
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'";

LocalDateTime ts = LocalDateTime.parse(str, DateTimeFormatter.ofPattern(pattern));
System.out.println("Text 2018-11-01T18:07:55.6725292Z parses as " + ts);

It seems that SimpleDateFormat is only able to read up to three millisecond digits. The parsing process works if one truncates the fraction portion of the date to three digits, i.e. "2018-11-01T18:07:55.672" instead of "2018-11-01T18:07:55.6725292Z", and also changes the according 'S' pattern specifiers, i.e. "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'".

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
  • 1
    Do you mind explaining what the exact problem is? The old API is known to work in most cases. Why doesn't work here? – ernest_k Feb 11 '19 at 17:00
  • I think the issue is that SimpleDateFormat has resolution only down to the millisecond. You are specifying a precision much higher than the three digits available (000-999 ms). The SimpleDateFormat may be getting confused with the out of bound condition. – Dave G Feb 11 '19 at 17:08
  • 1
    @ernest_k 6725292 milliseconds equals 1 hour 52 minutes 5.292 seconds. Add these to the time, 18:07:55, to obtain — yes, 20:00:00.292 to be precise — rendered as 20:00:00 since milliseconds are not printed. – Ole V.V. Feb 11 '19 at 17:20
  • @OleV.V. Thanks for solving the mystery. I didn't get it – ernest_k Feb 11 '19 at 17:35
  • MC Emperor Better and simpler without any explicit formatter: Either just `Instant.parse(str)` or just `OffsetDateTime.parse(str)`. This works because the format is the standard ISO 8601. – Ole V.V. Feb 11 '19 at 17:47
  • Yes, the terrible legacy classes (`Date`, `Calendar`) were limited to a resolution of [milliseconds](https://en.wikipedia.org/wiki/Millisecond). In a stroke of amazingly bad design, the awful legacy class `java.sql.Timestamp` bolts on a place to hold nanoseconds while maintaining the milliseconds as well, by inheriting from `java.util.Date`. Yet another of *many* reasons to **never use the legacy date-time classes**. In contrast, the *java.time* classes neatly use [nanosecond](https://en.wikipedia.org/wiki/Nanosecond) resolution consistently. – Basil Bourque Feb 11 '19 at 20:39