4

I was trying to convert the date in String format into java.util.Date by using java.text.SimpleDateFormat, however it's not giving me the right output. Please help!

My input is generated by Django date: ex. "2014-01-20T07:17:06.150995+00:00"

But, I got "Mon Jan 20 15:19:36 GMT+08:00 2014" instead of "Mon Jan 20 15:17:06 GMT+08:00 2014"

Here's my testing code:

String s = "2014-01-20T07:17:06.150995+00:00";

SimpleDateFormat sdf;
String fmt = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZZZZZ";
sdf = new SimpleDateFormat(fmt, Locale.US);

String result = "";
try {
    Date date = sdf.parse(s);
    Log.d(Constants.LOG_TAG, date.toString());
    result = date.toString();
} catch (Exception e) {
    Log.d(Constants.LOG_TAG, "date formatting error" + e.getMessage());
}
Log.d(Constants.LOG_TAG, "date test >> " + result);
Heron Yang
  • 336
  • 2
  • 16
  • Looks like a timezone thing to me. – Hot Licks Jan 20 '14 at 13:29
  • 1
    @HotLicks: A 2.5minute time zone? – Keppil Jan 20 '14 at 13:32
  • I am testing this code on my Android Device (Nexus 7). Is there any difference? – Heron Yang Jan 20 '14 at 13:35
  • Executing this on Ideone it gives an unparseable date error, so i'm guessing you need to sort the format string out; http://ideone.com/e.js/8R1NGM – Robadob Jan 20 '14 at 13:37
  • @bobbel: Check again. The hours are the same, the dates differ by 2.5 minutes. – Keppil Jan 20 '14 at 13:42
  • When posting sample code, please remove extraneous code such as your setting of 'result' var and calls to Log. Present the simplest possible example of your problem. – Basil Bourque Jan 21 '14 at 03:11
  • @HeronYang Yes, there is a big difference between running on Android and running on official Java platforms. Android is a copy of Java, but is not an official implementation and has not passed the requisite compatibility tests. The Android libraries are very close copies but not exact clones of Java. You should add a tag to the question for 'Android'. – Basil Bourque Jan 21 '14 at 03:20

3 Answers3

7

As you can see your two dates differ by 2.5 minutes.

This happens because you are parsing microseconds as milliseconds. This will add 150000 milliseconds to your result, or 2.5 minutes.

There is no standard way to parse a date string with microseconds using SimpleDateFormat, you will have to do it yourself if you can't get the source string in a different format.

If the date is always in exactly this format you could do something like:

String dateWithoutMicros = s.substring(0, s.length() - 9) + s.substring(s.length() - 6);
Date date = sdf.parse(dateWithoutMicros);
Keppil
  • 45,603
  • 8
  • 97
  • 119
  • if so, how can I solve this problem? I think this site should help:http://stackoverflow.com/questions/19223171/java-util-date-format-ssssss-if-not-microseconds-what-are-the-last-3-digits – Heron Yang Jan 20 '14 at 13:47
  • That question is about formatting, not parsing, so it won't really help. – Keppil Jan 20 '14 at 13:51
  • Nice! Ok, I will remove the 3 digits. Thanks! – Heron Yang Jan 20 '14 at 13:59
  • Thank you @Keppil exactly the answer I needed – russau Nov 05 '20 at 06:03
  • You might want to check out [setLenient](https://docs.oracle.com/javase/9/docs/api/java/text/DateFormat.html#setLenient-boolean-). More info: https://stackoverflow.com/questions/50746771/simpledateformat-leniency-leads-to-unexpected-behavior – russau Nov 09 '20 at 20:57
2

As I first tried to run your Code (replaced Log.d with System.out.println()) i got a ParseException: Unparseable date.

Next I tried several parts of the date with their respective format string parts. Lastly the problem was the timezone part "+00:00" respectively "ZZZZZ".

I read about the pattern letters in the documentation (http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html) and found:
Z -> -0800
X -> 08; -0800; -08:00
So swapped your ZZZZZ with X and then it worked fine for me. Final format string:
String fmt = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSX";

SNeutrino
  • 21
  • 3
1

Avoid using the java.util.Date & .Calendar and java.text.SimpleTextFormat classes. They are notoriously troublesome.

Joda-Time

Using the third-party open-source Joda-Time 2.3 library, you can pass that ISO 8601 formatted string directly to a constructor. No need for formatters and parsers.

However, like java.util.Date, Joda-Time has a resolution of milliseconds. So it can handle only the first 3 digits of your fraction of a second. Fortunately though, rather than through an exception, Joda-Time simply truncates (ignores) the latter extra fractional digits.

String s = "2014-01-20T07:17:06.150995+00:00";
DateTime dateTime = new DateTime( s );
System.out.println( "dateTime: " + dateTime );
System.out.println( "dateTime in UTC/GMT: " + dateTime.toDateTime( DateTimeZone.UTC ) );

When run…

dateTime: 2014-01-19T23:17:06.150-08:00
dateTime in UTC/GMT: 2014-01-20T07:17:06.150Z

java.time.* Classes

The new classes bundled with Java 8, in the java.time.* package, supplant the java.util.Date & .Calendar classes. They are inspired by Joda-Time but are entirely re-architected. JSR 310 defines these classes.

These new classes have a resolution of nanoseconds rather than milliseconds, so they can handle all six of your fractional digits. Like Joda-Time, they take an ISO 8601 string directly.

String s = "2014-01-20T07:17:06.150995+00:00";
ZonedDateTime zdt = ZonedDateTime.parse( s );

System.out.println( "zdt: " + zdt );

When run…

zdt: 2014-01-20T07:17:06.150995Z
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154