user3334226
user3334226

Reputation: 151

Change timezone of Date object without changing date

Can I change the timezone of Date object in my java code without changing the date? When I write Date date = new Date(longValue); I get this date in my local timezone. I want to get this date but my timezone should be one present in DB (not local) for my userID (for eg "America/Chicago").

Thanks in advance for your help.

Upvotes: 4

Views: 4865

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 338366

tl;dr

ZonedDateTime zdtMontreal = 
    ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );

ZonedDateTime zdtAuckland = 
    zdtMontreal.withZoneSameLocal( ZoneId.of( "Pacific/Auckland" ) );  

Not the same moment. The zdtAuckland moment occurred several hours earlier.

Be certain that is truly your intention. I have a sinking feeling you are doing the wrong thing, confused about how date-time handling works. Date-time work is confusing. Be sure to search and study Stack Overflow.

java.time

The Joda-Time project, now in maintenance mode, advises migration to java.time.

The Local… classes purposely have no time zone or offset-from-UTC information.

LocalDate ld = LocalDate.of( 2016 , Month.January , 23 ); // 2016-01-23
LocalTime lt = LocalTime.of( 12 , 34 , 56 );  // 12:34:56

These values do not yet represent a point on the timeline. Would that be the noon hour of Auckland NZ, Paris FR, or Montréal CA? We must apply a time zone to determine an actual moment. We apply a ZoneId to get a ZonedDateTime.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST or CST as they are not true time zones, not standardized, and not even unique(!).

ZoneId zMontreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtMontreal = ZonedDateTime.of( ld , lt , zMontreal );

To see a string representing this value in the standard ISO 8601 format, call toString. Actually, the ZonedDateTime class extends the standard format by wisely appending the name of the time zone in square brackets.

String outputMontreal = zdtMontreal.toString();

2016-01-23T12:34:56-05:00[America/Montreal]

To get the same date and same time-of-day in another time zone, repeat the process.

ZoneId zParis = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtParis = ZonedDateTime.of( ld , lt , zParis );

ZoneId zAuckland = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdtAuckland = ZonedDateTime.of( ld , lt , zAuckland );

But know that you are getting a different moment in time. Noon in Auckland happens several hours before noon in Paris, and noon in Montréal is even later, for three different points in time that happen to share coincidentally the same wall-clock time.

2016-01-23T12:34:56-05:00[America/Montreal]

2016-01-23T12:34:56+01:00[Europe/Paris]

2016-01-23T12:34:56+13:00[Pacific/Auckland]

enter image description here

Current moment

To get the current moment, call Instant.now. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Instant instance = Instance.now();

Apply a ZoneId to adjust into a time zone.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instance.atZone( z );

Repeat the process for other desired time zones, similar to what we did further above.

As a shortcut, you can get a ZonedDateTime directly.

ZonedDateTime zdtMontreal = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );

And as another shortcut, you can apply a different time zone while retaining the same date and same time-of-day (the same wall-clock time). Call ZonedDateTime::withZoneSameLocal.

ZonedDateTime zdtAuckland = zdtMontreal.withZoneSameLocal( ZoneId.of( "Pacific/Auckland" ) );

I repeat: This results is different points on the time line. The zdtAuckland is happening several hours before zdtMontreal occurs.

To keep the same moment, instead call ZonedDateTime::withZoneSameInstant.

Database

Usually best to store your date-time values in a database in UTC. Already discussed extensively on Stack Overflow. Search for more info.


About java.time

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 java.time.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

  • Java SE 8 and SE 9 and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android

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.

Upvotes: 14

Magd Kudama
Magd Kudama

Reputation: 3469

An example of how to do it using Java8 ZonedDateTime class:

Date date = new Date(longValue);
ZoneId = ZoneId.of("America/Chicago");
ZonedDateTime dt = ZonedDateTime.ofInstant(date.toInstant(), zoneId);

You've tagged the question with Joda, but really with Java8 you don't need it anymore.

Upvotes: 0

Coderslang Master
Coderslang Master

Reputation: 368

You may find ZonedDateTime quite helpful:

Java 8 Convert given time and time zone to UTC time

Alternatively you can create another Date object and apply some offset to it manually.

Upvotes: 0

Related Questions