I'm playing around with the new java.time package in Java 8. I have a legacy database that gives me java.util.Date
, which I convert to Instant
.
What I am trying to do is add a period of time that is based off of another database flag. I could be adding days, weeks, months, or years. I don't want to have to care what I am adding, and I would like to be able to add more options in the future.
My first thought was Instant.plus()
, but that gives me an UnsupportedTemporalTypeException
for values greater than a day. Instant apparently does not support operations on large units of time. Fine, whatever, LocalDateTime
does.
So that gives me this code:
private Date adjustDate(Date myDate, TemporalUnit unit){
Instant instant = myDate.toInstant();
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
dateTime = dateTime.plus(1, unit);
Instant updatedInstant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
return new Date(dueInstant.toEpochMilli());
}
Now, this is my first time using the new time API, so I may have missed something here. But it seems clunky to me that I have to go:
Date --> Instant --> LocalDateTime --> do stuff--> Instant --> Date.
Even if I did not have to use the Date part, I would still think it was a bit awkward. So my question is this, am I doing this completely wrong and what is the best way to do this?
Edit: Expanding on the discussion in the comments.
I think I have a better idea now about how LocalDateTime and Instant are playing with java.util.Date and java.sql.Timestamp. Thanks everyone.
Now, a more practical consideration. Let's say a user sends me a date from wherever they are in the world, arbitrary time zone. They send me 2014-04-16T13:00:00
which I can parse into a LocalDateTime. I then convert this directly to a java.sql.Timestamp and persist in my database.
Now, without doing anything else, I pull my java.sql.timestamp from my database, convert to LocalDateTime
using timestamp.toLocalDateTime()
. All good. Then I return this value to my user using the ISO_DATE_TIME formatting. The result is 2014-04-16T09:00:00
.
I assume this difference is because of some type of implicit conversion to/from UTC. I think my default time zone may be getting applied to the value (EDT, UTC-4) which would explain why the number is off by 4 hours.
New question(s). Where is the implicit conversion from local time to UTC happening here? What is the better way to preserve time zones. Should I not be going directly from Local time as a string (2014-04-16T13:00:00) to LocalDateTime
? Should I be expecting a time zone from the user input?
Instant
doesn't logically know about a calendar system - it's just a point in time - so adding a month to it doesn't make sense. You should also carefully consider whether you really want to use the system time zone - do you want to get different results for the same values, depending on where you're running? – Jenjava.sql.Timestamp
has atoLocalDateTime()
method and a staticvalueOf(LocalDateTime)
. There should be no need to useInstant
as an intermediary. – Hawkshaw