58

I get a date from a JSON API which looks like this "2018-04-10T04:00:00.000Z". I want to convert it in order to obtain a Date or String object and get something like "01-04-2018" that its "dd-MM-YYYY". How can I do it?

Miguel Barra
  • 769
  • 1
  • 5
  • 7
  • 1
    Use `SimpleDateFormat` –  Apr 10 '18 at 11:13
  • 3
    ...or use the Java 8 date API. Either way, this is a duplicate. – Tim Biegeleisen Apr 10 '18 at 11:13
  • 3
    @Arvind Please don’t teach the young ones to use the long outdated and notoriously troublesome `SimpleDateFormat` class. At least not as the first option. And not without any reservation. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/) and its `DateTimeFormatter`. Yes, you can use it on Android. For older Android see [How to use ThreeTenABP in Android Project](https://stackoverflow.com/questions/38922754/how-to-use-threetenabp-in-android-project). – Ole V.V. Apr 10 '18 at 11:25
  • 1
    Search Stack Overflow before posting. You can assume all the basic date-time Questions have been asked and answered already. – Basil Bourque Apr 10 '18 at 16:29

2 Answers2

115

Update: Using DateTimeFormat, introduced in java 8:

The idea is to define two formats: one for the input format, and one for the output format. Parse with the input formatter, then format with the output formatter.

Your input format looks quite standard, except the trailing Z. Anyway, let's deal with this: "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'". The trailing 'Z' is the interesting part. Usually there's time zone data here, like -0700. So the pattern would be ...Z, i.e. without apostrophes.

The output format is way more simple: "dd-MM-yyyy". Mind the small y -s.

Here is the example code:

DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("dd-MM-yyy", Locale.ENGLISH);
LocalDate date = LocalDate.parse("2018-04-10T04:00:00.000Z", inputFormatter);
String formattedDate = outputFormatter.format(date);
System.out.println(formattedDate); // prints 10-04-2018

Original answer - with old API SimpleDateFormat

SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
SimpleDateFormat outputFormat = new SimpleDateFormat("dd-MM-yyyy");
Date date = inputFormat.parse("2018-04-10T04:00:00.000Z");
String formattedDate = outputFormat.format(date);
System.out.println(formattedDate); // prints 10-04-2018
Tamas Rev
  • 7,008
  • 5
  • 32
  • 49
  • 9
    Please don’t teach the young ones to use the long outdated and notoriously troublesome `SimpleDateFormat` class. At least not as the first option. And not without any reservation. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/) and its `DateTimeFormatter`. Yes, you can use it on Android. For older Android see [How to use ThreeTenABP in Android Project](https://stackoverflow.com/questions/38922754/how-to-use-threetenabp-in-android-project). – Ole V.V. Apr 10 '18 at 11:24
  • Right, Sir, updated the answer. – Tamas Rev Apr 10 '18 at 11:34
  • Acknowledged and upvoted, Tamas. As input formatter you may use [`DateTimeFormatter.ISO_OFFSET_DATE_TIME`](https://docs.oracle.com/javase/9/docs/api/java/time/format/DateTimeFormatter.html#ISO_OFFSET_DATE_TIME), so you don’t need to roll your own. – Ole V.V. Apr 10 '18 at 11:36
  • Thanks! This `DateTimeFormatter.ISO_OFFSET_DATE_TIME` is nice. Cannot use here unfortunately as OP has a literal `Z` in his input string. Probably they have formatting problems in other parts of their systems, that's why it's not a real time zone data. Anyway, that's a separate problem. – Tamas Rev Apr 10 '18 at 11:40
  • 4
    `LocalDate.parse("2018-04-10T04:00:00.000Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)` works nicely and gives `2018-04-10`. `Z` is a perfectly valid offset, widely used rather than +00:00. – Ole V.V. Apr 10 '18 at 11:45
  • Indeed. I thought it would work the same way `SimpleDateFormat` does. It's great to learn from comment on answers :) – Tamas Rev Apr 10 '18 at 11:49
  • 2
    The `Z` means that the date/time is in UTC, according to [ISO 8601's definition](https://en.wikipedia.org/wiki/ISO_8601#Coordinated_Universal_Time_(UTC)). As said by OleVV, it can be used when the offset is zero (+00:00). Using `SimpleDateFormat` with `Z` inside quotes makes it parse the Z as a literal (the letter Z), instead of parsing it as a zero-offset. The problem is that, in this case, `SimpleDateFormat` will use the JVM default timezone, and the `Date` will correspond to a wrong point in time. – paulXkt Apr 10 '18 at 18:02
  • @OleV.V. I'm not sure you can always rely on those nicer new Java date utilities always being available in Android. – pyetti Aug 14 '18 at 04:32
  • @pyetti I don’t know the exact limit, but it is my understanding that the ThreeTenABP library works on pretty old Android versions too. You are right, the features are only built-in from API level 26, under that level you need the mentioned library. – Ole V.V. Aug 14 '18 at 08:16
  • 1
    It seems this way needs minimum API level 26. I'm wondering if there's a way to do this using functions from minimum API 23 – Kira Nofans Jun 09 '20 at 05:49
9

Using Date pattern yyyy-MM-dd'T'HH:mm:ss.SSS'Z' and Java 8 you could do

String string = "2018-04-10T04:00:00.000Z";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
LocalDate date = LocalDate.parse(string, formatter);
System.out.println(date);

Update: For pre 26 use Joda time

String string = "2018-04-10T04:00:00.000Z";
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
LocalDate date = org.joda.time.LocalDate.parse(string, formatter);

In app/build.gradle file, add like this-

dependencies {    
    compile 'joda-time:joda-time:2.9.4'
}
Deb
  • 2,922
  • 1
  • 16
  • 32
  • works great but this call requires API Level 26 (current min is 15) on my Android app and I don't want to change it for now. There is another alternative? – Miguel Barra Apr 10 '18 at 11:23
  • 1
    This will work nicely on older Android too. For pre-level-26 see [How to use ThreeTenABP in Android Project](https://stackoverflow.com/questions/38922754/how-to-use-threetenabp-in-android-project). – Ole V.V. Apr 10 '18 at 11:25
  • Since the string is in ISO 8601 format, you don’t even need an explicit formatter. The `java.time` classes parse this format as their default. `LocalDate date = OffsetDateTime.parse(string).toLocalDate()`. – Ole V.V. Apr 10 '18 at 11:30
  • 2
    Joda-Time was a very good library. “Joda-Time is considered to be a largely “finished” project. … If using Java SE 8, please migrate to java.time (JSR-310).” Quoted from [the Joda-Time homepage](http://www.joda.org/joda-time/). So I recommend ThreeTenABP over Joda-Time. – Ole V.V. Apr 10 '18 at 11:33
  • Ole V.V is right. Joda time suggested to migrate to java.time. I didn't have the oppertunity to use the ThreeTenABP before, so I can not tell / suggest about it. – Deb Apr 10 '18 at 11:42
  • 1
    This Answer ignores the crucial issue of the me zone. For any given moment, **the date varies** around the globe by zone. – Basil Bourque Apr 10 '18 at 16:28