-1

I have some TimeStamp and I have date format "EEEE, MMM dd, yyyy hh:mm a zzz". But I don't know how I can show this timestamp with timezone. When I trying to show it I get wrong DateTime or wrong timezone

example1:

Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(device.getUpdatedDate().getTime())); // here is 2018-07-09 20:02:26.506000
SimpleDateFormat sdf = new SimpleDateFormat(EMAIL_DATE_FORMAT);
sdf.format(calendar.getTime()); // i have wrong timezone

and i get Monday, Jul 09, 2018 08:02 PM EEST

but when i add sdf.setTimeZone(TimeZone.getTimeZone("HST")); i have right timezone and wrong time Monday, Jul 09, 2018 07:02 AM HST

expected result Monday, Jul 09, 2018 08:02 PM HST

actual results: Monday, Jul 09, 2018 08:02 PM EEST or Monday, Jul 09, 2018 07:02 AM HST

Basil Bourque
  • 218,480
  • 72
  • 657
  • 915
JVic
  • 131
  • 1
  • 11
  • 1
    Well you could have an error in your code. Would you like to show it? Some people here are able to find errors in code they are looking at. But without code, that is quite hard to do... – Yunnosch Jul 10 '18 at 05:47
  • what you have tried so far please post your code – Sasikumar Murugesan Jul 10 '18 at 05:47
  • 1
    Pleae study and apply the concept of making a [mcve]. – Yunnosch Jul 10 '18 at 05:47
  • Please read the MCVE link and try harder to create one. – Yunnosch Jul 10 '18 at 05:57
  • Add some sets of sample data, the output and desired output in comparison. – Yunnosch Jul 10 '18 at 05:57
  • @SharonBenAsher updated the question – JVic Jul 10 '18 at 06:28
  • Be aware that a `Date` hasn’t got a time zone. See [All about java.util.Date](https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/). Is `device.getUpdatedDate()` a `Date` too? – Ole V.V. Jul 10 '18 at 07:43
  • 1
    I recommend you avoid the `Calendar`, `Date` and `SimpleDateFormat` classes. They are not only long outdated, they are also poorly designed and `SimpleDateFormat` in particular notoriously troublesome. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Jul 10 '18 at 07:49
  • Assuming you have got a legacy `Date` object, first convert to the modern `Instant` class, then do further opreations from there: `device.getUpdatedDate().toInstant().atZone(ZoneId.of("Pacific/Honolulu")).format(DateTimeFormatter.ofPattern("EEEE, MMM dd, yyyy hh:mm a zzz", Locale.US))`. – Ole V.V. Jul 10 '18 at 07:55
  • What `TimeStamp`? I see only `Calendar` in your example code. – Basil Bourque Jul 10 '18 at 22:52

2 Answers2

1

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.

Basil Bourque
  • 218,480
  • 72
  • 657
  • 915
0

As I understand device.getUpdatedDate() returns a java.sql.Timestamp, for example 2018-07-09 20:02:26.506000. I assume that (contrary to the idea of a timestamp) this date and time was produced without time zone, but that you know that it is in Pacific/Honolulu time zone (Hawaii Standard Time or HST, used in Hawaii all year).

If you are getting the Timestamp from an SQL database (as would be normal) — don’t. The Timestamnp class is long outdated and quite confusing. Assuming you are using at least Java 8 and at least JDBC 4.2, you may get an instance of the modern LocalDateTime from the database instead. Assuming that rs is your result set and your column is named updated_date (I trust you to tailor the code to your situation):

    DateTimeFormatter formatter
            = DateTimeFormatter.ofPattern(EMAIL_DATE_FORMAT, Locale.US);
    LocalDateTime updatedDateTime 
            = rs.getObject("updated_date", LocalDateTime.class);
    ZonedDateTime timeOnHawaii 
            = updatedDateTime.atZone(ZoneId.of("Pacific/Honolulu"));
    String formattedDateTime = timeOnHawaii.format(formatter);

If your timestamp is stored in the database with time zone information you can do even better by using Instant.class instead and be sure to get the same point in time as in the database. The exact possibilities depend on the capabilities of your JDBC driver.

In case you cannot avoid getting the Timestamp, convert it like this:

    ZonedDateTime timeOnHawaii = device.getUpdatedDate()
            .toLocalDateTime()
            .atZone(ZoneId.of("Pacific/Honolulu"));

With your example Timestamp and the formatter from my first code snippet above this prints:

Monday, Jul 09, 2018 08:02 PM HST

(assuming that EMAIL_DATE_FORMAT is defined as "EEEE, MMM dd, yyyy hh:mm a zzz").

What went wrong in your code?

One confusing thing about Timestamp is that it represents a point in time (without time zone) but has often been used for representing a date and time of day (also without time zone) instead. So your Timestamp of 2018-07-09 20:02:26.506000 really holds the value (point in time) equal to 2018-07-09 20:02:26.506000 Eastern European Summer Time (EEST, as used in Украина/Ukraine) but is confusingly used by device.getUpdatedDate() to mean 2018-07-09 20:02:26.506000 in Hawaii. Neither Date nor SimpleDateFormat change the point in time, which is why they give you Monday, Jul 09, 2018 08:02 PM EEST or the equivalent Monday, Jul 09, 2018 07:02 AM HST.

Links:

Ole V.V.
  • 65,573
  • 11
  • 96
  • 117