Reputation: 13
I'm a bit puzzled regarding the Java timestamp formatting functions as they seem to change the timestamp by a few minutes.
My Pivotal CloudFoundry app writes a new entry into a PostgreSQL 9.4.5 database. Doing so, I let PostgreSQL generate and store a timestamp for that entry (within the SQL statement I use 'now()' for that particular column). All that works fine so far. Problems arise when I read the entry with my app because I have to format the timestamp to ISO 8601 (company policy) and this seems to change the timestamp. I've used this code:
public String parseTimestamp(String oldDate) {
System.out.println("String oldDate: " + oldDate);
TimeZone timeZone = TimeZone.getTimeZone("Europe/Berlin");
SimpleDateFormat oldDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSS");
SimpleDateFormat newDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
newDateFormat.setTimeZone(timeZone);
Date tempDate = null;
try {
tempDate = oldDateFormat.parse(oldDate);
} catch (ParseException e) {
//TODO
}
System.out.println("tempDate before format(): " + tempDate);
String newDate = newDateFormat.format(tempDate);
System.out.println("tempDate after format(): " + tempDate);
System.out.println("String newDate: " + newDate);
return newDate;
}
Output:
String oldDate: 2018-06-18 13:07:27.624828+02
tempDate before format(): Mon Jun 18 13:17:51 CEST 2018
tempDate after format(): Mon Jun 18 13:17:51 CEST 2018
String newDate: 2018-06-18T13:17:51Z
As you can see, the timestamp changed from 13:07 to 13:17. All the other queried entries also show a difference, varying between ~2 to 10 minutes. However, when I re-run the query, each difference stays the same. OPs told me that all involved systems have synchronised time and I'm not sure if system time should play a role here at all.
Does someone know what is going on?
Upvotes: 1
Views: 2353
Reputation: 24444
First, I was really puzzled and thought, you might have found some kind of bug in SimpleDateFormat
. Your code can be reduced to the following lines to show the same behaviour:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSS");
String str = "2018-06-18 13:07:27.624828+02";
System.out.println(str);
System.out.println(format.parse(str));
Result:
2018-06-18 13:07:27.624828+02
Mon Jun 18 13:17:51 CEST 2018
The parsed Date
object got ten additional minutes (and some seconds).
Taking a closer look reveals the problem - it is NOT a bug in JDK:
Your millisecond-part is 624828
- these are six(!) digits (not three). 624828 milliseconds are about 624 seconds, which are 10 minutes and 24 seconds.
The SimpleDateFormat
correctly summed up this additional seconds and minutes.
What's wrong too: Your date format contains five digits for the milliseconds part.
Solution:
The (new) Java Time API can handle larger fractions of a second - and also convert easily between different time zones:
String str = "2018-06-18 13:07:27.624828+02";
DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSx");
OffsetDateTime date = OffsetDateTime.parse(str, pattern);
System.out.println(date);
System.out.println(date.withOffsetSameInstant(ZoneOffset.UTC));
Result:
2018-06-18T13:07:27.624828+02:00
2018-06-18T11:07:27.624828Z
Upvotes: 2
Reputation: 11
Your input date contains micro seconds but SimpleDateFormat supports only milli seconds (up to 3 digits). When parsing the value with the flag lenient enabled the complete 6 digits are evaluated as micro seconds. So at the end you have 624 seconds that are added to the date additionally.
You can try to use the SSSSSS pattern with DateTimeFormatter that has been introduced in Java 8.
But you may have further issues. Your code parses the input date without the time zone information +02 that is included at the end. You should add one letter X for the ISO8601 time zone format. When formatting the date for outputting you use letter 'Z' that indicates time zone UTC. But you set time zone CET (Berlin). So the output date is not in UTC. The correct ouput in UTC for the specified input date is:
2018-06-18 11:07:27Z
Upvotes: 1