-1

I am receiving time from server in this format:

2018-04-04T08:41:21.265185Z

I have converted this time to local time. But after conversion the time I am getting time one hour more than the cctual current time.

This is code for time conversion:

SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
try {
   Date date=dateFormat.parse(bookingTime);
    TimeZone zone=TimeZone.getTimeZone("IST");
    dateFormat.setTimeZone(zone);
    tempTime=dateFormat.format(date);
    finalTime=tempTime.substring(11,16);
    Log.i("time",finalTime);
    Log.i("timeOriginal",tempTime);
} catch (ParseException e) {
    e.printStackTrace();
}  

How to subtract one hour from this converted server time to get actual time?

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Satyam Gondhale
  • 1,415
  • 1
  • 16
  • 43
  • Which time zone do you expect to get from `TimeZone.getTimeZone("IST")`? Rather avoid the ambiguous three and four letter abbreviations and specify either Europe/Dublin, Asia/Tel_Aviv or Asia/Kolkata (all of which are known as IST). – Ole V.V. Apr 05 '18 at 07:06
  • 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. Apr 05 '18 at 07:10

1 Answers1

3

The Z in the end means that the date/time is in UTC. When you put it inside quotes ('Z'), you're saying to the formatter that it should be treated as a literal (the letter Z itself), ignoring the fact that it's in UTC - and the formatter will use the JVM default timezone instead.

Another detail is that your input has 6 decimal digits for the fraction of seconds:

2018-04-04T08:41:21.265185Z

Unfortunately, SimpleDateFormat can handle only 3 decimal digits. With more than 3 digits, it gives wrong results.

One alternative is to discard the extra digits, leaving only 3. Then you use another formatter to get the output (better than substring it):

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
String input = "2018-04-04T08:41:21.265185Z";
// keep only 3 decimal digits, ignore the rest
input = input.replaceAll("(\\.\\d{3})\\d*", "$1"); // input is now "2018-04-04T08:41:21.265Z"
// parse it
Date date = dateFormat.parse(input);

SimpleDateFormat outputFormat = new SimpleDateFormat("HH:mm");
outputFormat.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
// convert the UTC date to another timezone
String finalTime = outputFormat.format(date); // 14:11

This converts the UTC's time (08:41) to India's timezone (14:11) - that's what I understood from your question that you're trying to do.

For the timezone name, I used "Asia/Kolkata". Abbreviations such as "IST" are ambiguous and the API usually doesn't do what you need (IST is used in Israel, Ireland and India, and who knows what the API considers to be the default).

To parse all the 6 fractional digits, the only way is to use another API. In Android you can use ThreetenABP, or java.time classes in API level 26:

Instant instant = Instant.parse("2018-04-04T08:41:21.265185Z");
String finalTime = instant
    // convert to another timezone
    .atZone(ZoneId.of("Asia/Kolkata"))
    // format (just hour and minutes) -> 14:11
    .format(DateTimeFormatter.ofPattern("HH:mm"));
flok
  • 120
  • 4
  • i have been told that modern versions of `SimpleDateFormat` *on Android* can handle more than three `S` in the format pattern string, as opposed to desktop Java. I certainly agree with skipping that troublesome class completely, adding ThreeTenABP to the project and using the modern API. – Ole V.V. Apr 05 '18 at 07:09