Zaw Than oo
Zaw Than oo

Reputation: 9935

SameTime with Different TImeZone

Why does the program printout the same output/time with different TimeZone?

    Calendar cal = GregorianCalendar.getInstance();
    TimeZone timeZone_1 = TimeZone.getTimeZone("Asia/Rangoon");
    cal.setTimeZone(timeZone_1);
    System.out.println(cal.getTime());

    TimeZone timeZone_2 = TimeZone.getTimeZone("Asia/Tokyo");
    cal.setTimeZone(timeZone_2);
    System.out.println(cal.getTime());

Example Output :

Thu Nov 22 09:00:33 MMT 2012
Thu Nov 22 09:00:33 MMT 2012        

My Expected Output is:

Thu Nov 22 09:00:33 MMT 2012
Thu Nov 22 11:30:33 MMT 2012

Upvotes: 2

Views: 90

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 338181

tl;dr

Instant                                           // Represent a moment as seen in UTC, that is, with an offset from UTC of zero hours-minutes-seconds.
.now()                                            // Capture the current moment in UTC.
.atZone( ZoneId.of( "Asia/Rangoon" ) )            // Adjust from UTC to a particular time zone. Same moment, different wall-clock/calendar.
.atZoneSameInstant( ZoneId.of( "Asia/Tokyo" ) )   // Adjust from one time zone to another. Same moment, different wall-clock/calendar. 
.toString()                                       // Generate text in ISO 8601 format wisely extended to append the name of time zone in square brackets.

java.util.Date#toString tells a lie

The Answer by Tomasz Nurkiewicz is correct. Your call to cal.getTime() returns a java.util.Date object whose toString method lies to you. That Date#toString method has the anti-feature of dynamically applying a current default time zone to its value which is actually stored as a moment seen in UTC (an offset-from-UTC of zero hours-minutes-seconds).

This anti-feature is one of many reasons to avoid Date & Calendar classes.

Avoid legacy date-time classes

You are using terribly flawed date-time classes that were years ago supplanted by the modern java.time classes defined in JSR 310.

ZonedDateTime

To represent the current moment, use Instant.

You can adjust that moment to be seen through a particular time zone. Apply a ZoneId to produce a [ZonedDateTime][2] object.

ZoneId zRangoon = ZoneId.of( "Asia/Rangoon" );
ZoneId zTokyo = ZoneId.of( "Asia/Tokyo" ) ;

Instant instant = Instant.now() ;  // Always in UTC (offset of zero). 

// Adjust that moment into particular time zones.
ZonedDateTime zdtRangoon = instant.atZone( zRangoon ) ;
ZonedDateTime zdtTokyo = instant.atZone( zTokyo ) ;

The objects referenced by variables instant, zdtRangoon, and zdtTokyo all represent the very same moment, the same point on the timeline — three views, one moment.

Call ZonedDateTime#toString to generate text in standard ISO 8601 format wisely extended to append the name of time zone in square brackets.

String outputRangoon = zdtRangoon.toString() ;
String outputTokyo = zdtTokyo.toString() ;

See this code run at Ideone.com. Notice the difference in date as well as time-of-day.

instant.toString() = 2023-12-31T20:36:15.449185Z
outputRangoon = 2024-01-01T03:06:15.449185+06:30[Asia/Rangoon]
outputTokyo = 2024-01-01T05:36:15.449185+09:00[Asia/Tokyo]

To get localized output, use DateTimeFormatter.ofLocalizedDateTime. Search Stack Overflow to find more info.

Upvotes: 0

Tomasz Nurkiewicz
Tomasz Nurkiewicz

Reputation: 340708

Your code is fine, it's only the debug output that's wrong (misleading). cal.getTime() returns Date object, which is independent from time zone. But Date.toString() always prints this date with systems' time zone. Date.toString() is so counterintuitive (it displays calendar time with system time zone while it barely stores number of millliseconds) that it should have been banned/deprecated.

To have accurate logging use SimpleDateFormat or call various Calendar.get*() methods instead:

System.out.println(cal.get(Calendar.HOUR_OF_DAY));
System.out.println(cal.get(Calendar.MINUTE));

And as always with any questions regarding Java date/time handling, consider ...

Upvotes: 4

Related Questions