Harini Ganta
Harini Ganta

Reputation: 1

Timezone conversion for a specific datetime in java

I will be giving input date time for a timezone and the timezone for the input date time and we want the relevant DateTime in the expected timezone.

And here is my method.

convertToTimezone("03/08/2010 20:19:00 PM","Asia/Shanghai","US/Central");

The above time is the time in Asia/Shanghai. We would like to know what is the corresponding time in US/Central.

It's working fine but I am getting a 1-hour difference from the actual time.

Can I know where I am going wrong?

Here is the code:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class DateUtil {

    private static String format_date = "MM/dd/yyyy HH:mm:ss a";

    public static void main(String a[]) {
        try {
            String sourceTimezone = "Asia/Shanghai";
            String destTimezone = "US/Central";
            String outputExpectedTimezone = convertToTimezone("03/08/2010 20:19:00 PM", sourceTimezone, destTimezone);
            System.out.println("outputExpectedTimezone :" + outputExpectedTimezone);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static String convertToTimezone(String inputDate, String inputDateTimezone, String destinationDateTimezone)
            throws Exception {
        String outputDate = null;

        SimpleDateFormat format = new SimpleDateFormat(format_date);
        format.setTimeZone(TimeZone.getTimeZone(inputDateTimezone));

        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(inputDateTimezone));
        calendar.setTime(format.parse(inputDate));
        calendar.add(Calendar.MILLISECOND, -(calendar.getTimeZone().getRawOffset()));
        calendar.add(Calendar.MILLISECOND, -calendar.getTimeZone().getDSTSavings());
        calendar.add(Calendar.MILLISECOND, TimeZone.getTimeZone(destinationDateTimezone).getRawOffset());

        outputDate = format.format(calendar.getTime());
        return outputDate;
    }
}

Upvotes: 0

Views: 1088

Answers (2)

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79550

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 from 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.

Solution using java.time, the modern Date-Time API:

  • Since your input Date-Time does not have timezone information, parse it into a LocalDateTime
    • Attach the timezone of the input Date-Time with it to get a ZonedDateTime

Demo:

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // Tests
        System.out.println(convertToTimezone("03/08/2010 20:19:00 PM", "Asia/Shanghai", "US/Central"));
        System.out.println(convertToTimezone("03/08/2010 20:19:00 PM", "Asia/Shanghai", "America/Mexico_City"));
    }

    static String convertToTimezone(String inputDate, String inputDateTimezone, String destinationDateTimezone) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd/uuuu HH:mm:ss a", Locale.ENGLISH);
        LocalDateTime ldt = LocalDateTime.parse(inputDate, dtf);
        ZonedDateTime zdtInput = ldt.atZone(ZoneId.of(inputDateTimezone));
        ZonedDateTime zdtDestination = zdtInput.withZoneSameInstant(ZoneId.of(destinationDateTimezone));
        return zdtDestination.format(dtf);
    }
}

Output:

03/08/2010 06:19:00 AM
03/08/2010 06:19:00 AM

ONLINE DEMO

Note: Avoid using the deprecated ID, US/Central. Use the standard ID, America/Mexico_City where Mexico City is the largest city in this timezone.

Learn more about 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.

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1503200

You shouldn't be adding anything to the calendar - that represents a specific instant in time. In fact, you don't need a calendar at all.

Instead, have two different formats, one for each time zone:

public static String convertToTimezone(String inputDate,
     String inputDateTimezone,
     String destinationDateTimezone)
     throws Exception
{
    SimpleDateFormat parser = new SimpleDateFormat(format_date);
    parser.setTimeZone(TimeZone.getTimeZone(inputDateTimezone));

    Date date = parser.parse(inputDate);

    SimpleDateFormat formatter = new SimpleDateFormat(format_date);
    formatter.setTimeZone(TimeZone.getTimeZone(outputDateTimezone));
    return formatter.format(date);
}

As an aside, I'd thoroughly recommend using Joda Time instead of the built-in date/time API.

Upvotes: 2

Related Questions