CodeGym/Blog Java/France/Date et calendrier Java : Classes DateTime et Calendar
Auteur
Milan Vucic
Programming Tutor at Codementor.io

Date et calendrier Java : Classes DateTime et Calendar

Publié dans le groupe France
membres
Coucou ! Aujourd'hui, nous allons commencer à travailler avec un nouveau type de données que nous n'avons pas encore rencontré, les dates. J'imagine que tu sais ce qu'est une date. :) En principe, nous pourrions stocker la date et l'heure actuelles dans une chaîne Java ordinaire.
public class Main {
   public static void main(String[] args) {

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
Mais cette approche présente de nombreux inconvénients. La classe String est conçue pour fonctionner avec du texte, et ses méthodes sont appropriées pour cette tâche. Si nous avons besoin de manipuler une date d'une manière ou d'une autre (lui ajouter 2 heures, par exemple), String ne fonctionne pas si bien. Ou si nous voulons afficher la date et l'heure actuelles lorsque le programme est compilé. String n'aide pas ici non plus : au moment où tu écris le code et l'exécutes, l'heure aura changé et la console affichera les mauvaises informations. C'est pourquoi les créateurs de Java ont fourni plusieurs classes pour travailler avec les dates et heures. La première d'entre elles est java.util.Date

La classe Date Java

Nous avons spécifié son nom complet, car un autre package Java dispose de la classe java.sql.Date. Ne les confonds pas ! La première chose que tu dois savoir à son sujet est qu'elle stocke la date comme le nombre de millisecondes passées depuis le 1er janvier 1970. Ce système de temps a même son propre nom : « Heure Unix » Une approche plutôt intéressante, tu ne trouves pas ? :) La deuxième chose à retenir est la suivante : Si tu crées un objet Date à l'aide du constructeur par défaut, le résultat représente la date et l'heure actuelles au moment où l'objet a été créé. Tu te souviens quand nous avions dit qu'une date représentée comme un objet String aurait du mal avec une telle tâche ? La classe Date gère cela facilement.
public class Main {
   public static void main(String[] args) {

       Date date = new Date();
       System.out.println(date);
   }
}
Exécute ce code à plusieurs reprises, et tu verras l'heure changer chaque fois. :) C'est possible car le temps est stocké en millisecondes : ce sont des unités de temps extrêmement petites, les résultats sont donc très précis. La classe Date possède un autre constructeur : tu peux lui transmettre le nombre exact de millisecondes de minuit le 1er janvier 1970 à la date requise, et un objet de date correspondant sera créé :
public class Main {
   public static void main(String[] args) {

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Sortie de la console :
Fri May 30 04:20:12 GMT 2008
Cela nous donne le 30 mai 2008. « Fri » indique le jour de la semaine en anglais (vendredi), et GMT le fuseau horaire (Temps moyen de Greenwich). Les millisecondes sont transmises sous forme de long, car le nombre de millisecondes n'entre généralement pas dans un int. Alors, quelles opérations avec les dates pourrions-nous avoir besoin d'effectuer ? Eh bien, la plus évidente, bien sûr, est la comparaison. Pour déterminer si une date est antérieure ou postérieure à une autre. Il y a pour cela plusieurs façons de procéder. Par exemple, tu peux appeler la méthode Date.getTime() qui renvoie le nombre de millisecondes qui se sont écoulées depuis minuit le 1er janvier 1970. Il suffit de l'appeler sur deux objets Date et de comparer les résultats :
public class Main {
   public static void main(String[] args) {

       Date date1 = new Date();

       Date date2 = new Date();

       System.out.println((date1.getTime() > date2.getTime())?
               "date1 is later than date2" : "date1 is earlier than date2");
   }
}
Sortie :
date1 est antérieure à date2
Mais il y a aussi un moyen plus pratique, en utilisant les méthodes spéciales fournies par la classe Date : before(), after() et equals(). Toutes retournent une valeur booléenne. La méthode before() vérifie si notre date est antérieure à la date passée comme argument :
public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);// Suspend the program for 2 seconds
       Date date2 = new Date();

       System.out.println(date1.before(date2));
   }
}
Sortie de la console :
true
De même, la méthode after() vérifie si notre date est postérieure à la date passée comme argument :
public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);// Suspend the program for 2 seconds
       Date date2 = new Date();

       System.out.println(date1.after(date2));
   }
}
Sortie de la console :
false
Dans nos exemples, nous « mettons le programme en veille » pendant 2 secondes, pour nous assurer d'avoir deux dates différentes. Sur les ordinateurs rapides, le délai entre la création de date1 et date2 peut être inférieur à une milliseconde, auquel cas les deux méthodes, before() et after(), renverraient false. Mais dans ce cas, la méthode equals() renverra true ! Après tout, elle compare le nombre de millisecondes depuis minuit le 1er janvier 1970 pour chaque date. Les objets ne sont considérés comme égaux que s'ils correspondent au même nombre de millisecondes :
public static void main(String[] args) {

   Date date1 = new Date();
   Date date2 = new Date();

   System.out.println(date1.getTime());
   System.out.println(date2.getTime());

   System.out.println(date1.equals(date2));
}
Voici une autre chose à laquelle tu dois faire attention. Si tu ouvres la documentation pour la classe Date sur le site Web d'Oracle, tu verras que bon nombre de ses méthodes et constructeurs ont été marqués comme dépréciés (c'est-à-dire que leur utilisation est déconseillée). Voici ce que les créateurs de Java ont à dire sur les parties de classes qui ont été dépréciées :
« Un élément de programme annoté @Deprecated est quelque chose que nous recommandons aux programmeurs de ne pas utiliser, généralement parce que c'est dangereux, ou parce qu'il existe une meilleure alternative. »
Cela ne signifie pas que ces méthodes ne peuvent pas être utilisées du tout. Si tu essaies d'exécuter du code à l'aide de méthodes dépréciées dans un EDI, il fonctionnera très probablement. Par exemple, prenons la méthode Date.getHours(), dépréciée, qui renvoie le nombre d'heures associées à un objet Date.
public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());
}
Si tu exécutes le code à 14h21, elle affichera le numéro 14. Comme tu peux le voir, la méthode dépréciée est rayée, mais elle fonctionne toujours. Ces méthodes ne sont pas supprimées afin de ne pas briser l'énorme corps de code existant qui les utilise. En d'autres termes, ces méthodes ne sont ni « brisées » ni « retirées ». C'est juste que leur utilisation est déconseillée, car une alternative plus pratique est disponible. Et dans notre cas, la documentation mentionne spécifiquement cette alternative :Comment ne pas se perdre dans le temps : Classes DateTime et Calendar - 2La plupart des méthodes de la classe Date ont été déplacées dans la classe Calendar, améliorée et étendue. Nous allons bientôt nous familiariser avec. :)

