tl;dr
- You are seeing a feature, not a bug, adjusting same moment to another time zone.
- 8 PM in eastern Europe is also 7 AM in Hawaii.
- Use real time zone names, not 3-4 letter pseudo zones.
- Use modern java.time classes, not poorly-designed legacy classes.
Same moment: Call withZoneSameInstant
You adjusted from one time zone 3 hours ahead of UTC to another zone 10 hours behind UTC, for a total difference of 13 hours. Understand that 8 PM in one place is simultaneously 7 AM in the other.
Note our call to withZoneSameInstant
(‘Instant’) in the following code.
ZonedDateTime.of(
2018 , 7 , 9 , 20 , 2 , 0 , 0 , ZoneId.of( "Europe/Athens" ) // 8 PM in Greece.
)
.withZoneSameInstant( // Adjust into another time zone to view the same moment with another wall-clock time.
ZoneId.of( "Pacific/Honolulu" ) // 7 AM in Hawaii.
)
.toString()
2018-07-09T07:02-10:00[Pacific/Honolulu]
Different moment: Call withZoneSameLocal
Apparently you wanted a different moment, a different point on the timeline, that has the same date and same time-of-day but a different time zone.
Note our call to withZoneSameLocal
(‘Local’, not ‘Instant’) in the following code.
ZonedDateTime.of(
2018 , 7 , 9 , 20 , 2 , 0 , 0 , ZoneId.of( "Europe/Athens" ) // 8 PM in Greece.
)
.withZoneSameLocal( // Different moment, coincidentally having the same date and same time-of-day. But different time zone means this is a different point on the timeline.
ZoneId.of( "Pacific/Honolulu" ) // Also 8 PM in Hawaii, which happens many hours later than 8 PM in Greece. Different moment, same wall-clock time.
)
.toString()
2018-07-09T20:02-10:00[Pacific/Honolulu]
Details
Real time zone
HST
& EEST
are pseudo-zones, not real time zones. Avoid these 3-4 letter codes as they are not standardized and are not even unique(!).
Use real time zone names as defined in tzdata by the IANA. See a list in Wikipedia (possibly outdated). These names are in Continent/Region
format such as America/Montreal
or Europe/Tallinn
.
ZoneId z = ZoneId.of( "Europe/Vilnius" ) ;
Avoid legacy date-time classes
Avoid the terribly troublesome classes Calendar
& SimpleDateFormat
. These were supplanted years ago by the java.time classes. Working with java.time is much clearer and easier.
Let's get your starting point. I am guessing that by EEST
you had in mind one of the eastern European time zones. I am choosing one arbitrarily.
ZoneId zAthens = ZoneId.of( "Europe/Athens" ) ;
LocalDate ld = LocalDate.of( 2018 , Month.JULY , 9 ) ; // 2018-07-09.
LocalTime lt = LocalTime.of( 20 , 2 ) ; // 8:02 PM.
ZonedDateTime zdtAthens = ZonedDateTime.of( ld , lt , zAthens ) ;
Generate a String
representing the value of that ZonedDateTime
object. By default, use standard ISO 8601 format wisely extended to append the name of the time zone in square brackets.
String outputAthens = zdtAthens.toString() ; // Generate `String` in a format extending standard ISO 8601 format.
2018-07-09T20:02+03:00[Europe/Athens]
By HST
I guess you mean Hawaii time. The proper name for that zone is Pacific/Honolulu
.
ZoneId zHonolulu = ZoneId.of( "Pacific/Honolulu" ) ;
Let's adjust our Athens moment into this other zone for Hawaii. Same moment, same point on the timeline, but a different wall-clock time. Imagine a pair of friends in each place calling each and simultaneously looking up at a clock on their wall. Each sees a different time-of-day and possibly a different date, nevertheless they experience the same simultaneous moment, same point on the timeline.
ZonedDateTime zdtHonolulu = zdtAthens.withZoneSameInstant( zHonolulu ) ; // Same moment (same `Instant` inside the `ZonedDateTime`) but a different time zone.
On that date, Honolulu is ten hours behind UTC while Athens is three hours ahead. That is a total delta of thirteen hours. So, 8 PM (20:00) minus 13 is 7 AM. We expect to see 7 AM in Hawaii. Let's verify, by generating another string in ISO 8601 format.
String outputHonolulu = zdtHonolulu.toString() ; // Generate `String` representing the value of the `ZonedDateTime` object.
2018-07-09T07:02-10:00[Pacific/Honolulu]
Sure enough, 7 AM.
Perhaps what you wanted was the same date and same time-of-day located in Hawaii. This would mean you are not representing the same simultaneous moment. You would be representing a different point on the timeline, off by several hours.
The ZonedDateTime
does provide for this function. Call ZonedDateTime::withZoneSameLocal
meaning conceptually: Use the same internal LocalDate
and the same internal LocalTime
, but use a different assigned ZoneId
.
ZonedDateTime eightPmOnJuly9InPacificHonolulu = zdtAthens.withZoneSameLocal( zHonolulu) ;
String outputDifferentMoment= eightPmOnJuly9InPacificHonolulu.toString() ;
2018-07-09T20:02-10:00[Pacific/Honolulu]
UTC
All this flipping around between time zones can drive a person batty. Get grounded by focusing on UTC. Think of UTC as The One True Time, and all other zones are but mere variations.
To adjust from a time zone to UTC, extract a Instant
object from our ZonedDateTime
objects. An Instant
is always in UTC by definition.
Instant instantAthens = zdtAthens.toInstant() ;
Instant instantHonolulu = zdtHonolulu.toInstant() ;
Instant instantDifferentMoment = eightPmOnJuly9InPacificHonolulu.toInstant() ;
2018-07-09T17:02:00Z
2018-07-09T17:02:00Z
2018-07-10T06:02:00Z
The Z
on the end means UTC, is pronounced Zulu, and is defined by ISO 8601 and other standards.
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 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.