0

I receive a date that represents a datetime in utc. Lets say: 21-Jun-2019 10:00

I'd like to convert this datetime to the timezone "Europe/Vienna" expecting: 21-Jun-2019 12:00

I do not understand, why my code below shows the same time for both

        Date utcFinish = new Date(new Date().getYear(), Calendar.JUNE, 21);
        TimeZone europeVienna = TimeZone.getTimeZone("Europe/Vienna");
        Calendar finishInViennaTime = Calendar.getInstance(europeVienna);
        finishInViennaTime.setTime(utcFinish);

        System.out.println(format.format(utcFinish));
        System.out.println(format.format(finishInViennaTime.getTime()));

Output:

2019-06-21 00:00
2019-06-21 00:00

What would be the best java7 only (no joda, localdate pls) solution!? Thank you

EDIT: I also tried:

        SimpleDateFormat formatWithTimezone = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        formatWithTimezone.setTimeZone(TimeZone.getTimeZone("Europe/Vienna"));

        SimpleDateFormat formatonly = new SimpleDateFormat("yyyy-MM-dd HH:mm");

        Date utcDate = new Date(new Date().getYear(), Calendar.JUNE, 21);

        System.out.println(formatonly.format(utcDate));
        System.out.println(formatWithTimezone.format(utcDate));

Output:

2019-06-21 00:00
2019-06-21 00:00

SOLUTION

