Comment manipuler les dates et heures en Java?

Java fournit plusieurs API pour travailler avec les dates et les heures. Il existe aussi une ancienne classe java.util.Date, mais nous ne l’aborderons pas ici. Vous avez besoin d’une instruction d’importation pour travailler avec les classes modernes de date et d’heure. Pour les utiliser, ajoutez ceci à votre programme :

import java.time.*; // importer les classes de temps

Jour vs. Date

En français, le mot date est utilisé pour représenter deux concepts différents. Parfois, il s’agit de la combinaison mois/jour/année lorsque quelque chose s’est produit, comme le 1er janvier 2000. Parfois, il s’agit du jour du mois, comme “La date d’aujourd’hui est le 6”.

C’est vrai; les mots jour et date sont souvent utilisés comme synonymes. Soyez attentif à cette distinction, surtout si vous vivez dans un endroit où les gens sont plus précis à ce sujet.

Création de Dates et d’Heures

Dans le monde réel, nous parlons généralement des dates et des fuseaux horaires comme si l’autre personne se trouvait près de nous. Par exemple, si vous me dites “Je t’appellerai à 11h00 mardi matin”, nous supposons que 11h00 signifie la même chose pour nous deux. Mais si je vis à New York et que vous vivez en Californie, nous devons être plus précis. La Californie a trois heures de retard sur New York car les états se trouvent dans des fuseaux horaires différents. Vous diriez plutôt : “Je t’appellerai à 11h00 EST (Heure de l’Est) mardi matin”.

Lorsque vous travaillez avec des dates et des heures, la première chose à faire est de décider de la quantité d’informations dont vous avez besoin. Quatre choix s’offrent à vous :

  • LocalDate – Contient juste une date—pas d’heure ni de fuseau horaire. Un bon exemple de LocalDate est votre anniversaire cette année. C’est votre anniversaire pendant toute la journée, quelle que soit l’heure.
  • LocalTime – Contient juste une heure—pas de date ni de fuseau horaire. Un bon exemple de LocalTime est minuit. Il est minuit à la même heure chaque jour.
  • LocalDateTime – Contient à la fois une date et une heure mais pas de fuseau horaire. Un bon exemple de LocalDateTime est “le coup de minuit du Nouvel An”. Minuit le 2 janvier n’est pas aussi spécial, ce qui rend la date relativement peu importante, et clairement une heure après minuit n’est pas aussi spéciale non plus.
  • ZonedDateTime – Contient une date, une heure et un fuseau horaire. Un bon exemple de ZonedDateTime est “une conférence téléphonique à 9h00 EST”. Si vous vivez en Californie, vous devez vous lever très tôt car l’appel est à 6h00 heure locale !

Vous obtenez des instances de date et d’heure en utilisant une méthode static :

System.out.println(LocalDate.now());
System.out.println(LocalTime.now());
System.out.println(LocalDateTime.now());
System.out.println(ZonedDateTime.now());

Chacune des quatre classes a une méthode statique appelée now(), qui donne la date et l’heure actuelles. Votre sortie dépendra de la date/heure à laquelle vous l’exécutez et de l’endroit où vous vivez. La sortie ressemblera à ceci lorsqu’elle est exécutée le 25 octobre à 9h13 :

2021-10-25
09:13:07.768
2021-10-25T09:13:07.768
2021-10-25T09:13:07.769-05:00[America/New_York]

La clé est le type d’informations dans la sortie. La première ligne contient uniquement une date et pas d’heure. La deuxième contient uniquement une heure et pas de date. L’heure affiche les heures, les minutes, les secondes et les fractions de seconde. La troisième contient à la fois une date et une heure. La sortie utilise T pour séparer la date et l’heure lors de la conversion de LocalDateTime en String. Enfin, la quatrième ajoute le décalage du fuseau horaire et le fuseau horaire. New York est à quatre fuseaux horaires de Greenwich Mean Time (GMT).

Greenwich Mean Time est un fuseau horaire en Europe qui est utilisé comme fuseau horaire zéro lors de la discussion des décalages. Vous avez peut-être également entendu parler du Temps Universel Coordonné, qui est une norme de fuseau horaire. Il est abrégé en UTC, comme compromis entre les noms anglais et français. (Ce n’est pas une faute de frappe. UTC n’est pas vraiment l’acronyme approprié dans l’une ou l’autre langue !) UTC utilise le même fuseau horaire zéro que GMT.

