1

I receive a datetime with timezone as a String and want to format as a LocalDateTime to save it in Postgre as a field timestamptz but Java can't format it. I mean I want to save in the same format as i have received.

I have tried to format it with DateTimeFormatter but it throw DateTimeParseException.

This is string received: 2019-09-02T11:47:50.877+0200 and trying to format like this:

String datetimeString = "2019-09-02T11:47:50.877+0200";
String pattern = "yyyy-MM-dd\'T\'HH:mm:ss.SSS Z";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);

 LocalDateTime created = (LocalDateTime.from(formatter.parse(datetimeString )));

I expect this: 2019-09-02T11:47:50.877+0200 but it throw an exception. java.time.format.DateTimeParseException: Text '2019-09-02T11:47:50.877+0200' could not be parsed at index 23

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
kamboj
  • 411
  • 1
  • 9
  • 18
  • I think your string is not 100% correct. Check [ISO_OFFSET_DATE_TIME](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_OFFSET_DATE_TIME) format, should have `:` in the last portion `+HH:mm` – grog Sep 02 '19 at 10:17
  • Possible duplicate of [Parse and retrieve timezone offset from date-time](https://stackoverflow.com/questions/48230408/parse-and-retrieve-timezone-offset-from-date-time) – Vignesh_A Sep 02 '19 at 10:28
  • Possible duplicate of [Convert date into AEST using java](https://stackoverflow.com/questions/48412345/convert-date-into-aest-using-java). – Ole V.V. Sep 02 '19 at 11:17
  • @grog The variant without colon in the offset is pretty frequently seen too, Unfortunately you are right, `DateTimeFormatter.ISO_OFFSET_DATE_TIME` doesn’t parse it, so we need to build a custom formatter for it. – Ole V.V. Sep 02 '19 at 11:19
  • @OleV.V. true, but is +HHmm a valid ISO format or simply a commonly used non-ISO format? Because if not, then it might be worth it to follow the standard, adding the missing : instead of working around the issue Nevermind, looks like it is valid: https://en.wikipedia.org/wiki/ISO_8601 section Time zone designators – grog Sep 03 '19 at 13:30
  • @grog *The offset from UTC is appended to the time … in the form ±[hh]:[mm], ±[hh][mm], or ±[hh].* [from Wikipedia](https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC) So the form with no colon is ISO compliant too. – Ole V.V. Sep 03 '19 at 13:35

3 Answers3

3

Read the exception message carefully

It’s a counting exercise.

java.time.format.DateTimeParseException: Text '2019-09-02T11:47:50.877+0200' could not be parsed at index 23

Index 23 is where the + (plus) is in your date time string. So right after the milliseconds. Compare this with your format pattern string:

String pattern = "yyyy-MM-dd\'T\'HH:mm:ss.SSS Z";

There’s a space after the milliseconds which isn’t in the string you are trying to parse. A space in the format pattern string means that the parser expects a space in the date time string and objects when it doesn’t find one. Remove the space, and your string is parsed into 2019-09-02T11:47:50.877.

As an aside, consider using OffsetDateTime instead of LocalDateTime. One, LocalDateTime hasn’t got much good use because it doesn’t define a point in time. Two, generally it’s best to obtain all the information we can from the date time string, and your string does include an offset. It’s easier to throw information away later (and sorry to say, based on experience it’s much too easy to invent wrong information to replace the correct information that we forgot to keep from the string, try to avoid that pitfall). Three, according to the documentation the PostgreSQL JDBC driver does require an OffsetDateTime rather than a LocalDateTime for a timestamp with timezone column. See the link below.

Related questions and other links

Using Java 8 Date and Time classes in the PostgreSQL JDBC Driver manual.

Your format is ISO 8601. There are other questions about parsing the same format (thanks to @Vignesh_A for the first link):

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • I have taken this opportunity to write [a longer answer](https://stackoverflow.com/a/57757907/5772882) to one of the linked original questions as a supplement to what I have written here. – Ole V.V. Sep 02 '19 at 13:45
  • This as very clear solution. All you have to do is use the String.replace() character and replace the + char with a special character to enable it get parsed – Chuka_FC Jun 05 '22 at 01:25
  • @Chuka_FC I recommend you do not replace the `+` character. It’s part of the UTC offset (`+0200`) and could also be a minus for offsets behind UTC, for example in the Americas. As I mentioned, I would parse that offset, both because it’s needed for defining which point in time was intended and because it’s easier to parse everything and throw any unneeded parts away than to ignore the offset at first and then later discover we had a need for it. – Ole V.V. Jun 05 '22 at 06:27
  • 1
    V.V i really appreciate the advice but in my case, I'm doing the replace in the toJson() part of my Moshi adapter and doing the reverse in the fromJson() function. That way my navigation does not crash with a datetime exception. But i will have to try testing my solution with timezones that have a negative character in them – Chuka_FC Jun 05 '22 at 08:13
0

You need to change the String pattern to "yyyy-MM-dd'T'HH:mm:ss.SSSZZ"

0

String s="2019-09-02T11:47:50.877+0200";

String client = s;
    String cttdate = "";
    char[] c = client.toCharArray();
    for (int i = 0; i < 10; i++) {      
        cttdate = cttdate + c[i];           // Getting  Client UTC Date as a String From String
    }
    int ctdate = Integer.valueOf(cttdate.replaceAll("-", "")); //Replace All Special Symbol From Client Date For Compare

    String cttime = "";
    for (int i = 11; i <= 15; i++) {
        cttime = cttime + c[i];             // Getting  Client UTC Time as a String From String
    }
    Date ctime = sdf.parse(cttime);
  • Thanks for wanting to contribute. Is `sdf` a `SimpleDateFormat`? When the modern `DateTimeFormatter` and `LocalDateTime` are asked about, IMHO suggesting the poorly designed and long outdated `Date` and `SimpleDateFormat` is leading astray and bad. – Ole V.V. Sep 02 '19 at 11:23