Pour formater une date en chaîne de caractère ou pour convertir une chaîne de caractère en date, on utilise la classe java.time.format.DateTimeFormatter
, depuis le JDK 8.
Avec les JDK précédents, on utilisait java.text.DateFormat
ou sa sous-classe java.text.SimpleDateFormat
.
DateTimeFormatter.parse()
En choisissant, et imposant, le format de saisie de date, le code de parsing est simple.
public class DateFormatUtil {
private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy")
public static TemporalAccessor parse(String dateSaisie) {
if (dateSaisie != null) {
TemporalAccessor date = formatter.parse(dateSaisie);
return date;
}
return null;
}
}
SimpleDateFormat.parse()
Dans une application, pour pouvoir faire les conversions, il est nécessaire d’imposer un format de saisie, qui correspond au pattern du SimpleDateFormat
.
public class DateFormatUtil {
private String dateFormat = "dd/MM/yyyy"
public static Date parse(String dateSaisie) throws ParseException {
if (dateSaisie != null) {
SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
Date date = formatter.parse(dateSaisie);
return date;
}
return null;
}
}
Contrairement à java.time.format.DateTimeFormatter , java.text.SimpleDateFormat n’est pas thread-safe.
C’est pourquoi je l’utilise en variable locale.
|
Multi-formats
Afin de rendre l’application plus conviviale, il faut donner une plus grande souplesse de saisie à l’utilisateur et supporter une série de patterns. Avant d’en appliquer un, il faut rechercher celui qui est adapté à la saisie, ce qui peut se faire avec des expressions régulières.
public class DateFormatUtil {
private static Map<String , DateTimeFormatter> regexToDatePattern
= Map.of(
"(\\d{1})/(\\d{1})/(\\d{2})", DateTimeFormatter.ofPattern("d/M/yy"),
"(\\d{2})/(\\d{2})/(\\d{4})", DateTimeFormatter.ofPattern("dd/MM/yyyy"),
"(\\d{2})/(\\d{2})/(\\d{2})", DateTimeFormatter.ofPattern("dd/MM/yy"),
"(\\d{1})/(\\d{2})/(\\d{2})", DateTimeFormatter.ofPattern("d/MM/yy"),
"(\\d{2})/(\\d{1})/(\\d{2})", DateTimeFormatter.ofPattern("dd/M/yy"),
"(\\d{1})/(\\d{1})/(\\d{4})", DateTimeFormatter.ofPattern("d/M/yyyy"),
"(\\d{2})/(\\d{1})/(\\d{4})", DateTimeFormatter.ofPattern("dd/M/yyyy"),
"(\\d{1})/(\\d{2})/(\\d{4})", DateTimeFormatter.ofPattern("d/MM/yyyy")
);
public static TemporalAccessor parse(String dateSaisie) throws ParseException{
if (dateSaisie != null) {
return regexToDatePattern.entrySet().stream()
.filter(entry -> dateSaisie.matches(entry.getKey()))
.findAny()
.map(entry -> entry.getValue().parse(dateSaisie))
.orElse(null);
}
return null;
}
}
Avant le JDK 8, on stockait le pattern dans la map, pour instancier un formatter à chaque besoin.
public class DateFormatUtil {
private static Map<String , String> regexToDatePattern = new HashMap<String, String>();
static {
regexToDatePattern.put("(\\d{1})/(\\d{1})/(\\d{2})", "d/M/yy");
regexToDatePattern.put("(\\d{2})/(\\d{2})/(\\d{4})", "dd/MM/yyyy");
regexToDatePattern.put("(\\d{2})/(\\d{2})/(\\d{2})", "dd/MM/yy");
regexToDatePattern.put("(\\d{1})/(\\d{2})/(\\d{2})", "d/MM/yy");
regexToDatePattern.put("(\\d{2})/(\\d{1})/(\\d{2})", "dd/M/yy");
regexToDatePattern.put("(\\d{1})/(\\d{1})/(\\d{4})", "d/M/yyyy");
regexToDatePattern.put("(\\d{2})/(\\d{1})/(\\d{4})", "dd/M/yyyy");
regexToDatePattern.put("(\\d{1})/(\\d{2})/(\\d{4})", "d/MM/yyyy");
}
public static Date parse(String dateSaisie) throws ParseException{
if (dateSaisie != null) {
for (Entry<String, String> entry : regexToDatePattern.entrySet()) {
if (dateSaisie.matches(entry.getKey())) {
SimpleDateFormat fmt = new SimpleDateFormat(entry.getValue());
Date d = fmt.parse(dateSaisie);
return d;
}
}
}
return null;
}
}