Essayons d’abord de déterminer à quel point ces moments sont éloignés dans le temps. Remarquez comment l’Inde a un décalage d’une demi-heure, pas d’une heure complète. Pour aborder un problème comme celui-ci, vous soustrayez le fuseau horaire de l’heure. Cela vous donne l’équivalent GMT de l’heure :

2022-06-20T06:50+05:30[Asia/Kolkata] // GMT 2022-06-20 01:20
2022-06-20T07:50-05:00[US/Eastern] // GMT 2022-06-20 12:50

N’oubliez pas que vous devez ajouter lorsque vous soustrayez un nombre négatif. Après conversion en GMT, vous pouvez voir que l’heure de l’Est américain est 11 heures et demie derrière l’heure de Kolkata.

Le décalage du fuseau horaire peut être indiqué de différentes manières : +02:00, GMT+2 et UTC+2 signifient tous la même chose. Vous pourriez voir n’importe lequel d’entre eux.

Si vous avez du mal à vous en souvenir, essayez de mémoriser un exemple où les fuseaux horaires sont séparés de quelques zones, et souvenez-vous de la direction. Aux États-Unis, la plupart des gens savent que la côte Est a trois heures d’avance sur la côte Ouest. Et la plupart des gens savent que l’Asie est en avance sur l’Europe. Évitez simplement de traverser le fuseau horaire zéro dans l’exemple que vous choisissez de mémoriser. Le calcul fonctionne de la même manière, mais ce n’est pas une aussi bonne aide-mémoire.

J’habite pas aux États-Unis

Les exemples utilisent les formats de date et d’heure américains. Souvenez-vous simplement que le mois vient avant la date. De plus, Java a tendance à utiliser une horloge de 24 heures même si les États-Unis utilisent une horloge de 12 heures avec a.m./p.m.

Maintenant que vous savez comment créer la date et l’heure actuelles, examinons d’autres dates et heures spécifiques. Pour commencer, créons simplement une date sans heure. Ces deux exemples créent la même date :

var date1 = LocalDate.of(2022, Month.JANUARY, 20);
var date2 = LocalDate.of(2022, 1, 20);

Les deux passent l’année, le mois et la date. Bien qu’il soit bon d’utiliser les constantes Month pour rendre le code plus facile à lire, vous pouvez passer directement le numéro du mois. Utilisez simplement le numéro du mois de la même manière que si vous écriviez la date dans la vie réelle.

Les signatures de méthode sont les suivantes :

public static LocalDate of(int year, int month, int dayOfMonth)
public static LocalDate of(int year, Month month, int dayOfMonth)

Jusqu’à présent, nous vous avons continuellement dit que Java compte à partir de 0. Eh bien, les mois font exception. Pour les mois dans les nouvelles méthodes de date et d’heure, Java compte à partir de 1, tout comme nous, les humains.

Lors de la création d’une heure, vous pouvez choisir le niveau de détail souhaité. Vous pouvez spécifier uniquement l’heure et les minutes, ou vous pouvez inclure le nombre de secondes. Vous pouvez même inclure des nanosecondes si vous voulez être très précis. (Une nanoseconde est un milliardième de seconde, bien que vous n’aurez probablement pas besoin d’être aussi précis.)

var time1 = LocalTime.of(6, 15); // heures et minutes
var time2 = LocalTime.of(6, 15, 30); // + secondes
var time3 = LocalTime.of(6, 15, 30, 200); // + nanosecondes

Ces trois heures sont toutes différentes mais à moins d’une minute l’une de l’autre. Les signatures de méthode sont les suivantes :

public static LocalTime of(int hour, int minute)
public static LocalTime of(int hour, int minute, int second)
public static LocalTime of(int hour, int minute, int second, int nanos)

Vous pouvez combiner des dates et des heures en un seul objet :

var dateTime1 = LocalDateTime.of(2022, Month.JANUARY, 20, 6, 15, 30);
var dateTime2 = LocalDateTime.of(date1, time1);

La première ligne de code montre comment vous pouvez spécifier toutes les informations sur le LocalDateTime dans la même ligne. La deuxième ligne de code montre comment vous pouvez créer des objets LocalDate et LocalTime séparément d’abord puis les combiner pour créer un objet LocalDateTime.

