16

I created this wonderful static method yesterday, and it worked just fine - yesterday

However, today it gives me this error. I guess it is from too many 0s before the Z.

Can anyone recommend how to parse in a concise way (Java 8) this type of String format date - keeping in mind that it worked yesterday too, so ISO_INSTANT is also a valid format for the String?

Caused by: java.time.DateTimeException: Unable to obtain LocalDate from TemporalAccessor: {NanoOfSecond=0, InstantSeconds=1443451604, MilliOfSecond=0, MicroOfSecond=0},ISO of type java.time.format.Parsed
at java.time.LocalDate.from(LocalDate.java:368)
at java.time.LocalDateTime.from(LocalDateTime.java:456)
... 9 more

throwing an exception on input time: "2015-09-28T14:46:44.000000Z"

/**
 *
 * @param time the time in RFC3339 format (e.g. "2013-07-03T14:30:38Z" )
 * @return
 */
public static LocalDateTime parseTimeINSTANT(String time) {
    DateTimeFormatter f = DateTimeFormatter.ISO_INSTANT;
    return LocalDateTime.from(f.parse(time));
}

enter image description here

Tunaki
  • 132,869
  • 46
  • 340
  • 423
ycomp
  • 8,316
  • 19
  • 57
  • 95
  • 1
    ISO_INSTANT doesn't support timezones, can be fixed with something like: `Instant.from(DateTimeFormatter.ISO_DATE_TIME.parse("2017-04-20T00:00:00+04:00"))` – Pavel Evstigneev Apr 11 '17 at 07:55

4 Answers4

23

You are parsing a String that is consistent with an ISO instant so you need to store the result in a Instant instead of LocalDateTime:

public static Instant parseTimeINSTANT(String time) {
    DateTimeFormatter f = DateTimeFormatter.ISO_INSTANT;
    return Instant.from(f.parse(time)); // could be written f.parse(time, Instant::from);
}

Note that this formatter handles correctly fractional seconds so you don't need to remove them. Quoting DateTimeFormatter.ISO_INSTANT Javadoc (emphasis mine):

When parsing, time to at least the seconds field is required. Fractional seconds from zero to nine are parsed.

As to why it worked yesterday and not today, I have no idea...

Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • 1
    thanks, and it's ok to do `LocalDateTime.from(instant);` ? my code is really expecting the LocalDateTime format. nanoseconds are not important – ycomp Sep 28 '15 at 15:16
  • 2
    @ycomp You can convert an Instant to LocalDateTime, see [this answer](http://stackoverflow.com/a/19726814/1743880). – Tunaki Sep 28 '15 at 15:19
  • perhaps I just coded it yesterday, thought I ran it but never ran it until today - I can't see anything in my code that indicates I would have been able to run it yesterday.. so I guess it never actually worked the way I originally coded it – ycomp Sep 28 '15 at 15:55
9

Just for the sake of helping anyone seeing this question later.

You need to parse the ISO Date as Instant, convert it to Instant Object and then create a LocalDateTime from it providing the zone Id. I'm setting the zone Id of UTC here.

The code is as follows

public static LocalDateTime getISODate(String dateString) {
    DateTimeFormatter isoFormatter = DateTimeFormatter.ISO_INSTANT;
    Instant dateInstant = Instant.from(isoFormatter.parse(dateString));
    LocalDateTime date = LocalDateTime.ofInstant(dateInstant, ZoneId.of(ZoneOffset.UTC.getId()));

    return date;
}
Ahmed Kamal
  • 1,478
  • 14
  • 27
  • 1
    _As a side note:_ you could use a shorter form, like: `LocalDateTime.ofInstant(dateInstant, ZoneOffset.UTC)`, i.e. without getting `ZoneId` _explicitly_, because `ZoneOffset` (in this case it's `ZoneOffset.UTC`) extends `ZoneId`. – informatik01 Nov 03 '19 at 21:57
  • Aplying the shortcut informatik01 mentioned you end up in this line: `LocalDateTime date = LocalDateTime.ofInstant(dateInstant, ZoneOffset.UTC);` – Robert Sep 25 '20 at 09:08
4

You do not need a DateTimeFormatter

Parse your ISO 8601 compliant Date-Time string directly into an Instant using Instant#parse. The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards.

Demo:

import java.time.Instant;

public class Main {
    public static void main(String[] args) {
        Instant instant = Instant.parse("2015-09-28T14:46:44.000000Z");
        System.out.println(instant);
    }
}

Output:

2015-09-28T14:46:44Z

ONLINE DEMO

What if I want LocalDateTime at UTC?

Instant can be converted to other java.time types e.g.

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

public class Main {
    public static void main(String[] args) {
        Instant instant = Instant.parse("2015-09-28T14:46:44.000000Z");
        System.out.println(instant);

        LocalDateTime ldt = instant.atZone(ZoneOffset.UTC).toLocalDateTime();
        System.out.println(ldt);
    }
}

Output:

2015-09-28T14:46:44Z
2015-09-28T14:46:44

ONLINE DEMO

Learn more about the modern Date-Time API from Trail: Date Time.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
0

ISO_INSTANT does not have zone info. Just add that. Or use DateTimeFormatter.ISO_ZONED_DATE_TIME instead

import java.time.*;
import java.time.format.*;

public class TestMain {

    DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.of("Z"));

    DateTimeFormatter formatter2 = DateTimeFormatter.ISO_ZONED_DATE_TIME

    public static void main(String[] args) {
        ZonedDateTime.parse("2031-12-01T10:58:30Z", formatter);
        ZonedDateTime.parse("2031-12-01T10:58:30Z", formatter2);
    }
}
Valchkou
  • 369
  • 5
  • 8