0

Searching up and down, right and left - don't find simple answer to this question:

I have java.util.Date instance, which get its value from mySQL.

Also I have time-zone code of the logged-in user.

I need to get the actual time at user time-zone.

For example:

My server-machine time-zone is GMT+2.

My date value in DB is: 2017-02-09 16:38:58.000

According to my server-machine-time-zone I get it into date instance as: 2017-02-09T16:38:58.000+0200

Now I need to know what to do if:

In case, for sample, my client-time-zone-code is GMT+4, I want to get:

2017-02-09 20:38:58.000

Pure date, that is right to my time zone and not contain "+4" or "GMT" indication.

In short words: convert my java.util.date to pure date that right to specific time-zone.

Sound very simple? after read very much documentaion, I already not sure that this is really simple.

user5260143
  • 1,048
  • 2
  • 12
  • 36
  • I recommend you don’t use `Date`. That class is poorly designed and long outdated. Instead use `LocalDateTime` and `OffsetDateTime` or `ZonedDateTime`, all from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Mar 12 '19 at 13:49
  • So do I understand correctly that the date-time in the database in UTC, but when you retrieve it, you (incorrectly) receive 2017-02-09T16:38:58.000+0200? So we need to compensate for the error *and* convert to the client’s time zone? Sure we can do that. – Ole V.V. Mar 12 '19 at 13:56

2 Answers2

4

Timestamp (with time zone)

As far as I have understood, the date-time in your database in UTC, but when you retrieve it, you (incorrectly) receive 2017-02-09T16:38:58.000+02:00.

First, if you can, change the datatype of your MySQL database column to timestamp (in some other databases it would be called timestamp with time zone). This will make sure that MySQL knows that the times are in UTC and should enable you to retrieve them as the right point in time rather than the right time of day in the wrong time zone. This in turn will give you the best starting point for converting to the client time zone.

java.time

Second, retrieve your value into an appropriate type from java.time, the modern Java date and time API. Avoid java.util.Date since it is poorly designed and cannot handle different time zones. For example, if your database datatype is datetime:

    LocalDateTime dateTime = yourResultSet.getObject("your_col", LocalDateTime.class);

LocalDateTime is a date and time of day without time zone, so you cannot get the wrong time zone. Supply the offset that you know is right:

    OffsetDateTime odt = dateTime.atOffset(ZoneOffset.UTC);

Convert to client time zone:

    ZoneId clientTimeZone = ZoneId.of("Indian/Reunion");
    ZonedDateTime clientDateTime = odt.atZoneSameInstant(clientTimeZone);

    System.out.println(clientDateTime);

2017-02-09T20:38:58+04:00[Indian/Reunion]

Do yourself the favour of using a real time zone in the region/city format rather than an offset like +04:00. It’s easier to understand and more future-proof. Indian/Reunion is just an example, of course, use the correct one for your client.

The ZonedDateTime above has both offset and time zone in it. It’s recommended to keep it that way, and I don’t see it doing any harm. The client can always opt not to display it. If you still insist, convert to LocalDateTime again:

    LocalDateTime clientDateTimeWithoutOffset = clientDateTime.toLocalDateTime();
    System.out.println(clientDateTimeWithoutOffset);

2017-02-09T20:38:58

If the database datatype is timestamp:

    OffsetDateTime odt = yourResultSet.getObject("your_col", OffsetDateTime.class);

This saves the first step above. The remainder is the same.

Link

Oracle tutorial: Date Time explaining how to use java.time.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • First thanks for your best and precise answer. I will use this information in the future. I accept other answer becouse in my case I cannot change db declaration, but I vote up. – user5260143 Mar 13 '19 at 09:18
  • Thanks for reporting back! Just to make sure, you did notice that I show you how to use java.time without changing the DB declaration? Since you are using the other answer, you are of course doing the right thing by accepting it (you may consider upvoting it too). – Ole V.V. Mar 13 '19 at 10:06
  • Sorry for the delay, I had other urgent things to do. I have a problem: I use hibernate query with result transformer, and it say that the value cannot be converted to LocalDateTime (even that value in mySql is datetime typed)/ any solution? – user5260143 Mar 26 '19 at 10:40
  • Sorry, my Hibernate experience is so tiny and lies many years back. I was under the impression that it ought to work, but what exactly it takes — I’m sure someone else can answer. – Ole V.V. Mar 27 '19 at 14:21
0

java.util.Date does not store any time zone. It just stores the number of milliseconds since the 'epoch', which is 1 January 1970, 00:00:00 UTC.

Thus, all you have to do is to know the time zone of your server machine, find the period between this time zone and the time zone you want to convert it to and add or subtract the period.

UPDATE:

int clientGMT = 4; //GMT you want to convert to
int serverGMT = 2; //server's GMT
int delta = clientGMT - serverGMT; //delta between the dates

//assume this is the date in GMT + 2 received from the server
Date d1 = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss").parse("12.03.2019 13:00:00");

//... and you want to convert it to GMT + 4 (client side's time zone)
Date resultDate = new Date(d1.getTime() + delta * 3600000);

P.S. Yes, you have to manipulate time zones manually, as I said above, java.util.Date does not store this information (each date is assumed to be in UTC).

Pavel Smirnov
  • 4,611
  • 3
  • 18
  • 28
  • Sound very simple, but can you add code of how to do that? I also thought this is simple untill I tried to code it... – user5260143 Mar 12 '19 at 09:37
  • Check this out. – Pavel Smirnov Mar 12 '19 at 10:28
  • Of course Java.util.date include info about timezone! if you ask its value you get what it register in its property "cdate" – user5260143 Mar 12 '19 at 10:36
  • "cdate" has nothing to do with timezones. Read carefully this https://docs.oracle.com/javase/7/docs/api/java/util/Date.html and this https://stackoverflow.com/questions/1516213/is-java-util-date-using-timezone/1522571 – Pavel Smirnov Mar 12 '19 at 11:01
  • 1
    Please don’t teach the young ones to use the long outdated and notoriously troublesome `SimpleDateFormat` class. At least not as the first option. And not without any reservation. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/) and its `DateTimeFormatter`. – Ole V.V. Mar 12 '19 at 13:50
  • 2
    The approach shown is an anti-pattern. 1) it doesn't take DST into account. 2) It creates an object representing a different point in time. 3) it relies on the server's time zone setting, which should be irrelevant. – Matt Johnson-Pint Mar 12 '19 at 15:16
  • FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Mar 12 '19 at 18:18