Il existe de nombreuses signatures de méthode car il y a plus de combinaisons. Les signatures de méthode suivantes utilisent des valeurs entières :

public static LocalDateTime of(int year, int month,
    int dayOfMonth, int hour, int minute)
public static LocalDateTime of(int year, int month,
    int dayOfMonth, int hour, int minute, int second)
public static LocalDateTime of(int year, int month,
    int dayOfMonth, int hour, int minute, int second, int nanos)

D’autres prennent une référence Month :

public static LocalDateTime of(int year, Month month,
    int dayOfMonth, int hour, int minute)
public static LocalDateTime of(int year, Month month,
    int dayOfMonth, int hour, int minute, int second)
public static LocalDateTime of(int year, Month month,
    int dayOfMonth, int hour, int minute, int second, int nanos)

Enfin, une prend un LocalDate et un LocalTime existants :

public static LocalDateTime of(LocalDate date, LocalTime time)

Pour créer un ZonedDateTime, nous devons d’abord obtenir le fuseau horaire souhaité. Nous utiliserons US/Eastern dans nos exemples :

var zone = ZoneId.of("US/Eastern");
var zoned1 = ZonedDateTime.of(2022, 1, 20,
    6, 15, 30, 200, zone);
var zoned2 = ZonedDateTime.of(date1, time1, zone);
var zoned3 = ZonedDateTime.of(dateTime1, zone);

Nous commençons par obtenir l’objet de fuseau horaire. Ensuite, nous utilisons l’une des trois approches pour créer le ZonedDateTime. La première passe tous les champs individuellement. Nous ne recommandons pas cette approche – il y a trop de nombres, et c’est difficile à lire. Une meilleure approche consiste à passer un objet LocalDate et un objet LocalTime, ou un objet LocalDateTime.

Bien qu’il existe d’autres façons de créer un ZonedDateTime, vous n’avez besoin de connaître que trois pour l’instant :

public static ZonedDateTime of(int year, int month,
    int dayOfMonth, int hour, int minute, int second,
    int nanos, ZoneId zone)
public static ZonedDateTime of(LocalDate date, LocalTime time,
    ZoneId zone)
public static ZonedDateTime of(LocalDateTime dateTime, ZoneId zone)

Notez qu’il n’y a pas d’option pour passer l’énumération Month. De plus, nous n’avons pas utilisé de constructeur dans aucun des exemples. Les classes de date et d’heure ont des constructeurs privés avec des méthodes statiques qui renvoient des instances. C’est ce qu’on appelle le modèle de fabrique.

Ne tombez pas dans ce piège. Vous n’êtes pas autorisé à construire directement un objet de date ou d’heure.

var d = new LocalDate(); // NE COMPILE PAS

Un autre piège est ce qui se passe lorsque vous passez des nombres invalides à of(), par exemple :

var d = LocalDate.of(2022, Month.JANUARY, 32) // DateTimeException

Vous n’avez pas besoin de connaître l’exception exacte qui est lancée, mais c’en est une claire :

java.time.DateTimeException: Invalid value for DayOfMonth
(valid values 1-28/31): 32

Manipulation des Dates et des Heures

Ajouter à une date est facile. Les classes de date et d’heure sont immuables. N’oubliez pas d’assigner les résultats de ces méthodes à une variable de référence afin qu’ils ne soient pas perdus.

12: var date = LocalDate.of(2022, Month.JANUARY, 20);
13: System.out.println(date); // 2022-01-20
14: date = date.plusDays(2);
15: System.out.println(date); // 2022-01-22
16: date = date.plusWeeks(1);
17: System.out.println(date); // 2022-01-29
18: date = date.plusMonths(1);
19: System.out.println(date); // 2022-02-28
20: date = date.plusYears(5);
21: System.out.println(date); // 2027-02-28

