0

I'm trying to parse lets say "2020-01-12+01:00" with JSR-310 time.

I read it via DateTimeFormatter.ofPattern("yyyy-MM-ddVV"), however now if I want to transform that into a Instant via Instant.from(DateTimeFormatter.ofPattern("yyyy-MM-ddVV").parse("..."), it throws where it complains that time is null.

Which granted it is, but, I'd like to get Instant from that, i.e. epochMillis, so I can serialize the long into a database.

Is there a way around it? Basically I'd like to extend the "2020-01-12+01:00" to "2020-01-12T00:00.000+01:00" and parse that to Instant as usual

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
urSus
  • 12,492
  • 12
  • 69
  • 89

3 Answers3

1

You need to use DateTimeFormatterBuilder, specifying ISO_DATE format and a default time-of-day (midnight1):

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .append(DateTimeFormatter.ISO_DATE)
        .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
        .toFormatter();
Instant instant = Instant.from(formatter.parse("2020-01-12+01:00"));
System.out.println(instant);

1) The ChronoField can be any time-of-day field, i.e. HOUR_OF_DAY, CLOCK_HOUR_OF_DAY, MINUTE_OF_DAY, SECOND_OF_DAY, MILLI_OF_DAY, MICRO_OF_DAY, or NANO_OF_DAY.

Output

2020-01-11T23:00:00Z

If you want to retain the time zone offset, you need to use OffsetDateTime (or ZonedDateTime) instead of Instant:

OffsetDateTime dateTime = OffsetDateTime.parse("2020-01-12+01:00", formatter);
System.out.println(dateTime);
System.out.println(dateTime.format(DateTimeFormatter.ISO_DATE));

Output (from both OffsetDateTime and ZonedDateTime)

2020-01-12T00:00+01:00
2020-01-12+01:00
Andreas
  • 154,647
  • 11
  • 152
  • 247
0

You can use LocalDate.parse(dateString, formatter) using the Formatter you've made above to give you a LocalDate instance.

LocalDate can then give you a LocalDateTime at any time in that day, but (for example) you can get the start of day from it.

LocalDateTime has a toInstant method to give you an Instant.

Instant has a toEpochMilli method to get your long.

BeUndead
  • 3,463
  • 2
  • 17
  • 21
0

It’s easy enough when you know how. The formatter we need is built in. There’s a complication in the fact that there isn’t a type to parse the string into, no OffsetDate. I present two options for tackling this.

    String s = "2020-01-12+01:00";

    TemporalAccessor parsed = DateTimeFormatter.ISO_OFFSET_DATE.parse(s);
    LocalDate date = LocalDate.from(parsed);
    ZoneOffset offset = ZoneOffset.from(parsed);
    Instant result = date.atStartOfDay(offset).toInstant();

    System.out.println(result);

Output from this snippet is:

2020-01-11T23:00:00Z

We seldom need to use the TemporalAccessor interface directly, and it’s considered low-level. It also isn’t the only way to go here. The other good option is to define a default time of day so we can parse directly into an Instant:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_OFFSET_DATE)
            .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
            .toFormatter();
    Instant result = formatter.parse(s, Instant::from);

The result is the same as before.

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