Search code examples
androiddatetimeutc

Convert a date time string to Utc date time in android give an hour less


I have a date time string, which I need to convert to UTC format. I have used the below code.

SimpleDateFormat format = new SimpleDateFormat("MM/dd/yy HH:mm a",Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
    Date date = format.parse("09/06/19 06:39 pm");
    System.out.println(date);
    selectedDateForApi=date.toString();
} catch (ParseException e) {
    e.printStackTrace();
}

Output: Fri Sep 06 12:09:00 GMT+05:30 2019

The output is 1 hr less than the actual time. it should be Fri Sep 06 13:09:00 GMT+05:30 2019. What have I done wrong?


Solution

  • java.time and ThreeTenABP

        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()
                .appendPattern("MM/dd/yy hh:mm a")
                .toFormatter(Locale.ENGLISH);
        ZoneId zone = ZoneId.of("Asia/Kolkata");
    
        ZonedDateTime indiaDateTime = LocalDateTime
                .parse("09/06/19 06:39 pm", formatter)
                .atZone(zone);
        Instant utcDateTime = indiaDateTime.toInstant();
        System.out.println(utcDateTime);
    

    Output from this snippet is:

    2019-09-06T13:09:00Z

    The trailing Z in the output means UTC.

    The date and time classes that you were trying to use, SimpleDateFormat, TimeZone and Date, are all poorly designed and long outdated. Consider not using them. Instead I am using java.time, the modern Java date and time API. I and many find it much nicer to work with.

    I also use a proper time zone name, Asia/Kolkata. Using GMT+05:30 as a time zone is poor style and dangerous. In your case it probably works for dates after WWII and until Indian politicians change the time zone offset at some unknown time in the future. For other time zones, in particular those that use summer time (DST), you will run into incorrect results much faster.

    What went wrong in your code?

    There are two errors in your code. And possibly also a case of impossible expectations.

    First you are performing the opposite conversion of the one you said you wanted. You wanted to convert from your local time (India Standard Time) to UTC, but you are telling SimpleDateFormat that the string is already in UTC.

    Second you are using uppercase HH in your format pattern string, MM/dd/yy HH:mm a. HH is for hour of day from 00 through 23. Since you have pm in your string, you should use lowercase hh for hour within AM or PM from 01 through 12. It would have been reasonable to expect SimpleDateFormat to throw an exception when hour of day of 6 doesn’t agree with pm, but it’s typical for SimpleDateFormat to give you an incorrect result and pretend that all is well. It’s just one of the many troubles with this class.

    The errors in combination caused you string to be parsed as 06:39 AM in UTC, which is the same point in time as 12:09 PM at offset 05:30, the result you saw. It may also have been confusing you that your Date prints in your local time zone. A Date hasn’t got a time zone or offset in it, and Date objects always print in the default time zone of the JVM. In other words, if you wanted a Date in UTC, that is not possible. By contrast, the modern Instant, which also is independent of time zone, always prints in UTC, which I figured was probably what you wanted.

    Question: Can I use java.time on Android?

    Yes, java.time works nicely on 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 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 use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

    Links