Ce code est agréable car il fait exactement ce à quoi il ressemble. Nous commençons par le 20 janvier 2022. À la ligne 14, nous lui ajoutons deux jours et le réassignons à notre variable de référence. À la ligne 16, nous ajoutons une semaine. Cette méthode nous permet d’écrire du code plus clair que plusDays(7). Notre date est maintenant le 29 janvier 2022. À la ligne 18, nous ajoutons un mois. Cela nous amènerait au 29 février 2022. Cependant, 2022 n’est pas une année bissextile. (2020 et 2024 sont des années bissextiles.) Java est assez intelligent pour réaliser que le 29 février 2022 n’existe pas, et il nous donne le 28 février 2022 à la place. Enfin, la ligne 20 ajoute cinq ans.

Le 29 février n’existe que dans une année bissextile. Les années bissextiles sont des années qui sont des multiples de 4 ou 400, mais pas d’autres multiples de 100. Par exemple, 2000 et 2016 sont des années bissextiles, mais 2100 ne l’est pas.

Il existe également des méthodes agréables et faciles pour remonter dans le temps. Cette fois, travaillons avec LocalDateTime :

22: var date = LocalDate.of(2024, Month.JANUARY, 20);
23: var time = LocalTime.of(5, 15);
24: var dateTime = LocalDateTime.of(date, time);
25: System.out.println(dateTime); // 2024-01-20T05:15
26: dateTime = dateTime.minusDays(1);
27: System.out.println(dateTime); // 2024-01-19T05:15
28: dateTime = dateTime.minusHours(10);
29: System.out.println(dateTime); // 2024-01-18T19:15
30: dateTime = dateTime.minusSeconds(30);
31: System.out.println(dateTime); // 2024-01-18T19:14:30

La ligne 25 imprime la date originale du 20 janvier 2024 à 5h15. La ligne 26 soustrait un jour, ce qui nous amène au 19 janvier 2024 à 5h15. La ligne 28 soustrait 10 heures, montrant que la date changera si les heures le font ajuster, et cela nous amène au 18 janvier 2024 à 19h15 (7h15 du soir). Enfin, la ligne 30 soustrait 30 secondes. Vous pouvez voir que tout d’un coup, la valeur d’affichage commence à montrer des secondes. Java est assez intelligent pour cacher les secondes et les nanosecondes lorsque nous ne les utilisons pas.

Il est courant que les méthodes de date et d’heure soient chaînées. Par exemple, sans les instructions d’impression, l’exemple précédent pourrait être réécrit comme suit :

var date = LocalDate.of(2024, Month.JANUARY, 20);
var time = LocalTime.of(5, 15);
var dateTime = LocalDateTime.of(date, time)
    .minusDays(1).minusHours(10).minusSeconds(30);

Lorsque vous avez beaucoup de manipulations à faire, ce chaînage est pratique. Il y a deux façons dont on peut vous induire en erreur. Que pensez-vous que cela imprime ?

var date = LocalDate.of(2024, Month.JANUARY, 20);
date.plusDays(10);
System.out.println(date);

Cela imprime le 20 janvier 2024. L’ajout de 10 jours était inutile car le programme a ignoré le résultat. Chaque fois que vous voyez des types immuables, faites attention à vous assurer que la valeur de retour d’un appel de méthode n’est pas ignorée. On peut également tester pour voir si vous vous souvenez de ce que chacun des objets de date et d’heure inclut. Voyez-vous ce qui ne va pas ici ?

var date = LocalDate.of(2024, Month.JANUARY, 20);
date = date.plusMinutes(1); // NE COMPILE PAS

LocalDate ne contient pas d’heure. Cela signifie que vous ne pouvez pas lui ajouter des minutes. Cela peut être délicat dans une séquence chaînée d’opérations d’addition/soustraction, alors assurez-vous de savoir quelles méthodes dans le tableau 4.6 peuvent être appelées sur quels types.

 Peut appeler sur LocalDate?Peut appeler sur LocalTime?Peut appeler sur LocalDateTime ou ZonedDateTime?
plusYears() minusYears()OuiNonOui
plusMonths() minusMonths()OuiNonOui
plusWeeks() minusWeeks()OuiNonOui
plusDays() minusDays()OuiNonOui
plusHours() minusHours()NonOuiOui
plusMinutes() minusMinutes()NonOuiOui
plusSeconds() minusSeconds()NonOuiOui
plusNanos() minusNanos()NonOuiOui

Travailler avec les Périodes

Maintenant, vous en savez assez pour faire quelque chose d’amusant avec les dates ! Notre zoo effectue des activités d’enrichissement pour les animaux pour leur donner quelque chose d’agréable à faire. Le gardien en chef a décidé de changer les jouets chaque mois. Ce système continuera pendant trois mois pour voir comment cela fonctionne.

