0

Consider a String "2022-03-23 21:06:29.4933333 +00:00". How do I parse the above DateTimeOffset String to LocalDateTime in Java?

I tried with the following DateTimeFormatter but the format seems to be incorrect:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss\[.nnnnnnn\] \[+|-\]hh:mm\]");

LocalDateTime dateTime = LocalDateTime.parse(timestamp, formatter)
nathan liang
  • 1,000
  • 2
  • 11
  • 22
Moo
  • 5
  • 5
  • 1
    Go via `ZonedDateTime` first – MadProgrammer Mar 23 '22 at 23:18
  • 1
    Do you understand that by using `LocalDateTime`, you will be discarding vital information: the offset? Your input represents a moment, a specific point on the timeline. But a `LocalDateTime` cannot, by definition. You should be using `OffsetDateTime` here. – Basil Bourque Mar 24 '22 at 02:58

2 Answers2

3

First, start by having the JavDocs for DateTimeFormatter at hand, this is going to really help determine which specifiers you need

The first thing to do is parse the text into a ZonedDateTime, LocalDateTime won't parse a input value with a time zone (AFAIK), you "might" be able to force it, but what's the point?

String text = "2022-03-23 21:06:29.4933333 +00:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSSS z");
ZonedDateTime zdt = ZonedDateTime.parse(text, formatter);
System.out.println(zdt);

This prints...

2022-03-23T21:06:29.493333300Z

Now you could use ZonedDateTime#toLocalDateTime, but this won't take into account the current time zone of the user/computer.

If you need to convert the ZonedDateTime to LocalDateTime, it's best to do so in away which will translate the time (and date if required) to best represent the time within the current time zone (okay, I was confused typing it)

For example, converting the input value into my current time zone (+11 hours) would look like this...

ZoneId currentZone = ZoneId.systemDefault();
ZonedDateTime currentZDT = zdt.withZoneSameInstant(currentZone);
System.out.println(currentZDT);
LocalDateTime ldt = currentZDT.toLocalDateTime();
System.out.println(ldt);

which will print...

2022-03-24T08:06:29.493333300+11:00[Australia/Melbourne]
2022-03-24T08:06:29.493333300

This means that at 9:06pm on the 23rd March in Grinch (GMT), it was 8:06am on the 24th March where I live.

Now you can use different ZoneIds to convert to a TimeZone which is not the current computers TimeZone, but I'll leave that up to you to experiment with (for example, I used Convert ZonedDateTime to LocalDateTime at time zone to base my example on)

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Since the string contains an offset, `+00:00`, and no time zone like Australia/Melbourne, prefer `OffsetDateTime` over `ZonedDateTime`. Otherwise a fine answer. – Ole V.V. Mar 25 '22 at 19:22
1

You need create custom DateTimeFormatter:

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;

public class Main {
    public static void main(String args[]){
        String dateString = "2022-03-23 21:06:29.4933333 +00:00";

        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
                .appendLiteral(' ')
                .append(java.time.format.DateTimeFormatter.ISO_LOCAL_TIME)
                .appendLiteral(' ')
                .appendOffsetId()
                .toFormatter();

        //In case of OffSet matter, retaining the instant
        LocalDateTime localDateTimeSavePointOfTime = OffsetDateTime.parse(dateString, formatter).withOffsetSameInstant(OffsetDateTime.now().getOffset()).toLocalDateTime();

        //In case OffSet does not matter we can skip it
        LocalDateTime localDateTimeSkipOffSet = LocalDateTime.parse(dateString, formatter);

    }
}
Eugene
  • 5,269
  • 2
  • 14
  • 22
  • 1
    Interesting, except the result isn't converted into the current systems `TimeZone`, I don't know if that's important or not, but I'm picky about date/time manipulation – MadProgrammer Mar 23 '22 at 23:59
  • 1
    `LocalDateTime` is the wrong class for the given input. That input includes an offset. The offset is vital information which you discard by using `LocalDateTime`. – Basil Bourque Mar 24 '22 at 02:56
  • Described two cases, when OffSet matters or not – Eugene Mar 24 '22 at 12:14
  • 1
    A very fine demonstration of building a custom formatter from built-in parts (I don’t think you need `parseCaseInsensitive()`). – Ole V.V. Mar 25 '22 at 19:23
  • Agreed, in this particular case parseCaseInsensitive() is useless. – Eugene Mar 25 '22 at 19:47