Java date-time handling was notoriously bad for the vast majority of Java's lifetime. It was so bad that a third party library, Joda-Time, was the defacto standard for Java date processing until finally, in Java 8, the features, functionality, and design of Joda-Time were adopted into Java. JSR-310 added refinements to conventional datetime objects, like Timestamp
s and LocalDate
s, but also added useful classes like Instant
(an immutable instant in time) and DateTimeFormatter
s that had a conventional and flexible API for doing date formatting and parsing.
Since JSR-310, it's easy to write good date handling code in Java.
That, of course, doesn't mean that you can't still write terrible date handling code. Normally, you'd expect your bad date handling code to take the form of one of the standard badnesses: write your own string mangler, insist on using the legacy libraries, homebrew a stacked up library of edge cases and ugly code and weird misunderstandings of the calendar.
Brendan sends us an example where they manage to use the new APIs in a head-scratching fashion.
private static Timestamp getCdrTimestampParameter(CSVParam param) {
return Timestamp.valueOf(
LocalDateTime.ofInstant(Instant.from(DateTimeFormatter.ISO_INSTANT.parse(param.getParamValue())), ZoneOffset.UTC));
}
The goal here is to take the text supplied from a CSVparam
(presumably a field in a CSV file?) and convert it into a Timestamp
object. This could easily be a one-line operation. Well, I guess technically, this code already is a one-statement operation, but you could easily write this without using every single one of the new datetime objects. Perhaps the developer just wanted the practice?
In this case, LocalDateTime
has a parse
method which allows you to pass a DateTimeFormatter
, so you could just build the LocalDateTime
by LocalDateTime.parse(param.getParamValue(), DateTimeFormatter.ISO_INSTANT)
. Which gets weird, anyway, because they are somehow passing a timezone offset into the LocalDateTime
through that ofInstant
method, but local date times don't have timezone information in them, and the java.time
docs don't have an ofInstant
method in the first place, which implies that something weird and inappropriate is going on here, in terms of classes getting replaced or modified. It's possible that ofInstant
returns a ZonedDateTime
by injecting timezone information into a LocalDateTime
, but Timestamp
doesn't expect ZonedDateTime
s in its valueOf
method, but LocalDateTimes
, because Timestamp
s are also not timezone aware.
When I started looking at this code, I didn't realize how weird and wrong it was. I almost didn't do a dive into it, to try and figure out what was happening here, because it looks ugly, but the WTF only appears when you dig into the layers.
As an aside, there are a lot of ways to do this, but the easiest looking way, to my eye, is something like:
return Timestamp.from(Instant.parse(param.getParamValue()));
//`Instant.parse` defaults to the `DateTimeFormatter.ISO_INSTANT`
The down side, I guess, to my approach is that it doesn't try and use every single tool in the toolbox of java.time
.