No difference, except for the very slight lag caused by allocating a Date object.
From the javadoc the the default constructor of Date
:
Allocates a Date object and initializes it so that it represents the time at which it was allocated, measured to the nearest millisecond.
A Date
is just a thin wrapper around the epoch milliseconds, without any concept of timezones. Only when rendered to a String is timezone considered, but that is handled by the Locale
class.
I will go ahead and post an answer based on my final solution and a sort of summary of the very long comment chain.
To start, the whole conversion chain of:
Date --> Instant --> LocalDateTime --> Do stuff --> Instant --> Date
Is necessary to preserve the time zone information and still do operations on a Date like object that is aware of a Calendar and all of the context therein. Otherwise we run the risk of implicitly converting to the local time zone, and if we try to put it into a human readable date format, the times may have changed because of this.
For example, the toLocalDateTime()
method on the java.sql.Timestamp
class implicitly converts to the default time zone. This was undesirable for my purposes, but is not necessarily bad behavior. It is important, however, to be aware of it. That is the issue with converting directly from a legacy java date object into a LocalDateTime
object. Since legacy objects are generally assumed to be UTC, the conversion uses the local timezone offset.
Now, lets say our program takes the input of 2014-04-16T13:00:00
and save to a database as a java.sql.Timestamp
.
//Parse string into local date. LocalDateTime has no timezone component
LocalDateTime time = LocalDateTime.parse("2014-04-16T13:00:00");
//Convert to Instant with no time zone offset
Instant instant = time.atZone(ZoneOffset.ofHours(0)).toInstant();
//Easy conversion from Instant to the java.sql.Timestamp object
Timestamp timestamp = Timestamp.from(instant);
Now we take a timestamp and add some number of days to it:
Timestamp timestamp = ...
//Convert to LocalDateTime. Use no offset for timezone
LocalDateTime time = LocalDateTime.ofInstant(timestamp.toInstant(), ZoneOffset.ofHours(0));
//Add time. In this case, add one day.
time = time.plus(1, ChronoUnit.DAYS);
//Convert back to instant, again, no time zone offset.
Instant output = time.atZone(ZoneOffset.ofHours(0)).toInstant();
Timestamp savedTimestamp = Timestamp.from(output);
Now we just need to output as a human readable String in the format of ISO_LOCAL_DATE_TIME
.
Timestamp timestamp = ....
LocalDateTime time = LocalDateTime.ofInstant(timestamp.toInstant(), ZoneOffset.ofHours(0));
String formatted = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(time);
Best Answer
Both
System.currentTimeMillis()
andInstant.toEpochMilli()
return the number of milliseconds since the Unix epoch. That isn't "in" any particular time zone, although the Unix epoch is normally expressed as "midnight on January 1st 1970, UTC". But an instant is just an instant in time, and is the same whichever time zone you're in - but it will reflect a different local time.The output of
LocalDateTime.atZone(UTC)
differs because you're saying "Take the local date and time, and convert it to an instant as if it were in the UTC time zone" - even though when you created thatLocalDateTime
you did so implicitly in the UTC+3 time zone... that's why it's "wrong".LocalDateTime.now()
takes the local date and time in the system default time zone. So if your time zone is UTC+3, the current instant in time is 2015-10-06T16:57:00Z, thenLocalDateTime.now()
will return.2015-10-06T19:57:00
. Let's call thatlocalNow
...So
localNow.atZone(ZoneOffset.of("+3"))
will return aZonedDateTime
representing 2015-10-06T19:57:00+03 - in other words, the same local date/time, but "knowing" that it's 3 hours ahead of UTC... sotoInstant()
will return anInstant
representing 2015-10-06T16:57:00Z. Great - we still have the current date/time.But
localNow.atZone(ZoneOffset.UTC)
will return aZonedDateTime
representing 2015-10-06T19:57:00Z - in other words, the same local date/time, but "thinking" that it's already in UTC... sotoInstant()
will return anInstant
representing 2015-10-06T19:57:00Z.. which isn't the current time at all (it's in three hours).