1

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?

Manikandan
  • 1,479
  • 6
  • 48
  • 89
  • BST is +1 hours – JakeB Sep 06 '19 at 13:21
  • @JakeB, Kindly explain your comment, and where I need to add +1 – Manikandan Sep 06 '19 at 13:24
  • As an aside consider throwing away the long outmoded and notoriously troublesome `SimpleDateFormat` and friends, and adding [ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP) to your Android project in order to use `java.time`, the modern Java date and time API. It is so much nicer to work with. – Ole V.V. Sep 07 '19 at 08:46
  • 1
    @JakeB The questioner doesn’t seem to be using BST, and in any case the problem turned out to be somewhere else. – Ole V.V. Sep 07 '19 at 09:44

1 Answers1

2

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

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