2

I am struggling with this .. I have an input string - like this: 2021-10-13 11:33:16.000-04

Using Java.

I need to get a Date object from it. which formatting pattern can I use ?

I try with these

SimpleDateFormat inFormatter = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss.SSS'-'ZZ");

and

SimpleDateFormat inFormatter = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss.SSSZZ");

and I keep getting

java.text.ParseException: Unparseable date: "2021-10-13 11:33:16.000-04"
  at java.base/java.text.DateFormat.parse(DateFormat.java:396)
  at com.dima.tests.DatesConversions.main(DatesConversions.java:24)

Please, help !!

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
Dmitriy Ryabin
  • 363
  • 3
  • 16
  • I recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use `OffsetDateTime` and `DateTimeFormatter`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Oct 14 '21 at 16:46
  • 1
    I am doing a middle man module. I am dealing with input into my service, and output to another service. Those were designed already, and not by me – Dmitriy Ryabin Oct 14 '21 at 16:49

3 Answers3

2

Don't use Date as it is outdated. Use the classes in the java.time

OffsetDateTime odt = OffsetDateTime.parse(str, 
    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSX"));       
System.out.println(odt);

Prints

2021-10-13T11:33:16-04:00

WJS
  • 36,363
  • 4
  • 24
  • 39
2

java.time

Even though you need to give an old-fashionede Date object to a legacy API beyond your control, I still recommend that you use java.time, the modern Java date and time API, in your own code. The final conversion to Date is pretty straight-forward.

I’d use this formatter for maximum reuse of existing formatters:

private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
        .append(DateTimeFormatter.ISO_LOCAL_DATE)
        .appendLiteral(' ')
        .append(DateTimeFormatter.ISO_LOCAL_TIME)
        .appendOffset("+HHmm", "+00")
        .toFormatter(Locale.ROOT);

Then we parse and convert like this:

    String input = "2021-10-13 11:33:16.000-04";
    OffsetDateTime dateTime = OffsetDateTime.parse(input, PARSER);
    System.out.println(dateTime);
    
    Instant i = dateTime.toInstant();
    Date oldfashionedDate = Date.from(i);
    System.out.println(oldfashionedDate);

Output in my time zone, Europe/Copenhagen:

2021-10-13T11:33:16-04:00
Wed Oct 13 17:33:16 CEST 2021

Denmark is at offset +02:00 at this time of year, so 6 hours ahead of the UTC offset -04 from your string. Therefore Date.toString() confusingly prints a clock hour that is 6 hours ahead of the original time of day.

Note: if your forward service accepts anything else than an old-fashioned Date, you should not be using that class. For example, if a String is required, the OffsetDateTime that we got can be formatted into a new string using a second DateTimeFormatter (or in lucky cases, its toString method).

What went wrong in your code?

First, a UTC offset can have positive or negative sign. Instead of -04 you could have had for example +09. Formatters are designed for to take the sign, + or -, as part of the offset. Therefore hardcoding the minus sign as a literal, as in your first attempt, is bound to fail. In your second attempt, yyyy-MM-dd HH:mm:ss.SSSZZ, you are already closer. However, ZZ is for an offset with sign and four digits (like +0530 or -0400; hour and minute), so does not work for a two-digit offset like -04. Your SimpleDateFormat expected more digits where your string ended and therefore threw the exception that you saw.

Link

Oracle tutorial: Date Time explaining how to use java.time.

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

Since you are using ISO 8601 time zone timezone, you have the use the below pattern.

SimpleDateFormat inFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSX");

And then, to get the date:

Date date = inFormatter.parse("2021-10-13 11:33:16.000-04");

Always check the documentation.

HelloWorld123456789
  • 5,299
  • 3
  • 23
  • 33