public static void main(String[] args) {
    var start = LocalDate.of(2022, Month.JANUARY, 1);
    var end = LocalDate.of(2022, Month.MARCH, 30);
    performAnimalEnrichment(start, end);
}
private static void performAnimalEnrichment(LocalDate start, LocalDate end) {
    var upTo = start;
    while (upTo.isBefore(end)) { // vérifie si toujours avant la fin
        System.out.println("donner un nouveau jouet : " + upTo);
        upTo = upTo.plusMonths(1); // ajoute un mois
    }
}

Ce code fonctionne bien. Il ajoute un mois à la date jusqu’à ce qu’il atteigne la date de fin. Le problème est que cette méthode ne peut pas être réutilisée. Notre gardien de zoo veut essayer différents horaires pour voir lequel fonctionne le mieux.

LocalDate et LocalDateTime ont une méthode pour se convertir en valeurs longues, équivalentes au nombre de millisecondes qui se sont écoulées depuis le 1er janvier 1970, appelé l’époque. Qu’est-ce que cette date a de spécial ? C’est ce que Unix a commencé à utiliser pour les normes de date, alors Java l’a réutilisé.

Heureusement, Java a une classe Period que nous pouvons passer. Ce code fait la même chose que l’exemple précédent :

public static void main(String[] args) {
    var start = LocalDate.of(2022, Month.JANUARY, 1);
    var end = LocalDate.of(2022, Month.MARCH, 30);
    var period = Period.ofMonths(1); // créer une période
    performAnimalEnrichment(start, end, period);
}
private static void performAnimalEnrichment(LocalDate start, LocalDate end,
    Period period) { // utilise la période générique
    var upTo = start;
    while (upTo.isBefore(end)) {
        System.out.println("donner un nouveau jouet : " + upTo);
        upTo = upTo.plus(period); // ajoute la période
    }
}

La méthode peut ajouter une période arbitraire de temps qui est passée. Cela nous permet de réutiliser la même méthode pour différentes périodes de temps au fur et à mesure que notre gardien de zoo change d’avis.

Il existe cinq façons de créer une classe Period :

var annually = Period.ofYears(1);         // tous les 1 an
var quarterly = Period.ofMonths(3);        // tous les 3 mois
var everyThreeWeeks = Period.ofWeeks(3);   // toutes les 3 semaines
var everyOtherDay = Period.ofDays(2);      // tous les 2 jours
var everyYearAndAWeek = Period.of(1, 0, 7); // tous les ans et 7 jours

Il y a un piège. Vous ne pouvez pas chaîner des méthodes lors de la création d’un Period. Le code suivant semble équivalent à l’exemple everyYearAndAWeek, mais ce n’est pas le cas. Seule la dernière méthode est utilisée car les méthodes Period.of sont des méthodes statiques.

var wrong = Period.ofYears(1).ofWeeks(1); // toutes les semaines

Ce code trompeur est vraiment comme écrire ce qui suit :

var wrong = Period.ofYears(1);
wrong = Period.ofWeeks(1);

Ce n’est clairement pas ce que vous aviez prévu ! C’est pourquoi la méthode of() vous permet de passer le nombre d’années, de mois et de jours. Ils sont tous inclus dans la même période. Vous obtiendrez un avertissement du compilateur à ce sujet. Les avertissements du compilateur vous indiquent que quelque chose est incorrect ou suspect sans échouer à la compilation.

La méthode of() ne prend que des années, des mois et des jours. La possibilité d’utiliser une autre méthode de fabrique pour passer des semaines est simplement une commodité. Comme vous pouvez l’imaginer, la période réelle est stockée en termes d’années, de mois et de jours. Lorsque vous imprimez la valeur, Java affiche toutes les parties non nulles en utilisant le format P1Y2M3D.

Comme vous pouvez le voir, le P commence toujours la chaîne pour montrer qu’il s’agit d’une mesure de période. Viennent ensuite le nombre d’années, le nombre de mois et le nombre de jours. Si l’un d’entre eux est nul, il est omis.

Pouvez-vous déterminer ce que cela affiche ?

System.out.println(Period.ofMonths(3));

