jeudi 16 mars 2023

[Java 11] Gestion de plusieurs formats de date en Java avec DateTimeFormatterBuilder

Introduction

Lorsqu’on travaille avec des dates en Java, il est souvent nécessaire de gérer plusieurs formats de date différents. Cela peut être dû au fait que les utilisateurs peuvent entrer des dates dans différents formats, ou que les données sont fournies par des sources externes dans des formats variés. Sans une gestion appropriée de ces formats, il peut être difficile de manipuler les dates correctement et cela peut entraîner des erreurs dans l’application.

Problème

La gestion de plusieurs formats de date en Java est un défi courant lors de la manipulation des dates. Les développeurs sont souvent confrontés à des problèmes lorsqu’ils doivent convertir des chaînes de caractères en dates, ou vice versa, en raison de la diversité des formats de date.

Solution

Heureusement, Java offre des fonctionnalités avancées pour gérer les dates, notamment la classe LocalDate qui permet de représenter une date sans tenir compte du fuseau horaire et de l’heure. Java 8 a également introduit une API Date/Time qui offre des fonctionnalités supplémentaires pour la manipulation des dates et heures, y compris la gestion de plusieurs formats de date différents.

Les développeurs peuvent utiliser des outils tels que DateTimeFormatter et DateTimeFormatterBuilder pour analyser et formater les dates dans différents formats. Ces outils permettent également de définir des modèles de formatage personnalisés et de gérer les erreurs liées à la conversion de dates.

Voici un exemple concret d’utilisation du DateTimeFormatter et du DateTimeFormatterBuilder pour gérer plusieurs formats de date :

package org.example;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Locale;

public class DateParser {

    private static final String[] SUPPORTED_FORMATS = {
            "dd/MM/yyyy",
            "dd-MM-yyyy",
            "yyyy/MM/dd",
            "yyyy-MM-dd"
    };

    public static LocalDate parseDate(String dateString) throws DateTimeParseException {
        DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
        Arrays.stream(SUPPORTED_FORMATS).forEach(f ->
                builder.appendOptional(DateTimeFormatter.ofPattern(f))
        );

        DateTimeFormatter formatter = builder.toFormatter(Locale.ENGLISH);
        return LocalDate.parse(dateString, formatter);
    }
}

Et voici comment formater une date dans un format spécifique :

public static String formatDate(LocalDate date, String pattern) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
    return date.format(formatter);
}

Enfin, voici comment combiner ces deux méthodes pour convertir une date d’un format à un autre :

public static String formatDate(String dateString, String pattern) throws DateTimeParseException {
    LocalDate date = null;
    for (String format : SUPPORTED_FORMATS) {
        try {
            date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern(format));
            break;
        } catch (DateTimeParseException e) {
            // Le format ne correspond pas, on essaye avec le suivant
        }
    }
    if (date == null) {
        throw new DateTimeParseException("Aucun format supporté pour la date fournie", dateString, -1);
    }

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
    return date.format(formatter);
}

Discussion

Ces exemples montrent comment Java peut être utilisé pour gérer efficacement plusieurs formats de date. En comprenant ces concepts et en utilisant les outils appropriés, les développeurs peuvent éviter les erreurs courantes liées à la manipulation des dates en Java.

Pour s’assurer que notre code fonctionne comme prévu, il est important d’écrire des tests unitaires. Voici quelques tests que vous pouvez utiliser pour tester le code ci-dessus :

package org.example;

import static org.junit.jupiter.api.Assertions.*;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Collection;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

public class DateParserTest {

    private DateParser dateParser;

    @BeforeEach
    void setUp() {
        dateParser = new DateParser();
    }

    @ParameterizedTest(name = "{index} - Parsing {0} should return {1}")
    @MethodSource("dateStrings")
    void testParseDate(String dateString, LocalDate expectedDate) {
        assertEquals(expectedDate, dateParser.parseDate(dateString));
    }

    @ParameterizedTest(name = "{index} - Parsing invalid date string {0} should throw DateTimeParseException")
    @MethodSource("invalidDateStrings")
    void testParseDateThrowsDateTimeParseException(String dateString) {
        assertThrows(DateTimeParseException.class, () -> dateParser.parseDate(dateString));
    }

    static Collection<Object[]> dateStrings() {
        return Arrays.asList(new Object[][] {
                { "10/03/2022", LocalDate.of(2022, 3, 10) },
                { "10-03-2022", LocalDate.of(2022, 3, 10) },
                { "2022/03/10", LocalDate.of(2022, 3, 10) },
                { "2022-03-10", LocalDate.of(2022, 3, 10) },
                { "31/12/2023", LocalDate.of(2023, 12, 31) },
                { "31-12-2023", LocalDate.of(2023, 12, 31) },
                { "2023/12/31", LocalDate.of(2023, 12, 31) },
                { "2023-12-31", LocalDate.of(2023, 12, 31) }
        });
    }

    static Collection<String> invalidDateStrings() {
        return Arrays.asList(new String[] {
                "10/13/2022", // invalid month
                "02/29/2021", // not a leap year
                "2022/31/10", // invalid day
                "10-03-22", // 2-digit year
                "invalid", // not a date string
                "2022/03/10 10:00:00" // not a date string
        });
    }

}

Ces tests vérifient que la méthode parseDate peut analyser correctement une date dans différents formats et qu’elle lance une exception DateTimeParseException lorsqu’elle reçoit une chaîne de caractères qui ne correspond à aucun format de date supporté. Ces tests aident à s’assurer que notre code est robuste et qu’il se comporte comme prévu dans différentes situations. Ils sont un élément essentiel pour garantir la qualité du code et éviter les erreurs inattendues. En utilisant ces tests comme guide, les développeurs peuvent être plus confiants dans la robustesse de leur code et dans sa capacité à gérer correctement plusieurs formats de date.

Aucun commentaire:

Enregistrer un commentaire

to criticize, to improve