2

I need a different format of strings to convert to "DD.MM.YYYY".

"Thu, 3 Nov 2022 06:00:00 +0100" has to be changed to "03.11.2022"

and

"01.11.2022 20:00:00" to "01.11.2022".

All the formats are in String.

I tried doing

String pattern="DD.MM.YYYY";
DateTimeFormatter formatter=DateTimeFormatter.ofPattern(pattern);

new SimpleDateFormat(pattern).parse("01.11.2022 20:00:00")

I have also tried doing the following

java.time.LocalDateTime.parse(
        item.getStartdatum(),
        DateTimeFormatter.ofPattern( "DDMMYYYY" )
    ).format(
        DateTimeFormatter.ofPattern("DD.MM.YYYY")
    )

But got the error :

Exception in thread "main" java.time.format.DateTimeParseException:
Text 'Sun, 30 Oct 2022 00:30:00 +0200' could not be parsed at index 0

I tried doing the following as well

String pattern="DD.MM.YYYY";
DateFormat format = new SimpleDateFormat(pattern);
Date date = format.parse(01.11.2022 20:00:00);

However, I am not getting the correct output. How can I get my desired result?

catch23
  • 17,519
  • 42
  • 144
  • 217
Jeet
  • 359
  • 1
  • 6
  • 24
  • 1
    starting with the pattern, from the [documentation](https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/time/format/DateTimeFormatter.html) of `DateTimeFormatter` : "D | day-of-year" - probably not what you want – user16320675 Nov 04 '22 at 15:14
  • The former example can be parsed using `OffsetDateTime.parse("Thu, 3 Nov 2022 06:00:00 +0100", DateTimeFormatter.RFC_1123_DATE_TIME)`. You may combine this with one of the answers. – Ole V.V. Nov 05 '22 at 08:20
  • 1
    I strongly recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Use classes from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/) (`LocalDateTime` and `DateTimeFormatter` are from there). – Ole V.V. Nov 05 '22 at 08:23
  • 1
    Do I understand correctly that `01.11.2022 20:00:00` means 1 November (not January 11)? – Ole V.V. Nov 05 '22 at 08:48

2 Answers2

5

Several things…

  • if you can use java.time, use it exclusively if possible (no SimpleDateFormat or similar legacy stuff)
  • a DateTimeFormatter can be used to parse and format Strings representing a datetime, if input and output format are different, you will need two different DateTimeFormatters
  • the Text 'Sun, 30 Oct 2022 00:30:00 +0200' could not be parsed at index 0 due to your try to parse it with the pattern "DD.MM.YYYY", which is wrong on several levels:
    • the pattern seems to expect the String to start with a numerical representation of the day of month, but it starts with Thu, an abbreviation of the name of a day of week
    • the symbol D means day of year, a number between 1 and 366 (in leap years, 365 otherwise)
    • the symbol Y means week-based year

Read more about those symbols in the JavaDocs of DateTimeFormatter

You could do the following instead:

public static void main(String[] args) {
    // two example inputs
    String first = "Thu, 3 Nov 2022 06:00:00 +0100";
    String second = "01.11.2022 20:00:00";
    // prepare a formatter for each pattern in order to parse the Strings
    DateTimeFormatter dtfInFirst = DateTimeFormatter.ofPattern(
                                        "EEE, d MMM uuuu HH:mm:ss x",
                                        Locale.ENGLISH
                                   );
    // (second one does not have an offset from UTC, so the resulting class is different)
    DateTimeFormatter dtfInSecond = DateTimeFormatter.ofPattern("dd.MM.uuuu HH:mm:ss");
    // parse the Strings using the formatters
    OffsetDateTime odt = OffsetDateTime.parse(first, dtfInFirst);
    LocalDateTime ldt = LocalDateTime.parse(second, dtfInSecond);
    // prepare a formatter, this time for output formatting
    DateTimeFormatter dtfDateOnlySeparatedByDots = DateTimeFormatter.ofPattern("dd.MM.uuuu");
    // extract the date part of each result of the parsing
    LocalDate firstResult = odt.toLocalDate();
    LocalDate secondResult = ldt.toLocalDate();
    // and print it formatted using the output formatter
    System.out.println(first + " ---> "
                             + firstResult.format(dtfDateOnlySeparatedByDots));
    System.out.println(second + " ---> " 
                              + secondResult.format(dtfDateOnlySeparatedByDots));
}

Which will output the conversion results as follows:

Thu, 3 Nov 2022 06:00:00 +0100 ---> 03.11.2022
01.11.2022 20:00:00 ---> 01.11.2022

The first formatter will need a Locale because of the presence of names (day of week & month). You cannot parse that using any exclusively numerical parser and the language / culture must match.<


short version

