Hadi Eskandari
Hadi Eskandari

Reputation: 26364

Converting UTC dates to other timezones

I'm converting a UTC time to another timezone, using this method:

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parsed = format.parse("2011-03-01 15:10:37");
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
format.setTimeZone(tz);

String result = format.format(parsed);

So the input is 2011-03-01 15:10:37 but the output of this (value of result) is 2011-03-01 05:40:37. While it seems off, and according to this link, it should be 2011-03-01 09:10:37.

What am I doing wrong?

Upvotes: 41

Views: 49962

Answers (7)

Seun Matt
Seun Matt

Reputation: 1858

The simple sequence I settled for is to parse the UTC time into a LocalDateTime and then create a ZonedDateTime with the desired timezone. The resulting ZonedDateTime can be used to get an Instant to construct a new Date object.

In the example snippet below, One can replace ZoneId.systemDefault() with the desired time zone id.


var instant = LocalDateTime.parse(serverDateTime, DateTimeFormatter.ISO_DATE_TIME)
                .atZone(ZoneId.of("UTC")) //the current zone is UTC
                .withZoneSameInstant(ZoneId.systemDefault()) //the new time zone
                .toInstant();

var date = Date.from(instant);

NB: To use LocalDateTime in Android API level below 26, you can add Android desugaring lib to your codebase.

Upvotes: 0

Anonymous
Anonymous

Reputation: 86324

java.time

Consider using java.time, the modern Java date and time API, for your date and time work.

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    ZoneId targetZone = ZoneId.of("America/Chicago");
    
    LocalDateTime parsed = LocalDateTime.parse("2011-03-01 15:10:37", formatter);
    ZonedDateTime converted = parsed.atOffset(ZoneOffset.UTC).atZoneSameInstant(targetZone);

    String result = converted.format(formatter);
    System.out.println(result);

Output is the expected:

2011-03-01 09:10:37

Question: Doesn’t java.time require Android API level 26?

java.time works nicely on both older and newer Android devices. It just requires at least Java 6.

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
  • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
  • On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.

Links

Upvotes: 2

Santhosh
Santhosh

Reputation: 5016

Following code works fine for me to change a date from one tz to another. It considers the DayLightSaving also.

public static Calendar changeTimezoneOfDate(Date date, TimeZone fromTZ, TimeZone toTZ) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    long millis = calendar.getTimeInMillis();
    long fromOffset = fromTZ.getOffset(millis);
    long toOffset = toTZ.getOffset(millis);
    long convertedTime = millis - (fromOffset - toOffset);
    Calendar c = Calendar.getInstance();
    c.setTimeInMillis(convertedTime);
    return c;
}

Upvotes: 10

Rehan Sarwar
Rehan Sarwar

Reputation: 1014

You can Parse your date format and time zone according to your requirements. Try this snippet of code i hope it helpful for you.

private String getFormattedDate(String OurDate) {
    try {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); // According to your Server TimeStamp
        formatter.setTimeZone(TimeZone.getTimeZone("UTC")); //your Server Time Zone
        Date value = formatter.parse(OurDate); // Parse your date

        SimpleDateFormat dateFormatter = new SimpleDateFormat("MM-dd-yyyy"); //this format changeable according to your choice
        dateFormatter.setTimeZone(TimeZone.getDefault());
        OurDate = dateFormatter.format(value);

    } catch (Exception e) {
        OurDate = "00-00-0000 00:00";

    }
    return OurDate;
}

Upvotes: 4

Hadi Eskandari
Hadi Eskandari

Reputation: 26364

It turns out the code was almost correct, what I didn't take into account was that when parsing the String to get a Date object initially, it uses default system TimeZone, so the source date was not in UTC as I expected.

The trick was to set the timezone when parsing the date to UTC and then set it to destination TimeZone. Something like this:

SimpleDateFormat sourceFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sourceFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date parsed = sourceFormat.parse("2011-03-01 15:10:37"); // => Date is in UTC now

TimeZone tz = TimeZone.getTimeZone("America/Chicago");
SimpleDateFormat destFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
destFormat.setTimeZone(tz);

String result = destFormat.format(parsed);

Upvotes: 76

QBLive
QBLive

Reputation: 313

Converting a date String of the format "2011-06-23T15:11:32" to out time zone.

 private String getDate(String dateString) {
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date value = null;
    try {
        value = formatter.parse(dateString);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yyyy hh:mmaa");
    dateFormatter.setTimeZone(TimeZone.getDefault());
    String dt = dateFormatter.format(value);

    return dt;
}

Upvotes: 14

Squonk
Squonk

Reputation: 48871

You need to take Daylight Savings into consideration. I do this by working out the offset (from UTC) in millieseconds. Something like this should work.

int currentOffsetFromUTC = tz.getRawOffset() + (tz.inDaylightTime(parsed) ? tz.getDSTSavings() : 0);
String result = format.format(parsed.getTime() + currentOffsetFromUTC);

The inDayLightTime(...) method returns a boolean and must be passed a Date object in order for it to decide if that 'date' represents one during a DST period or not.

Upvotes: 2

Related Questions