0

I'm are using Java 1.6. Now, we are having different values of date for 12 months which are being rendered as below

sam. 26 janv. 2019 
mer. 28 févr. 2018
jeu. 15 mars 2018
mer. 11 avr. 2018
mar. 15 mai 2018
mer. 20 juin 2018
mer. 20 jul 2018
mer. 22 août 2018
mer. 12 sept. 2018
mer. 24 oct. 2018
Ven. 23 nov. 2018
Dim. 16 déc. 2018

Need to deal with different formats of date. I need some generic method to achieve common format as sam. 20 sept, 2017 ?

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Are you sure that’s “jul”? “juil.” would be more standard as far as I can tell (no native French speaker). Also July 20, 2018 will be a Friday, not a Wednesday. – Ole V.V. Feb 16 '18 at 13:05

2 Answers2

1
    DateTimeFormatter frenchDateFormatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("EEE")
            .parseCaseSensitive()
            .appendPattern(" d MMM uuuu")
            .toFormatter(Locale.FRENCH)
            .withResolverFields(ChronoField.DAY_OF_MONTH,
                    ChronoField.MONTH_OF_YEAR, ChronoField.YEAR);
    for (String dateString : dates) {
        dateString = dateString.replace("jul", "juil.");
        String formattedDate = LocalDate.parse(dateString, frenchDateFormatter)
                .format(frenchDateFormatter);
        System.out.println(formattedDate);
    }

Given your 12 strings from the question this prints

sam. 26 janv. 2019
mer. 28 févr. 2018
jeu. 15 mars 2018
mer. 11 avr. 2018
mar. 15 mai 2018
mer. 20 juin 2018
ven. 20 juil. 2018
mer. 22 août 2018
mer. 12 sept. 2018
mer. 24 oct. 2018
ven. 23 nov. 2018
dim. 16 déc. 2018

Most of your date strings are already in a pretty standard format that would be recognized with a format pattern of EEE d MMM uuuu and French locale. The exceptions are:

  • There are two problems with mer. 20 jul 2018: July 20, 2018 will be a Friday (vendredi, ven.), not a Wednesday (mercredi, mer.). And the abbreviation for juillet (July) is juil., not jul (you may want to check once more whether this string is really the one you’ve got).
  • The days of the week begin with a lowercase letter in French, where you have an uppercase letter in the last two strings (Ven. and Dim.).

To solve those problems:

  • Use the formatter’s withResolverFields() to tell it which fields to use for determining the date; in particular, do not include day-of-week so that the formatter will tolerate wrong day-of-week while parsing.
  • Use dateString.replace() to fix the incorrect month abbreviation for July (I consider this a hack; there’s a better solution below).
  • Use a DateTimeFormatterBuilder and its parseCaseInsensitive method to build a formatter that ignores the case of day-of-week, so that the uppercase letters in Ven. and Dim. are accepted (alternatively use String.toLowercase(Locale.FRENCH) before parsing).

Edit: The gold-plated solution to parsing jul rather than juil. as a month name is telling the formatter all the month names we use:

    Map<Long, String> monthMap = new HashMap<>();
    // first put all the French month abbreviations into the map
    for (Month m : Month.values()) {
        monthMap.put(Long.valueOf(m.getValue()), m.getDisplayName(TextStyle.SHORT, Locale.FRENCH));
    }
    // finally overwrite the value for July with the one we get in our input strings
    monthMap.put(Long.valueOf(Month.JULY.getValue()), "jul");

    DateTimeFormatter frenchDateFormatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("EEE")
            .parseCaseSensitive()
            .appendPattern(" d ")
            .appendText(ChronoField.MONTH_OF_YEAR, monthMap)
            .appendPattern(" uuuu")
            .toFormatter(Locale.FRENCH)
            .withResolverFields(ChronoField.DAY_OF_MONTH,
                    ChronoField.MONTH_OF_YEAR, ChronoField.YEAR);

DateTimeFormatterBuilder.appendText() comes in an overloaded version that accepts a map of texts to print and parse. So we build such a map and pass it to the formatter builder. Since it’s a map from value to text, there can only be one text for each value, so the above will only accept jul (not juil.). But now your string mer. 20 jul 2018 can be parsed directly by the formatter, we no longer need to fix it first. On the other hand, if you want the more standard juil. in your output, you need to use a separate formatter for formatting: DateTimeFormatter.ofPattern("EEE d MMM uuuu", Locale.FRENCH).

I am using and recommending the modern Java date and time API known as java.time or JSR-310.

But I said I am using Java 1.6

No problem, using java.time with Java 6 works nicely.

  • In Java 8 and later and on newer Android devices the modern API comes built-in.
  • In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links below) and add it to your project.
  • On older Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

Links

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

You should use SimpleDateFormat

for example:

Date date = (new SimpleDateFormat("MMM dd yyyy HH:mm:ss", Locale.US)).parse(str);
Dsenese1
  • 1,106
  • 10
  • 18
  • Even in Java 6 I recommend you avoid the notoriously troublesome `SimpleDateFormat`. Rather consider adding [ThreeTen Backport](http://www.threeten.org/threetenbp/) to your project. This allows you to use [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/) in Java 6 and 7. It’s so much nicer to work with. Use its `DateTimeFormatter`. – Ole V.V. Feb 16 '18 at 12:54
  • 1
    Your code certainly won’t parse any of the strings in the question. – Ole V.V. Feb 16 '18 at 17:52