Thanks for all the solutions. In the end the problem was the default timezone. Here is my current solution (further feedback welcome!):

        // Unfortunately this date has the wrong time zone (Local Time Zone),
        // because Date assumes Local Time Zone the database stores timestamps 
        // in utc that's why I now convert to a datestring and reparse

        Date finishTimeWrongTimeZone = new Date(new Date().getYear(), Calendar.JUNE, 21);
        // in reality i call the db here like getFinishTime();

        // get the plain date string without time shifting
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MMM-dd HH:mm");
        String dateWithoutTimeZone = formatter.format(finishTimeWrongTimeZone);

        // add the timezone to the formatter and reinterpret the datestring
        // effectively adding the correct time zone the date should be in
        formatter.setTimeZone(TimeZone.getTimeZone("UTC"));

        String finishTime = null;
        try {

            Date dateWithCorrectTimeZone = formatter.parse(dateWithoutTimeZone);

            // Convert to expected local time zone (europe/vienna)
            formatter.setTimeZone(TimeZone.getTimeZone("Europe/Vienna"));
            finishTime = formatter.format(dateWithCorrectTimeZone);

        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(finishTime);
Shakka
  • 137
  • 8
  • 2
    A date does not have a timezone. Conceptually, it is an instant in time (it only wraps a number of milliseconds after Unich Epoch), no matter where you are. Only when representing it as a String you attach a timezone, so it is the job of the DateFormat object to do the conversion. – spi Apr 17 '19 at 11:49
  • 1
    @Shakka, the above spi's comment is exactly why your approach of "no joda or localdate" is faulty. These new ways of doing things exist precisely because legacy JDK date types are poorly named at the very least, and tricky to work with correctly. – M. Prokhorov Apr 17 '19 at 11:53
  • side Note: Data class is outdated, poorly design and some methods are deprecated if possible use java.time api, ZonedDateTime class and your case getYear() is deprecated – Akash Shah Apr 17 '19 at 11:54
  • I understand that "JDK date types are poorly". I just have those limitations. I tried setting the timezone in dateFormat aswell but it does not work. – Shakka Apr 17 '19 at 11:55
  • 3
    Pretty sure that `new Date(...)` (which is deprecated btw) produces a time in local timezone, and not UTC. – TiiJ7 Apr 17 '19 at 11:59
  • https://stackoverflow.com/questions/2891361/how-to-set-time-zone-of-a-java-util-date – SatyaTNV Apr 17 '19 at 12:07
  • 1
    @TiiJ7, as said above, `java.util.Date` is just a number of milliseconds since epoch, and as such doesn't really contain any time zone information. However, that specific constructor does indeed use the default system timezone to infer how to convert hour-minute values (0-0 for this case) into the epoch seconds value. – M. Prokhorov Apr 17 '19 at 12:35

4 Answers4

1

Alter the Timezone before doing the format. The date will be "converted" accordingly, but as we already told you, this old coding style has a lot of flaws:

public static void main(String[] x) {
    Date instant = new Date(new Date().getYear(), Calendar.JUNE, 21); // this call assumes the Timezone is your current default (system dependant).
    DateFormat sdf = SimpleDateFormat.getDateTimeInstance();

    sdf.setTimeZone(TimeZone.getTimeZone("Europe/Vienna"));
    System.out.println(sdf.format(instant)); //21 juin 2019 00:00:00

    sdf.setTimeZone(TimeZone.getTimeZone("Europe/Greenwich"));
    System.out.println(sdf.format(instant)); // 20 juin 2019 22:00:00

}
spi
  • 1,673
  • 13
  • 19
  • aah I see ... my test is wrong. new Date uses the local timezone... I will report back if this solves my problem! – Shakka Apr 17 '19 at 12:10
1

I use one formatter object and changes the time zone on it

SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy HH:mm"); format.setTimeZone(TimeZone.getTimeZone("UTC"));

Date dUtc = format.parse("21-06-2019 10:00");
System.out.println(dUtc);

TimeZone europeVienna = TimeZone.getTimeZone("europe/vienna");

format.setTimeZone(europeVienna);
String sVienna = format.format(dUtc);
System.out.println(sVienna);
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
1

Modern (java.time) solution

I have a version for the old API below like you asked, but for completeness, I will also provide the more modern solution. I recommend you to look into ThreeTen-Backport if updating Java is not an option:

ZonedDateTime zdt = LocalDateTime.of(
    Year.now().getValue(), Month.JUNE, 21, 10, 0, 0
).atZone(ZoneOffset.UTC);

System.out.println(
    zdt.withZoneSameInstant(ZoneId.of("Europe/Vienna"))
      .format(DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm"))
);

Old (java.util) solution

new Date(...) is deprecated, and you should not use it. If you really need to stick to the old API; you'll need to use Calendar:

Calendar utcFinish = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
utcFinish.set(Calendar.MONTH, Calendar.JUNE);
utcFinish.set(Calendar.DATE, 21);
utcFinish.set(Calendar.HOUR_OF_DAY, 10);
utcFinish.set(Calendar.MINUTE, 0);

And then use a DateFormat with the time zone that you actually wish to print it with:

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
TimeZone europeVienna = TimeZone.getTimeZone("Europe/Vienna");
format.setTimeZone(europeVienna);

System.out.println(format.format(utcFinish.getTime()));

Output

Both solutions should output (at time of writing, in 2019):

2019-06-21 12:00
TiiJ7
  • 3,332
  • 5
  • 25
  • 37
  • thank you this works, the only problem I have is that I get a Date from the DB and if I call the calendar like so: utcFinish.setTime(myDate) -> I get the same behaviour again (meaning that I get the utc time) – Shakka Apr 17 '19 at 13:18
  • 1
    Hmm, the problem is probably with how you retrieve the date from the database then. When I had to get dates from the database, I also had a problem like that. I had to use the [getDate](https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html#getDate(int,%20java.util.Calendar)) method that takes an extra calendar as input and pass it a calendar with UTC timezone. Not sure that'll fix it for you but it is worth a shot. – TiiJ7 Apr 17 '19 at 13:25
  • that's a good way to improve my new solution (see above). Thanks for your comments you led me to the devilish default timezone detail! – Shakka Apr 24 '19 at 12:45
0

Please use SimpleDateFormat to convert timezone

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Date utcFinish = new Date(new Date().getYear(), Calendar.JUNE, 21);
TimeZone europeVienna = TimeZone.getTimeZone("Europe/Vienna");
format.setTimeZone(europeVienna);
System.out.println(format.format(utcFinish));
Viren
  • 1
  • 1
  • sorry this does not work for me, I get the same datetime! – Shakka Apr 17 '19 at 11:51
  • in retrospect: this did not work, because new Date() constructor sets the default Locale as the timezone and I therefore get no change in the time – Shakka Apr 24 '19 at 12:43