La sortie est P3M. N’oubliez pas que Java omet toutes les mesures qui sont nulles. La dernière chose à savoir sur Period est avec quels objets il peut être utilisé. Examinons un code :

3: var date = LocalDate.of(2022, 1, 20);
4: var time = LocalTime.of(6, 15);
5: var dateTime = LocalDateTime.of(date, time);
6: var period = Period.ofMonths(1);
7: System.out.println(date.plus(period)); // 2022-02-20
8: System.out.println(dateTime.plus(period)); // 2022-02-20T06:15
9: System.out.println(time.plus(period)); // Exception

Les lignes 7 et 8 fonctionnent comme prévu. Elles ajoutent un mois au 20 janvier 2022, nous donnant le 20 février 2022. La première n’a que la date, et la seconde a à la fois la date et l’heure.

La ligne 9 tente d’ajouter un mois à un objet qui n’a qu’une heure. Cela ne fonctionnera pas. Java lance une UnsupportedTemporalTypeException et se plaint que nous avons tenté d’utiliser une unité non prise en charge : Months.

Comme vous pouvez le voir, vous devez prêter attention au type d’objets de date et d’heure à chaque endroit où vous les voyez.

Travailler avec les Durées

Vous avez probablement remarqué maintenant qu’une période est un jour ou plus de temps. Il existe également une classe Duration, destinée aux unités de temps plus petites. Pour la classe Duration, vous pouvez spécifier le nombre de jours, d’heures, de minutes, de secondes ou de nanosecondes. Et oui, vous pourriez passer 365 jours pour faire une année, mais vous ne devriez vraiment pas – c’est à cela que sert Period.

De manière pratique, Duration fonctionne à peu près de la même façon que Period, sauf qu’elle est utilisée avec des objets qui ont du temps. Une Duration est affichée en commençant par PT, que vous pouvez considérer comme une période de temps. Une Duration est stockée en heures, minutes et secondes. Le nombre de secondes inclut les fractions de secondes.

Nous pouvons créer une Duration en utilisant différentes granularités :

var daily = Duration.ofDays(1);           // PT24H
var hourly = Duration.ofHours(1);         // PT1H
var everyMinute = Duration.ofMinutes(1);  // PT1M
var everyTenSeconds = Duration.ofSeconds(10); // PT10S
var everyMilli = Duration.ofMillis(1);    // PT0.001S
var everyNano = Duration.ofNanos(1);      // PT0.000000001S

Duration n’a pas de méthode de fabrique qui prend plusieurs unités comme Period. Si vous voulez que quelque chose se produise toutes les heures et demie, vous spécifiez 90 minutes.

Duration inclut une autre méthode de fabrique plus générique. Elle prend un nombre et une unité TemporalUnit. L’idée est de dire quelque chose comme “5 secondes”. Cependant, TemporalUnit est une interface. À l’heure actuelle, il n’y a qu’une seule implémentation nommée ChronoUnit.

L’exemple précédent pourrait être réécrit comme ceci :

var daily = Duration.of(1, ChronoUnit.DAYS);
var hourly = Duration.of(1, ChronoUnit.HOURS);
var everyMinute = Duration.of(1, ChronoUnit.MINUTES);
var everyTenSeconds = Duration.of(10, ChronoUnit.SECONDS);
var everyMilli = Duration.of(1, ChronoUnit.MILLIS);
var everyNano = Duration.of(1, ChronoUnit.NANOS);

ChronoUnit inclut également des unités pratiques comme ChronoUnit.HALF_DAYS pour représenter 12 heures.

ChronoUnit pour les différences

ChronoUnit est un excellent moyen de déterminer la distance entre deux valeurs Temporal. Temporal inclut LocalDate, LocalTime, etc. ChronoUnit se trouve dans le package java.time.temporal.

var one = LocalTime.of(5, 15);
var two = LocalTime.of(6, 30);
var date = LocalDate.of(2016, 1, 20);
System.out.println(ChronoUnit.HOURS.between(one, two)); // 1
System.out.println(ChronoUnit.MINUTES.between(one, two)); // 75
System.out.println(ChronoUnit.MINUTES.between(one, date)); // DateTimeException

