Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 557
user3334226 Avatar asked Sep 02 '25 03:09

user3334226


1 Answers

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 ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
    • See How to use….

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.

like image 114
Basil Bourque Avatar answered Sep 04 '25 23:09

Basil Bourque