Skip to content

API Date

Introduction aux dates et heures

Maintenant que nous avons introduit les aéroports et leurs fuseaux horaires, il est temps de nous concentrer sur un aspect crucial des voyages : les dates et les heures. Nous allons utiliser l'API java.time pour cela.

API java.time

L'API java.time comporte 5 implémentations importantes :

  • LocalDate: Représente une date sans heure ni fuseau horaire (par exemple, 2023-12-15).
  • LocalTime: Représente une heure sans date ni fuseau horaire (par exemple, 10:15:30).
  • LocalDateTime: Combine LocalDate et LocalTime, représentant une date et une heure sans fuseau horaire.
  • ZonedDateTime: Comme LocalDateTime, mais avec la prise en charge des fuseaux horaires.
  • Instant: Représente un moment précis sur la timeline UTC.
  • Period, Duration : Représente des intervalles dans le temps.

Exemples d'utilisation :

LocalTime uneHeure = LocalTime.of(14, 30); // 14h30
LocalDateTime dateEtHeure = LocalDateTime.of(2023, Month.JULY, 15, 14, 30); // 15 juillet 2023, 14h30
ZonedDateTime dateHeureZone = ZonedDateTime.of(2023, 7, 15, 14, 30, 0, 0, ZoneId.of("Europe/Paris")); // 15 juillet 2023, 14h30, heure de Paris
Instant instant = Instant.now(); // Capture le moment courant en UTC
Period period = Period.between(dateEtHeure.toLocalDate(), dateHeureZone.toLocalDate());
Duration duration = Duration.between(instant, instant);

Period vs Duration

Period : utilise les unités année, mois et jour pour représenter une période de temps (prend des LocalDate en paramètre).

Duration : représente un intervalle de temps en secondes ou en nanosecondes et convient mieux pour traiter les cas qui requièrent plus de précision (prend des Instant en paramètre).

Intégration des dates du voyage

À vous de jouer

  • Ajoutez un attribut departure et arrival dans la classe Travel pour gérer les dates de départ et d'arrivée ainsi que les heures. Vous utiliserez un Instant.
  • Ajoutez dans le constructeur une levée d'exception si la date de départ est postérieure à la date d'arrivée. Vous pourrez utiliser une IllegalArgumentException avec un message indiquant que la date de départ est après la date d'arrivée.

Pourquoi un Instant plutôt qu'un ZonedDateTime ?

On privilégie l'utilisation d'Instant plutôt que ZonedDateTime car les dates/heures dépendent des fuseaux horaires, qui varient selon les régions du monde.

Ainsi, il est plus judicieux de convertir l'Instant en date/heure dans le frontend, permettant d'afficher la date et l'heure selon le fuseau horaire de chaque utilisateur. (Dans notre cas, nous ferons la conversion dans notre vue, au niveau du DTO).

DTO de sortie

Les DTO (Data Transfer Object) représentent notre modèle tel qu'il est exposé à l'extérieur. Ils permettent de contrôler les objets entrants et sortants de notre application, on parle donc de request DTO et de response DTO. Par souci de simplicité, on se focalisera uniquement sur les DTO de sortie dans notre application.

Les DTO de sortie représentent ce qui est exposé à l'extérieur (par exemple au frontend). On n'envoie pas directement le modèle, car il pourrait contenir des informations sensibles ou inutiles. Dans une application web complète, on ajouterait des controllers à nos DTO pour qu'ils puissent être transmis à notre frontend via le protocole HTTP.

Diagramme d'architecture

En fait, jusqu'à présent, nous vous avions demandé de créer des classes, mais depuis Java 17, il est possible de concevoir des classes immuables avec moins de code boilerplate avec les records.

Record

Avec les records, il n'est plus nécessaire de créer les méthodes equals(), hashCode() et toString(), ainsi que les constructeurs et les accesseurs.

Exemple

Notre classe User aurait pu être définie comme suit :

public record User(long id, 
                   String firstName, 
                   String lastName, 
                   String contact) {}

C'est l'occasion d'utiliser les records pour nos DTO.

Création du DTO de sortie Travel

À vous de jouer

  • Créez un fichier TravelResponseDto qui correspondra à une représentation du modèle Travel contenant seulement les informations à exposer (pour les dates en renverra des ZonedDateTime).

Création d'un mapper pour convertir les modèles en DTO

Maintenant que nous avons nos DTO, il faut pouvoir convertir nos classes dans leur DTO correspondants. Nous allons créer des méthodes permettant de faire cela.

Une première stratégie serait de créer des classes avec des méthodes de mapping public et static à l'intérieur.

Exemple
public class Main {
    public static void main(String[] args) {
        // Utilisation de la méthode statique sans instance de la classe
        int result = MathUtils.add(5, 3);
    }

    public static class MathUtils {
        public static int add(int a, int b) {
            return a + b;
        }
    }
}

À vous de jouer

  • Créez une classe TravelDtoMapper avec une méthode fromTravel pour convertir le modèle Travel dans son DTO de sortie.
    • La méthode fromTravel devra gérer la conversion d'Instant en date / heure exprimée dans le fuseau hoaire de l'aéroport de départ et d'arrivée. Utilisez l'AirportManager créé dans la partie précédente pour lier l'aéroport à son fuseau horaire.

Optionnel

Calcul de durée et gestion des retards

À vous de jouer

Faites les modifications suivantes dans la classe TravelService :

  • Créez une méthode computeTravelDuration qui calcule la durée totale du voyage ( méthode de la librairieDuration ).

  • Créez une méthode qui permet de modifier les dates des vols en cas de retard. La méthode prendra en paramètre un objet Travel et un delay qui correspondra à une durée de retard, par exemple 2 heures, 2 jours ou encore 1 semaine ( méthode de la librairieInstant ).

Essayez votre code dans le Main

À vous de jouer

Faites les modification suivantes dans le Main :

Jérôme s'inscrit à un voyage entre Paris et Tokyo du 26/04/2023, l'avion décolle à 12h10 et arrive le 27/04/2023 à 06h36.

  • Vérifiez que la méthode computeTravelDuration retourne bien 11 heures et 26 minutes.
  • Ajoutez un retard de 5h à la date de départ et assurez-vous que cela fonctionne en affichant la date de départ dans le bon fuseau horaire.
Date formatter
// Création de l'objet LocalDateTime pour la date et l'heure spécifiées
LocalDateTime dateTime = LocalDateTime.of(2024, Month.DECEMBER, 21, 12, 30);

// Conversion en Instant
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();

// Convertir Instant en LocalDateTime
LocalDateTime newLocalDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

Récapitulatif

Félicitations ! Vous avez maintenant intégré la gestion des dates et des heures dans votre application. Vous êtes dorénavant prêt à gérer des voyages dans différents fuseaux horaires et à effectuer des opérations complexes sur les dates.

Check

.
└── model
│   ├── Travel.java
│   └── responsedto
│       └── TravelResponseDto.java
├── mapper
│   └── TravelDtoMapper.java
└── Main.java

N'oubliez pas de commit votre travail !