Timezone conversion

Viewed 111344

I need to convert from one timezone to another timezone in my project.

I am able to convert from my current timezone to another but not from a different timezone to another.

For example I am in India, and I am able to convert from India to US using Date d=new Date(); and assigning it to a calendar object and setting the time zone.

However, I cannot do this from different timezone to another timezone. For example, I am in India, but I am having trouble converting timezones from the US to the UK.

13 Answers

java.time

The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.

Also, quoted below is a notice at the Home Page of Joda-Time:

Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.

How to switch to the modern API?

Convert java.util.Date to Instant using Date#toInstant e.g.

Date date = new Date();
Instant instant = date.toInstant();
System.out.println(instant); // 2021-05-30T13:10:01.890Z

What's Instant got to do with my requirement?

An Instant represents an instantaneous point on the timeline in UTC. The Z in the sample output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours). Its zero-timezone offset makes it independent of timezones i.e. an instant is the same at every place in the world. It's analogous to water in the physical world.

You can mix a timezone (i.e. ZoneId) with an Instant by calling Instant.atZone to get the corresponding Date-Time in that timezone (i.e. ZonedDateTime).

Similarly, you can mix a timezone offset (i.e. ZoneOffset) with an Instant by calling Instant#atOffset to get the corresponding Date-Time with that timezone offset (i.e. OffsetDateTime).

In the reverse way, you can also get an Instant by calling toInstant on the ZonedDateTime or OffsetDateTime.

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Date;

public class Main {
    public static void main(String[] args) {
        Date date = new Date();
        Instant instant = date.toInstant();
        System.out.println(instant);

        // The corresponding Date-Time in Chicago
        ZonedDateTime zdtChicago = instant.atZone(ZoneId.of("America/Chicago"));
        System.out.println(zdtChicago);

        // The corresponding Date-Time in Kolkata
        ZonedDateTime zdtKolkata = instant.atZone(ZoneId.of("Asia/Kolkata"));
        System.out.println(zdtKolkata);

        // The corresponding Date-Time at timezone offset of -05:00 hours
        OffsetDateTime odtAtOffsetMinus0500 = instant.atOffset(ZoneOffset.of("-05:00"));
        System.out.println(odtAtOffsetMinus0500);

        // The corresponding Date-Time at timezone offset of +05:30 hours
        OffsetDateTime odtAtOffset0530 = instant.atOffset(ZoneOffset.of("+05:30"));
        System.out.println(odtAtOffset0530);
    }
}

Output:

2021-05-30T13:44:26.599Z
2021-05-30T08:44:26.599-05:00[America/Chicago]
2021-05-30T19:14:26.599+05:30[Asia/Kolkata]
2021-05-30T08:44:26.599-05:00
2021-05-30T19:14:26.599+05:30

So far you have learnt a simple way to convert an Instant (which you have created directly or obtained from a java.util.Date or a ZonedDateTime or an OffsetDateTime) to a Date-Time in any timezone or at any timezone offset.

Alternatively

There is another way to convert a ZonedDateTime from one timezone to another. Again, there is a similar method to convert an OffsetDateTime from one timezone offset to another.

import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        // Current Date-Time in Chicago
        ZonedDateTime zdtChicago = ZonedDateTime.now(ZoneId.of("America/Chicago"));
        System.out.println(zdtChicago);

        // The corresponding Date-Time in Kolkata
        ZonedDateTime zdtKolkata = zdtChicago.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));
        System.out.println(zdtKolkata);

        // Current Date-Time at a timezone offset of -05:00 hours
        OffsetDateTime odtAtOffsetMinus0500 = OffsetDateTime.now(ZoneOffset.of("-05:00"));
        System.out.println(odtAtOffsetMinus0500);

        // The corresponding Date-Time at timezone offset of +05:30 hours
        OffsetDateTime odtAtOffset0530 = odtAtOffsetMinus0500.withOffsetSameInstant(ZoneOffset.of("+05:30"));
        System.out.println(odtAtOffset0530);
    }
}

Output:

2021-05-30T10:03:59.895923-05:00[America/Chicago]
2021-05-30T20:33:59.895923+05:30[Asia/Kolkata]
2021-05-30T10:03:59.897782-05:00
2021-05-30T20:33:59.897782+05:30

When to use ZonedDateTime and when to use OffsetDateTime?

  • If you are dealing with a fixed timezone offset value e.g. 02:00 hours, use OffsetDateTime. It is also supported by all JDBC drivers. Check this answer to learn more about it.
  • If you want the timezone offset to change automatically based on DST, use ZonedDateTime. Unfortunately, ZonedDateTime is not supported by JDBC.

Learn more about java.time, the modern Date-Time API* from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

here a story: my user in US enters a date in a web page. My server gets this as a java.util.Date object. Date objects have no notion of time zone.

so let's say user entered 11PM(== 4AM london time). For her this was 11PM US time. Your server gets this and interprets this as 11PM of JVM's timezone. but what you need is a Date object that represents 4AM.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timeStringInUS =  sdf.format("2020-05-04 23:00:00");

SimpleDateFormat dateFormatInUS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat dateFormatInUK = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

dateFormatInUS.setTimeZone(TimeZone.getTimeZone("America/New_York"));
dateFormatInUK.setTimeZone(TimeZone.getTimeZone("Europe/London"));

Date dateInUS = dateFormatInUS.parse(timeStringInUS);
Date dateInUK = sdf.parse(dateFormatInUK.format(dateInUS));
public static String convertTimeBasedOnTimeZoneAndTimePattern(String dateTime,
  String fromTimeZone, String toTimeZone, String originalTimePattern, String timePattern) {

  DateTimeFormatter formatterNew = DateTimeFormatter.ofPattern(timePattern);

  DateTimeFormatter formatter = DateTimeFormatter.ofPattern(originalTimePattern);

  TemporalAccessor temporalAccessor = formatter.parse(dateTime);
  ZoneId z = ZoneId.of(fromTimeZone);
  LocalDateTime localDateTime = LocalDateTime.from(temporalAccessor);
  ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, z);
  Instant instant = Instant.from(zonedDateTime);

  ZonedDateTime fromZonedDateTime = instant.atZone(ZoneId.of(toTimeZone));

  String fromZoneDateTime = fromZonedDateTime.format(formatterNew);

return fromZoneDateTime;}

To convert any time to the specific timezone (for example: UTC -> local timezone and vise versa) with any time pattern you can use java.time library.

This method will take time patterns (original and required format) and timezone (original time zone and required timezone) will give String as output. you can convert String to date by using SimpleDateFormatter or also use parse method of the ZoneDateTime/Instant class.

To convert String to date:

public static final DATE_FORMAT="yyyy-MM-dd HH:mm:ss.SSSSS";
public static Date convertStringToDate(String date) {
    SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);

    Date parsedDate = null;

    try {
      parsedDate = formatter.parse(date);
    } catch (Exception e) {
      throw new DateTimeParseException("Please provide date time in proper format", null, 0, null);
    }
    return parsedDate;
  }

To convert date to String:

public String convertTextDateToDate(Date textDate) {
    // SimpleDateFormat sdf = new SimpleDateFormat("EE MMM dd HH:mm:ss z yyyy", //Locale.ENGLISH);

    SimpleDateFormat date = new SimpleDateFormat(DATE_FORMAT);
    String dateFormatted = date.format(textDate);
    return dateFormatted;
  }
Related