Classe Calendar pour un calendrier Java

JDK 1.1 a introduit une nouvelle classe : Calendar. Elle rend le travail avec des dates en Java un peu plus facile qu'avant. La seule implémentation de la classe Calendar avec laquelle nous travaillerons est la classe GregorianCalendar. Elle implémente le calendrier grégorien, qui est observé par la plupart des pays du monde. Son principal avantage est qu'elle peut travailler avec des dates dans un format plus pratique. Par exemple, elle peut :
  • Ajouter un mois ou un jour à la date actuelle
  • Vérifier si l'année est bissextile ;
  • Renvoyer les composants individuels de la date (par exemple, extraire le numéro du mois d'une date entière)
  • Elle contient également un système très pratique de constantes (nous verrons plusieurs d'entre elles ci-dessous).
Une autre amélioration importante de la classe Calendar est sa constante Calendar.ERA : tu peux indiquer une date av. J.-C. ou dans notre ère. Voyons tout cela avec des exemples. Créons un objet calendar avec la date du 25 janvier 2017 :
public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
Dans la classe Calendar (ainsi que dans la classe Date, d'ailleurs), les mois commencent à zéro, donc nous passons le nombre 0 comme deuxième argument. Lorsque tu travailles avec la classe Calendar il est important de comprendre que c'est juste cela, un calendrier, pas une date individuelle. Une date n'est que quelques nombres qui indiquent un intervalle de temps spécifique. Un calendrier est un système complet qui te permet de faire beaucoup de choses avec des dates. :) Cela devient assez évident si tu essaies d'afficher l'objet Calendar : Sortie :
java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,dstSavings=0,useDaylight=false,transitions=79,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=1,ERA=?,YEAR=2017,MONTH=0,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=25,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
Regarde toutes les informations que tu obtiens ! Un calendrier a un tas de propriétés qu'une date normale n'a pas, et toutes sont affichées (c'est ainsi que fonctionne la méthode toString() dans la classe Calendar). Si tu as juste besoin d'obtenir une date simple à partir du calendrier, c'est-à-dire un objet Date utilise la méthode Calendar.getTime() (le nom n'est pas le plus logique, mais qu'est-ce qu'on peut y faire ?) :
public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Sortie :
Wed Jan 25 00:00:00 GMT 2017
Nous avons maintenant pris le calendrier et l'avons « réduit » en date ordinaire. Allons plus loin. En plus de désigner des mois par leur nombre, tu peux utiliser les valeurs des constantes des champs de la classe Calendar. Ces constantes sont des champs statiques de la classe Calendar avec une valeur prédéfinie qui ne peut pas être modifiée. Il s'agit en fait d'une option encore meilleure, car leur utilisation améliore la lisibilité de ton code.
public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Calendar.JANUARY est une des constantes qui représentent les mois de l'année. En utilisant ces constantes nommées, personne n'oubliera, par exemple, que le numéro 3 signifie avril, et non le troisième mois, que nous aimons appeler Mars. Il suffit d'écrire Calendar.APRIL et c'est fait. :) Tous les champs du calendrier (jour, mois, minutes, secondes, etc.) peuvent être spécifiés séparément à l'aide de la méthode set(). Cette méthode est très pratique, car la classe Calendar a une constante pour chaque champ, et le code résultant est très facile à lire. Dans le dernier exemple, nous avons créé une date, mais nous n'avons pas défini d'heure pour elle. Réglons l'heure sur 19:42:12
public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar();
   calendar.set(Calendar.YEAR, 2017);
   calendar.set(Calendar.MONTH, 0);
   calendar.set(Calendar.DAY_OF_MONTH, 25);
   calendar.set(Calendar.HOUR_OF_DAY, 19);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   System.out.println(calendar.getTime());
}
Sortie :
Wed Jan 25 19:42:12 GMT 2017
Nous appelons la méthode set() en passant une constante (en fonction du champ que nous voulons changer) et la nouvelle valeur pour le champ. Il s'avère que cette méthode set() est une sorte de « super-setter » qui sait comment définir la valeur non seulement pour un champ, mais aussi pour de nombreux autres. :) La classe Calendar utilise la méthode add() pour ajouter et soustraire des valeurs. Tu peux passer le champ que tu souhaites modifier, et un nombre (la quantité exacte que tu veux ajouter/soustraire à la valeur actuelle). Par exemple, obtenons une date antérieure de 2 mois à la date que nous avons créée :
public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 19);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.add(Calendar.MONTH, -2); // To subtract, pass a negative number
   System.out.println(calendar.getTime());
}
Sortie :
Fri Nov 25 19:42:12 GMT 2016
Très bien! Nous avons obtenu la date d'il y a 2 mois. Cela n'a pas fait changer que le mois : l'année est également passée de 2017 à 2016. Bien sûr, lors de la conversion de dates, l'année en cours est calculée automatiquement sans aucun besoin pour toi d'en garder une trace manuelle. Mais si pour une raison quelconque tu devais désactiver ce comportement, tu pourrais le faire. La méthode roll() peut ajouter et soustraire des valeurs sans affecter les valeurs restantes. Par exemple, comme ceci :
public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(calendar.getTime());
}
Nous avons fait exactement la même chose que dans l'exemple précédent : nous avons retiré 2 mois à la date actuelle. Mais maintenant, le code fait quelque chose de différent : le mois est passé de Janvier à Novembre, mais l'année reste inchangée : 2017 ! Sortie :
Sat Nov 25 10:42:12 GMT 2017
Seul le mois change. Comme nous l'avons dit précédemment, nous pouvons obtenir tous les champs de Calendar séparément. Nous le faisons avec la méthode get() :
public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   System.out.println("Year: " + calendar.get(Calendar.YEAR));
   System.out.println("Month: " + calendar.get(Calendar.MONTH));
   System.out.println("Week in the month: " + calendar.get(Calendar.WEEK_OF_MONTH));// Week in this month?

   System.out.println("Day: " + calendar.get(Calendar.DAY_OF_MONTH));

   System.out.println("Hours: " + calendar.get(Calendar.HOUR));
   System.out.println("Minutes: " + calendar.get(Calendar.MINUTE));
   System.out.println("Seconds: " + calendar.get(Calendar.SECOND));
   System.out.println("Milliseconds: " + calendar.get(Calendar.MILLISECOND));

}
Sortie :
Année : 2017 Mois : 0 Semaine du mois : 5 Jour : 25 Heures : 10 Minutes : 42 Secondes : 12 Millisecondes : 0
Donc en plus du « super-setter » de la classe Calendar, nous avons un « super-getter ». :) Bien sûr, un autre aspect intéressant de cette classe est le travail avec les ères. Pour créer une date « av. J.-C. », tu dois utiliser le champ Calendar.ERA. Par exemple, créons une date pour la Bataille de Cannes, au cours de laquelle Hannibal a vaincu l'armée romaine. Elle s'est déroulée le 2 août 216 av. J.-C. :
public static void main(String[] args) {
   GregorianCalendar cannae = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannae.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("MMM dd, yyy GG");
   System.out.println(df.format(cannae.getTime()));
}
Ici, nous avons utilisé la classe SimpleDateFormat pour imprimer la date dans un certain format de date en Java, qui est plus facile à comprendre pour nous (les lettres « GG » indiquent que nous voulons que l'ère soit affichée). Sortie :
02 Aug. 216 BC.
La classe Calendar a beaucoup d'autres méthodes et constantes. Tu peux en apprendre davantage à leur sujet dans la documentation. Si tu n'aimes pas le format de date Sat Nov 25 10:42:12 GMT 2017, tu peux utiliser SimpleDateFormat pour la transformer comme bon te semble.
public static void main(String[] args) {

   SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, MMMM d, yyyy");
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(dateFormat.format(calendar.getTime()));
}
Sortie :
Saturday 25 November 2017
C'est bien mieux ainsi, non ? :)
Cet article est également disponible en anglais:
Read the English version of this article about the Date class and Calendar class. Programmers need to be good at time management!
Commentaires
  • Populaires
  • Nouveau
  • Anciennes
Tu dois être connecté(e) pour laisser un commentaire
Cette page ne comporte pas encore de commentaires