public static void main(String[] args) {
    // two example inputs
    String first = "Thu, 3 Nov 2022 06:00:00 +0100";
    String second = "01.11.2022 20:00:00";
    // prepare a custom formatter for the second pattern
    DateTimeFormatter dtfInSecond = DateTimeFormatter
                                        .ofPattern("dd.MM.uuuu HH:mm:ss");
    // parse the first String by means of a built-in RFC formatter
    OffsetDateTime odt = OffsetDateTime.parse(
                                first,
                                DateTimeFormatter.RFC_1123_DATE_TIME);
    // parse the second String using the custom formatter
    LocalDateTime ldt = LocalDateTime.parse(second, dtfInSecond);
    // prepare a formatter, this time for output formatting
    DateTimeFormatter dtfDateOnlySeparatedByDots = DateTimeFormatter
                                                        .ofPattern("dd.MM.uuuu");
    // and print it formatted using the output formatter
    System.out.println(first + " ---> "
                             + odt.format(dtfDateOnlySeparatedByDots));
    System.out.println(second + " ---> " 
                              + ldt.format(dtfDateOnlySeparatedByDots));
}

HINT:

For dates like the one mentioned in your comment…

Text '9.28.2022 6:30:00' could not be parsed at index 0

you will have to use a pattern with single-digit day of month and hour of day, probably even month of year if anything like 9.8.2022 is possible. However, you will definitely need to switch day of month and month of year because there is just no month no. 28 in a year.

Short example:

String third = "9.28.2022 6:30:00";
DateTimeFormatter dtfInThird = DateTimeFormatter
                                    .ofPattern("M.d.uuuu H:mm:ss");
LocalDateTime ldtThird = LocalDateTime.parse(third, dtfInThird);
System.out.println(third + " ---> " 
                         + ldtThird.format(dtfDateOnlySeparatedByDots));

Executed in a main, this will output

9.28.2022 6:30:00 ---> 28.09.2022
deHaar
  • 17,687
  • 10
  • 38
  • 51
  • Text '9.28.2022 6:30:00' could not be parsed at index 0 ---error is due to the single digit day and hour? – Jeet Nov 04 '22 at 18:58
  • You will need another `DateTimeFormatter` for datetimes like that. Yes, the single digit day and hour are a problem, but this has a different order, month of year is first and day of month second. None of the provided examples were like that. – deHaar Nov 04 '22 at 19:42
  • Good answer detailing out the issues. For `dtfInFirst` I recommend you use the built-in `DateTimeFormatter.RFC_1123_DATE_TIME`. Also you need not extract the date parts before formatting. You can directly do `odt.format(dtfDateOnlySeparatedByDots)` and similarly for `ldt`. – Ole V.V. Nov 05 '22 at 08:34
  • @Jeet see my edit concerning your `Text '9.28.2022 6:30:00' could not be parsed at index 0`… – deHaar Nov 07 '22 at 08:27
  • 1
    @OleV.V. Thanks for the suggestions, the *long* version was put there on purpose. I wanted to point out the different steps needed, but it is definitely worth mentioning the short way. – deHaar Nov 07 '22 at 15:05
5

The java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.

deHaar has already written a good answer. However, if you want to use a single DateTimeFormatter, you can check this answer.

For parsing, you can build a DateTimeFormatter with optional patterns and default time-zone offset value (since you do not have time-zone offset in the second date-time string) as follows:

DateTimeFormatter parser = new DateTimeFormatterBuilder()
    .appendPattern("[d.M.uuuu H:m:s][EEE, d MMM uuuu H:m:s X]")
    .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
    .toFormatter(Locale.ENGLISH);

where the optional patterns are in square brackets. Alternatively, you can use DateTimeFormatterBuilder#optionalStart and DateTimeFormatterBuilder#optionalEnd to specify optional patterns.

With this parser, you can parse the given date-time strings to OffsetDateTime and format it to the desired string using the following DateTimeFormatter:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.uuuu", Locale.ENGLISH);

Demo:

public class Main {
  public static void main(String[] args) {
    DateTimeFormatter parser = new DateTimeFormatterBuilder()
        .appendPattern("[d.M.uuuu H:m:s][EEE, d MMM uuuu H:m:s X]")
        .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
        .toFormatter(Locale.ENGLISH);

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.uuuu", Locale.ENGLISH);

    // Test
    Stream.of(
          "Thu, 3 Nov 2022 06:00:00 +0100",
          "01.11.2022 20:00:00"
        )
        .map(s -> OffsetDateTime.parse(s, parser).format(formatter).toString())
        .forEach(System.out::println);
    ;
  }
}

Output:

03.11.2022
01.11.2022

Note

  1. Make sure to check the DateTimeFormatter documentation to understand the difference between Y and y and between D and d.
  2. You can use y instead of u but I prefer u to y with DateTimeFormatter.
  3. Learn more about the modern Date-Time API from Trail: Date Time.
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • Why is it throwing error if the String given as "9.28.2022 6:30:00", I mean single digit day or hour? The error I got is :- Text '9.28.2022 6:30:00' could not be parsed at index 0 – Jeet Nov 04 '22 at 18:57
  • 1
    @Jeet - You can use a single letter to parse one or multiple digits. I've updated the answer accordingly. Let me know in case you still face any issues. – Arvind Kumar Avinash Nov 04 '22 at 21:49