I'm new to the java.time formats in Java 8 and later, but I'm reasonably comfortable with Joda-Time and I'm very familiar with Java's java.util.Date, java.util.Calendar, and DateFormat classes along with ISO 8601.
I'm using PostgreSQL 9.3 with jOOQ 3.6.4, with a foo table column containing a timestamp:
bar timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP
I retrieve that bar value using jOOQ, and try to print it out using java.time's DateTimeFormatter.ISO_OFFSET_DATE_TIME:
DateTimeFormatter timestampFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
Cursor<FooRecord> fooRecordCursor = createDSLContext().selectFrom(FOO).fetchLazy();
for(FooRecord fooRecord : fooRecordCursor) {
System.out.println(timestampFormatter.format(fooRecord.getBar().toInstant());
}
This throws an UnsupportedTemporalTypeException:
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: Year
at java.time.Instant.getLong(Instant.java:608)
at java.time.format.DateTimePrintContext$1.getLong(DateTimePrintContext.java:205)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2543)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1745)
at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1719)
But if I use my own custom ISO8601DateFormat which extends the old-school SimpleDateFormat, I can parse the value just fine:
final DateFormat timestampFormatter = new ISO8601DateFormat();
...
System.out.println(timestampFormatter.format(fooRecord.getBar());
I find this very confusing:
- The jOOQ
barfield accessor returns ajava.sql.Timestamp. In the Java 8 version I convert that to anInstant, but why would that reduce the amount of information available? - An
Instantis supposed to be an absolute point of time --- isn't it simply based upon alongoffset just like JodaTime and JavaDate? - Why is
DateTimeFormatter.ISO_OFFSET_DATE_TIMEexpecting aYearfield from anInstant? Shouldn't the formatter just convert thelongoffset to a date/time in the current time zone, and retrieve the year from that? I wouldn't expect any instant to contain aYearfield.
In short: If my SimpleDateFormat-based ISO8601DateFormat works fine for a Timestamp from PostgreSQL, why can't DateTimeFormatter.ISO_OFFSET_DATE_TIME figure out how to format the Instant version of the same value?
.toLocalDateTime()instead?toLocalDatetime()wouldn't work either as it misses the time zone field needed forDateTimeFormatter.ISO_OFFSET_DATE_TIMEformat.