I\'m using timezone Brazil by default, but when caught one LocalDateTime of New York and convert to java.tim.Instant the instant is filled
It seems to me that you're confused about the difference between a LocalDateTime
and an Instant
(or a Date
, which is essentially the same thing as an Instant
). These are completely different objects.
A LocalDateTime
is a particular calendar date and a particular clock time. You can think of it like this picture.
Or you can think of it as a year, month, day, hour, minute and second. But it has no time zone. It's just what the calendar says and what the clock says.
An Instant
is a moment in time. For example, the moment when Neil Armstrong first stepped on the moon could be represented as an Instant
. So could the moment JFK was shot.
Again, there's no time zone. But it's something different from a LocalDateTime
. You can't write down what time an Instant
is unless you know which time zone to write it down for. Oh, and a Date
is the same thing as an Instant
.
Therefore, to convert between a LocalDateTime
and an Instant
, you need to reference a particular time zone. So to express the moment Neil Armstrong stepped on the moon as a year, month, date, hour, minute and second; you need to know what time zone to use. If you use UTC, it was 2:56am on 21 July 1969. If you use Pacific Standard Time, it was 6:56pm on 20 July 1969.
Armed with that knowledge, let's analyse your code. You started with a couple of LocalDateTime
objects.
Now, you use UTC to convert these to Instant
objects.
Then you print these out. We need to know a timezone to be able to do this, but that's OK. An Instant
gets printed in UTC, no matter what. That's what the Z
means.
Now, you convert the Instant
objects to a number of milliseconds. Fine. This is the number of milliseconds since midnight on 1 January 1970, UTC. milliNY is obviously 3.6 million less than milliBrazil, because it corresponds to an Instant
that's an hour earlier.
Then you convert the Instant
objects to Date
objects. This doesn't really change anything, since a Date
and an Instant
represent the same thing, even though they get printed out differently.
You print out those converted Date
objects. They get printed in Brazilian time, because that's your locale. And it just so happens that dateNY
is an hour earlier than dateBrazil
; but they still both get printed in Brazilian time, which is three hours behind UTC. So you get 19:11:52 and 18:11:52 respectively.
Lastly, you make a couple of more Date
objects, from the numbers of milliseconds. But these new Date
objects are exactly equal to the dateBrazil
and dateNY
that you already have, since you made them from the same number of milliseconds. And again, they get printed in Brazilian time.
LocalDateTime
means no zoneYou seem to misunderstand the purpose of LocalDateTime.
This class has no time zone and no offset-from-UTC. It is not a point on the timeline. Rather it represents a vague idea about possible moments. The name “Local…” may be counter-intuitive as it does not represent any particular locality, but rather any locality.
For example, Christmas this year is midnight at start of December 25, 2016, or 2016-12-25T00:00
. This has no meaning until you apply a time zone to get Christmas in Auckland NZ or Kolkata IN or Paris FR or Montréal CA, each being a different point on the timeline, getting later and later as you go westward.
Never use LocalDateTime because you think it will save you the hassle of zones and offsets. Just the opposite, you’ll be digging yourself into a hole with ambiguous date-time values.
Most of your business logic, logging, data storage, and data exchange should all be in UTC. Think of UTC as the one true time; all the other zones and offsets are masquerading as dressed-up UTC values.
In java.time, that means the Instant
class is your go-to class, the basic building-blocks of date-time objects. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.
Instant now = Instant.now();
ZonedDateTime
Adjust into time zones only where required to access the wall-clock time of some region. Apply a ZoneId
to get a ZonedDateTime
object.
ZoneId zNewYork = ZoneId.of("America/New_York");
ZoneId zRecife = ZoneId.of("America/Recife");
ZonedDateTime zdtNewYork = now.atZone( zNewYork );
ZonedDateTime zdtRecife = now.atZone( zRecife );
All three of these objects, now
, zdtNewYork
, and zdtRecife
, are all the very some moment, the same simultaneous point on the timeline. All three share the same count-from-epoch. The only difference is the lens through which we see their wall-clock time.
Avoid using the troublesome old date-time classes bundled with the earliest versions of Java. So, avoid java.util.Date
and java.util.Calendar
. They really are that bad. Stick with java.time classes.
If you must interact with old code not yet updated for java.time types, you can convert to/from java.time types. Look for new methods added to the old classes. The java.util.Date.from method takes an Instant
. We can extract an Instant
from a ZoneDateTime
(or from OffsetDateTime
).
java.util.Date utilDate = java.util.Date.from( zdtNewYork.toInstant() );
And going the other direction.
Instant instant = utilDate.toInstant();
For more info on converting, see my Answer to the Question, Convert java.util.Date to what “java.time” type?
Avoid using the count-from-epoch numbers such as milliseconds-since-start-of-1970-in-UTC. There are various granularities used for the count (milliseconds, microseconds, nanoseconds, whole seconds, and more). There are at least a couple dozen epochs in use by various computer systems besides 1970. The numbers have no meaning when read by humans, so bugs may go undetected.
You might find them useful when practicing. Call getEpochSecond
and getNano
on Instant
, or for a truncated value call toEpochMilli
.
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.