tl;dr
Core Concept: java.util.Date
does not have a time zone. The Date#toString
method lies to you.
If handed a legacy java.util.Date
object, immediately convert to java.time.Instant
.
Instant instant = myJavaUtilDate.toInstant() ;
Then apply your desired time zone.
ZonedDateTime zdt = instant.atZone( ZoneId.of( "Asia/Dubai" ) ) ;
Use only java.time
Your date-time handling should involve only the java.time classes.
The date-time classes outside that package are now legacy, terribly flawed in poor design. The legacy classes were supplanted by java.time in JSR 310, implemented in Java 8+.
You said:
// initailize date object
Date date = new Date();
Did you mean java.util.Date
or java.sql.Date
? Both are legacy.
- The first was replaced by
java.time.Instant
. Both the legacy and modern classes represent a moment as seen with an offset from UTC of zero hours-minutes-seconds.
- The second was replaced by
java.time.LocalDate
. The legacy class pretends to represent a date-only, but because of faulty design it actually contains a time-of-day and an assumption of an offset of zero. In contrast, the modern class truly represents a date-only, without time-of-day, and without time zone or offset.
Instead use this code:
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC (zero offset).
You said:
// get time zone
ZoneId zoneId = ZoneId.of("Asia/Dubai");
Good. A ZoneId
is the modern way to represent a time zone. And Asia/Dubai
, in Continent/Region
is the correct naming for real time zones.
You said:
// create zonedDateTime object
ZonedDateTime zdt = ZonedDateTime.ofInstant(date.toInstant(), zoneId);
Using our Instant
object seen above, use this code:
ZonedDateTime zdt = instant.atZone( zoneId ) ;
Both instant
& zdt
here represent the same simultaneous moment, the same point on the timeline. But the latter is viewed through the wall-clock time used by people in a particular region.
You said:
// instant of zonedDateTime
Instant instant = zdt.toInstant();
Yes, you can extract an Instant
from a ZonedDateTime
. But this code in unnecessary here as we already instantiate a Instant
object to capture the current moment.
You said:
// convert instant to specified zone
instant.atZone(zoneId);
The problem here is that an Instant
object, like all the java.time objects, is immutable. You can alter (“mutate”) the content of an Instant
object after its creation. That moment is frozen forever.
Furthermore, calling Instant#atZone
returns a fresh new ZonedDateTime
object. We saw just that in our code earlier above. Your code shown above ignores the new ZonedDateTime
object returned by atZone
.
You said:
// Get Local Date Time Object
LocalDateTime ldt = LocalDateTime.ofInstant(instant,zoneId);
Two problem here:
- You can more easily obtain a
LocalDateTime
from the ZonedDateTime
instantiated above. LocalDateTime ldt = zdt.toLocalDateTime() ;
- You may not be aware that in creating the
LocalDateTime
, you are discarding valuable information: the time zone. So you are left with merely a date and a time-of-day. But such a value is inherently ambiguous. For example, if noon on January 23 this year, we do not know if you meant in noon in Tokyo Japan, noon in Toulouse France, or noon in Toledo Ohio US — three very different moments several hours apart.
Tip: If you do not yet fully grok date-time handling, avoid using LocalDateTime
. In most business situations, we generally care about a moment, a specific point on the timeline. LocalDateTime
does not fit that case.
You said:
//Convert it back to Date Object
Date dateFinal = java.util.Date.from(Instant.from(ldt.atZone(zoneId)));
Two problems here:
- You can more easily write
java.util.Date.from( instant )
as we already have an Instant
in hand. Or, if we had just the ZonedDateTime
seen above, java.util.Date.from( zdt.toInstant() )
.
- You would usually never write this in new code. Convert to the legacy code only where necessary to interoperate with old code not yet updated to java.time. Otherwise, avoid both
Date
classes like the plague. Ditto for Calendar
, SimpleDateFormat
, etc.
Your title asks:
[Convert a Date object to a specified timeZone Date Object]
I do not understand what you mean. The java.util.Date
class represents a moment in UTC. It has no time zone.
(Actually there is a time zone buried with its code, but this code is practically irrelevant, and represents another of those terrible design decisions found in the legacy date-time classes.)
You said:
timeZone Date object in JAVA 8 Date date = Fri Mar 31 16:10:13 IST
Do not be fooled by the java.util.Date#toString
method. That method unfortunately injects the JVM’s current default time zone while generating text. While well-intentioned, this creates the false illusion that Date
includes a time zone in its meaning when in fact it is "in UTC" (has an offset from UTC of zero).