40

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?

Sufian
  • 6,405
  • 16
  • 66
  • 120
Hadi Eskandari
  • 25,575
  • 8
  • 51
  • 65

7 Answers7

75

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);
Hadi Eskandari
  • 25,575
  • 8
  • 51
  • 65
  • 3
    don't forget the `try{} catch (ParseException e){}` around `sourceFormat.parse()`. Also, to get the local timezone that the phone is in then use `TimeZone.getDefault()` so that you can convert UTC to local timezone – Someone Somewhere Feb 13 '13 at 00:32
  • @hadi Eskandari Mate you just saved me! I was tearing my hair out trying to figure this problem...! I pull down values from our server and store to a Database before i display to screen. The server dates are stored in AEST (Australian Eastern Standard) and I was having your exact problem where it was using the default system timezone so interpreting the time wrong. When i tried changing to another date it was always wrong :) I just needed `formater.setTimeZone(TimeZone.getTimeZone(RBApplication.adjustTimezoneAEST));` before my parsing line. Cheers i was on this problem for a few hours! – wired00 Feb 26 '13 at 07:43
  • the "HH" in SimpleDateFormat is for 24 hours and not for 12 hours, that ate up my 2 hours of debugging – Khurram Shehzad Jan 15 '16 at 10:52
14

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;
}
Jon Adams
  • 24,464
  • 18
  • 82
  • 120
QBLive
  • 313
  • 1
  • 5
  • 11
10

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;
}
Santhosh
  • 4,956
  • 12
  • 62
  • 90
4

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;
}
Rehan Sarwar
  • 994
  • 8
  • 20
2

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.

Squonk
  • 48,735
  • 19
  • 103
  • 135
2

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

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

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.

Seun Matt
  • 1,660
  • 1
  • 9
  • 14