CodeSOD: An Advent Calendar
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 Timestamps and LocalDates, but also added useful classes like Instant (an immutable instant in time) and DateTimeFormatters 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 ZonedDateTimes in its valueOf method, but LocalDateTimes, because Timestamps 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.
[Advertisement] ProGet can centralize your organization's software applications and components to provide uniform access to developers and servers. Check it out!