La première instruction d’impression montre que between tronque plutôt qu’arrondit. La seconde montre à quel point il est facile de compter en différentes unités. Changez simplement le type ChronoUnit. La dernière nous rappelle que Java lancera une exception si nous mélangeons ce qui peut être fait sur les objets de date et d’heure.

Alternativement, vous pouvez tronquer n’importe quel objet avec un élément de temps. Par exemple :

LocalTime time = LocalTime.of(3,12,45);
System.out.println(time); // 03:12:45
LocalTime truncated = time.truncatedTo(ChronoUnit.MINUTES);
System.out.println(truncated); // 03:12

Cet exemple met à zéro tous les champs plus petits que les minutes. Dans notre cas, il supprime les secondes.

L’utilisation d’une Duration fonctionne de la même manière que l’utilisation d’une Period. Par exemple :

7: var date = LocalDate.of(2022, 1, 20);
8: var time = LocalTime.of(6, 15);
9: var dateTime = LocalDateTime.of(date, time);
10: var duration = Duration.ofHours(6);
11: System.out.println(dateTime.plus(duration)); // 2022-01-20T12:15
12: System.out.println(time.plus(duration)); // 12:15
13: System.out.println(
14: date.plus(duration)); // UnsupportedTemporalTypeException

La ligne 11 montre que nous pouvons ajouter des heures à un LocalDateTime, puisqu’il contient une heure. La ligne 12 fonctionne également, puisque tout ce que nous avons est une heure. La ligne 13 échoue car nous ne pouvons pas ajouter des heures à un objet qui ne contient pas d’heure.

Essayons à nouveau, mais ajoutons 23 heures cette fois.

7: var date = LocalDate.of(2022, 1, 20);
8: var time = LocalTime.of(6, 15);
9: var dateTime = LocalDateTime.of(date, time);
10: var duration = Duration.ofHours(23);
11: System.out.println(dateTime.plus(duration)); // 2022-01-21T05:15
12: System.out.println(time.plus(duration)); // 05:15
13: System.out.println(
14: date.plus(duration)); // UnsupportedTemporalTypeException

Cette fois, nous voyons que Java avance au-delà de la fin de la journée. La ligne 11 passe au jour suivant puisque nous dépassons minuit. La ligne 12 n’a pas de jour, donc l’heure se déroule simplement – comme sur une vraie horloge.

Period vs. Duration

N’oubliez pas que Period et Duration ne sont pas équivalents. Cet exemple montre une Period et une Duration de même longueur :

var date = LocalDate.of(2022, 5, 25);
var period = Period.ofDays(1);
var days = Duration.ofDays(1);
System.out.println(date.plus(period)); // 2022-05-26
System.out.println(date.plus(days)); // Unsupported unit: Seconds

Puisque nous travaillons avec un LocalDate, nous sommes obligés d’utiliser Period. Duration a des unités de temps en elle, même si nous ne les voyons pas, et elles sont destinées uniquement aux objets avec du temps. Assurez-vous que vous pouvez remplir le tableau 4.7 pour identifier quels objets peuvent utiliser Period et Duration.

 Peut utiliser avec Period?Peut utiliser avec Duration?
LocalDateOuiNon
LocalDateTimeOuiOui
LocalTimeNonOui
ZonedDateTimeOuiOui

Travailler avec les Instants

La classe Instant représente un moment spécifique dans le temps dans le fuseau horaire GMT. Supposons que vous vouliez exécuter un chronomètre :

var now = Instant.now();
// faire quelque chose qui prend du temps
var later = Instant.now();
var duration = Duration.between(now, later);
System.out.println(duration.toMillis()); // Renvoie le nombre de millisecondes

Dans notre cas, le “quelque chose qui prend du temps” était juste plus d’une seconde, et le programme a affiché 1025.

Si vous avez un ZonedDateTime, vous pouvez le transformer en Instant :

var date = LocalDate.of(2022, 5, 25);
var time = LocalTime.of(11, 55, 00);
var zone = ZoneId.of("US/Eastern");
var zonedDateTime = ZonedDateTime.of(date, time, zone);
var instant = zonedDateTime.toInstant(); // 2022-05-25T15:55:00Z
System.out.println(zonedDateTime); // 2022-05-25T11:55-04:00[US/Eastern]
System.out.println(instant); // 2022-05-25T15:55:00Z

