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