I've seen many examples of converting date from one time zone to another. But all of them has output as a String. I want a date object as output.
The methods I've tried -
Approach 1
SimpleDateFormat dateTimeFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a z");
dateTimeFormat.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
Date date = new Date();
System.out.println(dateTimeFormat.format(date)); // this print IST Timezone
DateFormat timeFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a z");
timeFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String estTime = timeFormat.format(date);
try {
date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a z", Locale.ENGLISH).parse(estTime);
System.out.println(date);
} catch (ParseException ex) {
Logger.getLogger(A.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(timeFormat.format(date));
Approach 2
private static Date shiftTimeZone(Date date, TimeZone sourceTimeZone, TimeZone targetTimeZone) {
System.out.println(sourceTimeZone.toString());
System.out.println(targetTimeZone.toString());
Calendar sourceCalendar = Calendar.getInstance();
sourceCalendar.setTime(date);
sourceCalendar.setTimeZone(sourceTimeZone);
Calendar targetCalendar = Calendar.getInstance();
for (int field : new int[]{Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, Calendar.HOUR, Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND}) {
targetCalendar.set(field, sourceCalendar.get(field));
}
targetCalendar.setTimeZone(targetTimeZone);
return targetCalendar.getTime();
}
Approach 1 gives me result as a String.
03/22/2018 10:16:57 AM EDT <- instanceOf String
Approach 2 gives me correct date and time of Eastern Time time zone, but the Date has the time zone of IST.
Thu Mar 22 10:16:57 IST 2018 <- instanceof Date
Can anyone please help me to obtain a Date object with Eastern Time TimeZone.
Update - My ultimate goal is to get Unix Timestamp of the current Eastern Time.
Instant.now() // Capture the current moment in UTC, an `Instant` object.
.atZone( // Adjust from UTC into a particular time zone.
ZoneId.of( “Asia/Kolkata” )
) // Returns a `ZonedDateTime` object.
.withZoneSameInstant( // Adjust into yet another time zone. All three are the same moment but vowed using different wall-clock times.
ZoneId.of( “Africa/Tunis” )
) // Returns another `ZonedDateTime` object.
Or…
ZonedDateTime.now(
ZoneId.of( “Asia/Kolkata” )
).withZoneSameInstant(
ZoneId.of( “Africa/Tunis” )
)
Firstly, stop using the legacy date-time classes. They are an awful wretched mess. Supplanted by the java.time classes.
Date
is replaced by Instant
.Calendar
is replaced by ZonedDateTime
SimpleDateFormat
is replaced by DateTimeFormatter
.Date::toString
Secondly, understand that Date
has a horribly confusing feature of dynamically applying your JVM’s current default time zone while generating a String. Date
always represents a moment in UTC. The toString
method creates a false illusion of Date
carrying a time zone, when actually its value is in UTC. While well-intentioned by the class designers, this was a disastrous decision, causing no end of confusion amongst countless programmers for decades now.
Even worse: There actually is a time zone buried in a Date
, but is irrelevant to this discussion. Confusing? Yes; as I said, an awful wretched mess of bad design.
Instant
The Instant
class replacing Date
is much clearer. An Instant
represents a moment, a point on the timeline, always in UTC, with a resolution of nanoseconds.
Use Instant
to capture the current moment in UTC. The JVM’s current default time zone is irrelevant. The host OS’ assigned time zone is irrelevant.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
Unlike Date::toString
, the Instant::toString
method tells the truth. A Instant
is always in UTC, so toString
always reports UTC. A String is generated in standard ISO 8601 format. The Z
on the end is short for Zulu
and means UTC.
instant.toString(): 2018-01-23T12:34:56.123456789Z
About capturing the current moment… In Java 8, the current moment was captured in milliseconds even though the java.time classes can represent nanoseconds. In Java 9 and later, a new implementation of Clock
provides for capturing the current moment in finer granularity. In Java 9.0.4 on macOS Sierra, I see microseconds. The hardware clocks on conventional computers nowadays cannot capture the current moment with accuracy beyond microseconds.
ZonedDateTime
To view that same moment through the lens of a wall-clock time used by the people of a particular region, assign that region’s time zone. Applying a ZoneId
to an Instant
produces a ZonedDateTime
. Conceptually:
ZonedDateTime = ( Instant + ZoneId )
In code:
ZoneId z = ZoneId.of( “Pacific/Auckland” ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
Adjusting to another time zone is easy. You can start with the Instant
again.
ZoneId zKolkata = ZoneId.of( “Asia/Kolkata” ) ;
ZonedDateTime zdt = instant.atZone( zKolkata ) ;
Or you can adjust the ZonedDateTime
object. The java.time classes use immutable objects. So rather than “mutate” (alter) the original object, the adjustment produces a new distinct object.
ZonedDateTime zdtKolkata = zdt.withZoneSameInstant( zKolkata ) ; // Same moment, same point on the timeline, different wall-clock time.
You can skip the use of the Instant
. I do not recommend doing so. Programmers should be doing their thinking, debugging, logging, exchanging of data, and much of their business logic in UTC. So Instant
should be your go-to class whenever you start any work with date-time values.
ZonedDateTime zdtNewYork = ZonedDateTime.now( ZoneId.of( "America/New_York" ) ) ;
The ZonedDateTime::toString
method wisely extends the ISO 8601 standard by appending the name of the time zone in square brackets.
String output = zdtNewYork.toString() ;
2018-01-23T07:34:56.123456789-05:00[America/New_York]
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.