Les deux dernières lignes représentent le même moment dans le temps. Le ZonedDateTime inclut un fuseau horaire. L’Instant se débarrasse du fuseau horaire et le transforme en un Instant de temps en GMT.

Vous ne pouvez pas convertir un LocalDateTime en Instant. Rappelez-vous qu’un Instant est un point dans le temps. Un LocalDateTime ne contient pas de fuseau horaire, et il n’est donc pas universellement reconnu dans le monde entier comme le même moment dans le temps.

Tenir compte de l’heure d’été

Certains pays observent l’heure d’été. C’est lorsque les horloges sont ajustées d’une heure deux fois par an pour mieux utiliser la lumière du soleil. Tous les pays ne participent pas, et ceux qui le font utilisent différents week-ends pour le changement. Ne vous inquiétez pas, si cela est évoqué dans une question, il sera précisé si une date/heure mentionnée tombe un week-end où les horloges sont programmées pour être changées.

La figure montre ce qui se passe avec les horloges. Lorsque nous changeons nos horloges en mars, le temps avance de 1h59 à 3h00. Lorsque nous changeons nos horloges en novembre, le temps recule, et nous vivons l’heure de 1h00 à 1h59 deux fois. Les enfants apprennent cela comme “Avance au printemps, et recule en automne”.

Par exemple, le 13 mars 2022, nous avançons nos horloges d’une heure et passons de 2h00 à 3h00. Cela signifie qu’il n’y a pas de 2h30 ce jour-là. Si nous voulions connaître l’heure une heure plus tard que 1h30, ce serait 3h30.

var date = LocalDate.of(2022, Month.MARCH, 13);
var time = LocalTime.of(1, 30);
var zone = ZoneId.of("US/Eastern");
var dateTime = ZonedDateTime.of(date, time, zone);
System.out.println(dateTime); // 2022-03-13T01:30-05:00[US/Eastern]
System.out.println(dateTime.getHour()); // 1
System.out.println(dateTime.getOffset()); // -05:00
dateTime = dateTime.plusHours(1);
System.out.println(dateTime); // 2022-03-13T03:30-04:00[US/Eastern]
System.out.println(dateTime.getHour()); // 3
System.out.println(dateTime.getOffset()); // -04:00

Notez que deux choses changent dans cet exemple. L’heure passe de 1h30 à 3h30. Le décalage UTC change également. Souvenez-vous quand nous avons calculé l’heure GMT en soustrayant le fuseau horaire de l’heure ? Vous pouvez voir que nous sommes passés de 6h30 GMT (1h30 moins -5h00) à 7h30 GMT (3h30 moins -4h00). Cela montre que le temps a vraiment changé d’une heure du point de vue de GMT. Nous avons imprimé l’heure et les champs de décalage séparément pour mettre l’accent sur ce point.

De même, en novembre, une heure après le 1h30 initial est également 1h30 car à 2h00 nous répétons l’heure. Cette fois, essayez de calculer vous-même l’heure GMT pour les trois moments pour confirmer que nous ne déplaçons vraiment qu’une heure à la fois.

var date = LocalDate.of(2022, Month.NOVEMBER, 6);
var time = LocalTime.of(1, 30);
var zone = ZoneId.of("US/Eastern");
var dateTime = ZonedDateTime.of(date, time, zone);
System.out.println(dateTime); // 2022-11-06T01:30-04:00[US/Eastern]
dateTime = dateTime.plusHours(1);
System.out.println(dateTime); // 2022-11-06T01:30-05:00[US/Eastern]
dateTime = dateTime.plusHours(1);
System.out.println(dateTime); // 2022-11-06T02:30-05:00[US/Eastern]

Avez-vous compris ? Nous sommes passés de 5h30 GMT à 6h30 GMT, puis à 7h30 GMT.

Enfin, essayer de créer une heure qui n’existe pas avance simplement l’horloge :

var date = LocalDate.of(2022, Month.MARCH, 13);
var time = LocalTime.of(2, 30);
var zone = ZoneId.of("US/Eastern");
var dateTime = ZonedDateTime.of(date, time, zone);
System.out.println(dateTime); // 2022-03-13T03:30-04:00[US/Eastern]

Java est assez intelligent pour savoir qu’il n’y a pas de 2h30 cette nuit-là et passe au décalage GMT approprié.