Traductions pour la plateforme Java

Joda-Time

Article d'origine: 

Nul n'échappe au temps. Pourquoi ne pas se faciliter les choses ?

Résumé: 

Aucune application d'entreprise ne peut échapper au temps. Les applications doivent connaitre l'heure qu'il est et l'heure qu'il sera, et parfois elles doivent calculer comment passer de l'une à l'autre. Faire ce travail avec le JDK peut se révéler pénible et fastidieux. Découvrez Joda-Time, une librairie de manipulation des dates et de l'heure Open Source et simple d'emploi, destinée à la plateforme Java™. Comme vous le verrez dans cet article, Joda-Time réduit fortement ce côté pénible de la manipulation de la date et de l'heure.

Quand j'écris des applications métier, j'ai fréquemment besoin de manipuler des dates. Et dans ma mission la plus récente - pour l'industrie de l'assurance - des calculs de dates corrects sont tout spécialement importants. Je commençais à en avoir un peu assez de java.util.Calendar. Si vous vous êtes déjà servi de cette classe pour gérer des valeurs de type date ou heure, vous savez combien il est pesant de l'utiliser. Aussi quand j'ai entendu parler de Joda-Time - une librairie alternative de gestion de date / heure pour les applications Java - j'ai décider de m'y intéresser. Pour faire court: je suis ravi de l'avoir fait.

Joda-Time rend les valeurs de type date / heure faciles à gérer, à manipuler et à comprendre. La facilité d'emploi est en fait l'objectif principal des concepteurs de Joda. Les autres objectifs incluent l'extensibilité, un ensemble complet de fonctionnalités et le support de calendriers multiples. Et Joda est interopérable à 100% avec le JDK, il n'y a donc pas besoin de remplacer tout le code Java, seulement les parties qui effectuent les calculs de date/heure.

Cet article est une initiation à Joda et montre comment l'utiliser. Il couvre les sujets suivants:

  • L'utilité d'une librairie alternative pour gérer dates et heures
  • Les concepts clés de Joda
  • Création d'objets Joda-Time
  • Manipulation de dates et heures, façon Joda
  • Formattage de dates et heures, façon Joda

Vous pouvez télécharger le code source d'une application de démonstration de ces concepts.

Dans le giron de Joda

Joda est en fait un projet-cadre pour un certain nombre d'APIs alternatives dédiées à Java, donc techniquement parlant il est incorrect d'utiliser indifféremment les noms Joda et Joda-Time. Mais au moment où cet article est écrit, l'API Joda-Time semble être la seule API Joda dont le développement soit actif. Etant donné l'état actuel du projet-cadre Joda, je pense qu'identifier Joda à Joda-Time ne pose pas de problème.

L'utilité de Joda

Pourquoi s'intéresser à Joda ? Considérons la création d'un instant arbitraire - disons minuit pile le 1er janvier 2000. Comment créer avec le JDK un objet représentant cet instant ? java.util.Date ? Hé bien, pas vraiment, parce que la Javadoc indique depuis le JDK 1.1 qu'un java.util.Calendar devrait plutôt être utilisé. Le nombre de constructeurs dépréciés dans Date restreint beaucoup les options disponibles pour créer un tel objet.

Date possède cependant un constructeur que l'on peut utiliser pour créer un objet représentant un autre instant que "maintenant". Cette méthode prend en argument le nombre de millisecondes depuis l'époque, c'est-à-dire le 1er janvier 1970 à minuit, heure de Greenwich (GMT), et il faut donc prendre en compte dans le calcul le fuseau horaire. Vu l'importance de l'année 2000 dans le métier du développement logiciel, on pourrait penser que je connais cette valeur par coeur, mais il n'en est rien. Autant pour la classe Date.

Que dire de Calendar ? Je créerais l'instance souhaitée de cette façon:

Calendar calendar = Calendar.getInstance();
calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);

Avec Joda, le code ressemble à cela:

DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);

Il n'y a pas grande différence sur cette simple ligne de code. Mais je vais maintenant compliquer un peu le problème. Supposons que je veuille ajouter 90 jours à cette date et afficher le résultat. En utilisant le JDK, je ferais comme dans le Listing 1:

Listing 1. Ajouter 90 jours à une date et afficher le résultat, avec le JDK

Calendar calendar = Calendar.getInstance();
calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
SimpleDateFormat sdf =
  new SimpleDateFormat("E MM/dd/yyyy HH:mm:ss.SSS");
calendar.add(Calendar.DAY_OF_MONTH, 90);
System.out.println(sdf.format(calendar.getTime()));

En utilisant Joda, le code ressemble au Listing 2:

Listing 2. Ajouter 90 jours à une date et afficher le résultat, avec Joda

DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(90).toString("E MM/dd/yyyy HH:mm:ss.SSS");

Le fossé s'est un peu élargi (deux lignes de code pour Joda contre 5 pour le JDK).

Maintenant supposons que je veuille afficher la date du dernier jour de la semaine du mois suivant celui qui est à 45 jours de l'an 2000. Franchement, je ne veux même pas essayer de le faire au moyen de Calendar. C'est tout bonnement trop pénible d'utiliser le JDK pour faire un calcul qui n'a pourtant rien de bien compliqué. C'est à un moment comme celui-ci que j'ai réalisé pour la première fois, il y a quelques années, la puissance de Joda-Time.  En l'utilisant, le code nécessaire au calcul précédent ressemble au Listing 3:

Listing 3. Joda à la rescousse

DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek()
  .withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS");

Le Listing 3 affiche:

Sun 03/19/2000 00:00:00.000

Si vous cherchez une solution de remplacement facile à utiliser pour le traitement des dates du JDK, vous devriez vraiment prendre en compte Joda. Sinon, je vous en prie continuez à utiliser Calendar pour effectuer tous vos calculs de dates. Pendant que vous y êtes, vous pourriez coupez votre gazon avec une paire de ciseaux et laver votre voiture avec une vieille brosse à dents.

Joda et l'interopérabilité avec le JDK

Il ne faut pas longtemps pour se rendre compte que la classe Calendar du JDK est difficile à utiliser, et que Joda pallie à ce défaut. Les concepteurs de Joda ont aussi pris une décision qui, je pense, est la clé de son succès: l'interopérabilité avec le JDK. Les classes de Joda sont capables de produire (bien que parfois de manière un peu alambiquée, comme vous le verrez) des instances de java.util.Date (et de Calendar). Ceci permet de conserver tout le code existant qui est lié au JDK, mais de laisser Joda faire le travail le plus lourd concernant les calculs sur des dates/heures.

Par exemple, après avoir fait le calcul du Listing 3, tout ce que j'ai à faire pour repasser au JDK est d'effectuer les changements montrés dans le Listing 4:

Listing 4. Passage des résultats calculés par Joda à un objet du JDK

Calendar calendar = Calendar.getInstance();
DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek()
  .withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS");
calendar.setTime(dateTime.toDate());

Par ce procédé très simple, les résultats du calcul sont transférés dans un objet du JDK. C'est un aspect très sympathique de Joda.

Dates et heures: les concepts clés de Joda

Joda utilise les concepts suivants, qui sont valables pour toute librairie de manipulation du temps:

  • Immuabilité
  • Instant
  • Temps partiel
  • Chronologie
  • Fuseau horaire

Nous verrons tour à tour chacune de ces notions et  leur lien avec Joda.

Immuabilité

Les classes de Joda dont je parlerai dans cet article sont immuables, c'est-à-dire que leurs instances ne peuvent pas être modifiées. (Un avantage des classes immuables est qu'elles sont thread-safe). Les méthodes de l'API que je vous montrerai, et qui servent à faire des calculs sur les dates, ne modifient pas les instances originales. Quand on manipule une classe Joda au moyen d'une méthode de l'API, on doit enregistrer le résultat retourné car l'instance manipulée ne peut pas être modifiée. Vous êtes probablement habitué à cette conception, c'est ainsi que fonctionnent les différentes méthodes de manipulation de java.lang.String par exemple.

Instant

Un Instant représente un moment bien précis dans le temps, exprimé en millisecondes depuis l'époque. Cette définition est cohérente avec celle du JDK, et c'est la raison pour laquelle toute sous-classe d'Instant est compatible avec les classes Date et Calendar du JDK.

Pour le définir de manière plus rigoureuse, un instant est un point sur la ligne du temps qui est unique et n'apparait qu'une seule fois.

Instant partiellement défini

Un instant partiellement défini est exactement ce que son nom indique: la définition fragmentaire d'une donnée temporelle. Alors qu'un instant spécifie un point exact du temps par rapport à l'époque, un instant partiellement défini indique un moment susceptible de "glisser" de manière à correspondre à des instants multiples. Par exemple, le 2 juin pourrait s'appliquer à n'importe quel instant de n'importe quelle occurrence du second jour de juin (dans le calendrier grégorien) de n'importe quelle année. De la même manière, 11:06 peut survenir une fois par jour, peu importe l'année. Même s'ils ne spécifient pas un instant précis, les instants instants partiellement définis ont leur utilité.

J'aime imaginer un instant partiellement défini comme un point sur un cercle qui est parcouru plusieurs fois. Donc si le moment que je veux représenter peut survenir plusieurs fois (c'est-à-dire se répéter) d'une manière qui a du sens, alors c'est un instant partiellement défini.

Chronologie

La notion clé des mécanismes internes de Joda - et celle qui est au coeur de sa conception - est la chronologie (cette notion est représentée par une classe abstraite de même nom). Fondamentalement, une chronologie est un système calendaire - une façon spécifique de compter le temps - et le cadre dans lequel on effectue des calculs arithmétiques sur les dates. Voici des exemples de chronologies gérées par Joda:

  • ISO (la valeur par défaut)
  • Copte
  • Julien
  • Islamique

Joda-time 1.6 fournit un support pour huit chronologies, chacune d'elles servant de base aux calculs effectués dans un système calendaire donné.

Fuseau horaire

Un fuseau horaire est une position géographique déterminée relativement à Greenwich (Angleterre) qui est utilisée pour calculer l'heure. Pour savoir précisément à quelle heure un événement se produit, il est également important d'en connaitre le lieu. Tout calcul temporel rigoureux doit tenir compte du fuseau horaire (ou être relatif à GMT), à moins que ce calcul manipule des dates liées au même fuseau horaire (et même ainsi, cela peut être important si l'événement est susceptible d'intéresser des tierces parties se trouvant dans un autre fuseau horaire).

DateTimeZone est la classe utilisée par la librairie Joda pour encapsuler cette notion de lieu. Bien des calculs de dates/heures peuvent être effectués sans se préoccuper du fuseau horaire, mais il est tout de même important de comprendre de quelle manière DateTimeZone impacte ce que fait Joda. L'heure par défaut, qui provient de l'horloge système de la machine sur laquelle l'application tourne, est utilisée dans la plupart des cas.

Création d'objets Joda-Time

Je vais maintenant vous présenter quelques-unes des classes Joda que vous utiliserez couramment si vous adoptez la librairie, et je vais vous montrer comment les instancier.

Toutes les implémentations que vous verrez dans cette partie ont plusieurs constructeurs qui vous permettent d'initialiser la date/heure encapsulée. On peut les classer en quatre catégories:

  • Utilisation de la date système.
  • Spécification d'un instant (éventuellement partiellement défini) en utilisant des champs distincts qui varient en nombre selon la granularité de l'implémentation
  • Spécification d'un instant (éventuellement partiellement défini) en millisecondes
  • Utilisation d'un autre objet (par exemple java.util.Date, ou bien un autre objet Joda).

Je parlerai de chacun de ces constructeurs pour la première classe que nous étudierons: DateTime. Ces informations seront facilement transposables aux constructeurs correspondants des autres classes Joda.

Classes Joda modifiables

Je ne suis pas un grand fan des classes utilitaires modifiables. Je pense qu'il n'y a en a pas vraiment de cas d'utilisation courants qui justifieraient qu'on les utilise beaucoup. Mais si vous décidez que vous avez besoin d'utiliser les classes modifiables de Joda, l'information contenue ici pourrait se révéler utile pour vos projets. La seule différence entre les APIS Readable et ReadWritable est la capacité qu'ont les classes ReadWritable de modifier la date/heure encapsulée, je n'en parlerai donc pas davantage.

ReadableInstant

Joda concrétise le concept d'instant au moyen de la classe ReadableInstant. Les classes Joda représentant des instants immuables en sont des sous-classes. (Il aurait été préférable de la nommer ReadOnlyInstant, qui à mon avis correspond mieux à l'idée des concepteurs. Autrement dit, ReadableInstant représente un instant qui ne peut pas être modifié). Deux de ces sous-classes sont DateTime et DateMidnight:

  • DateTime: c'est la classe que vous utiliserez probablement le plus souvent. Elle encapsule un instant à la milliseconde près. Un DateTime est toujours associé à un DateTimeZone dont la valeur par défaut est le fuseau horaire de la machine sur laquelle le code tourne. Il existe de nombreuses façons de construire un objet DateTime. Le constructeur suivant utilise la date système:
    		DateTime dateTime = new DateTime();
    

    En général, j'essaie d'éviter d'utiliser l'horloge système pour initialiser les dates de mon application, et je préfère externaliser la récupération de la date système. Cet exemple montre comment faire:

    		DateTime dateTime = SystemFactory.getClock().getDateTime();
    

    Ainsi, je peux tester plus facilement mon code en utilisant des dates/heures différentes: je n'ai pas besoin de changer le code pour exécuter des scénarios utilisant des dates différentes, parce que la date est positionnée dans l'implémentation de SystemClock, et non dans mon application. (Je pourrais modifier la date de mon système, mais que ce serait pénible !)

    Le code suivant construit un objet DateTime en le spécifiant les valeurs des champs individuellement:

    		DateTime dateTime = new DateTime(
      2000, //année
      1,    // mois
      1,    // jour
      0,    // heure (zéro  = minuit)
      0,    // minute
      0,    // seconde
      0     // milliseconde
    );
    

    Comme vous le voyez, Joda permet de contrôler précisément la construction d'un objet DateTime pour représenter un instant particulier. Chaque classe Joda possède un constructeur similaire, permettant de spécifier tous les champs inclus dans la classe. Vous pouvez l'utiliser pour déterminer rapidement le niveau de granularité auquel une classe opère.

    Le constructeur suivant spécifie un instant en millisecondes depuis l'époque. Il crée un objet DateTime à partir de la valeur en millisecondes d'un objet Date du JDK, qui a la même définition en millisecondes depuis l'époque:

    		java.util.Date jdkDate = obtainDateSomehow();
    long timeInMillis = jdkDate.getTime();
    DateTime dateTime = new DateTime(timeInMillis);
    

    Et cet exemple est similaire au précédent, sauf que cette fois je passe directement l'objet Date au constructeur:

    		java.util.Date jdkDate = obtainDateSomehow();
    dateTime = new DateTime(jdkDate);
    

    Joda permet l'utilisation de beaucoup d'autres objets dans le constructeur d'un DateTime, comme le démontre le Listing 5:

    Listing 5. Passage de différents objets au constructeur de DateTime

    		// Utilisation d'un Calendar
    java.util.Calendar calendar = obtainCalendarSomehow();
    dateTime = new DateTime(calendar);
    // Utilisation d'une autre DateTime Joda
    DateTime anotherDateTime = obtainDateTimeSomehow();
    dateTime = new DateTime(anotherDateTime);
    // Utilisation d'une String (correctement formattée)
    String timeString = "2006-01-26T13:30:00-06:00";
    dateTime = new DateTime(timeString);
    timeString = "2006-01-26";
    dateTime = new DateTime(timeString);
    

    Notez que si vous prévoyez d'utiliser une String (qui doit être analysée), vous devez la formatter précisément. Consultez la Javadoc de la classe ISODateTimeFormat de Joda pour davantage de renseignements (voir les Ressources).

  • DateMidnight: cette classe représente l'instant minuit d'un jour donné pour un fuseau horaire quelconque (habituellement le fuseau horaire par défaut). C'est en grande partie la même chose qu'un DateTime, excepté que la partie concernant l'heure est toujours à minuit dans la DateTimeZone associée à l'objet.

Méthodes surchargées

Si vous créez une instance de DateTime sans fournir de Chronology ou de  DateTimeZone, Joda utilise ISOChronology (la valeur par défaut) et DateTimeZone (récupérée depuis le système). Cependant, tous les constructeurs des sous-classes de ReadableInstant sont surchargés pour prendre en paramètre une Chronology ou une DateTimeZone. L'application de démonstration de l'article montre comment utiliser ces méthodes (voir les Téléchargements). Je n'en parlerai pas dans le détail parce qu'ils sont vraiment simples d'utilisation. Néanmoins, je vous encourage à jouer un peu avec l'application pour avoir une idée de la facilité avec laquelle vous pouvez, dans votre code, changer de Chronology et de DateTimeZone à la volée sans affecter le reste du code.

 

Les autres classes que l'on verra dans cet article suivent le même modèle que les classes ReadableInstant (comme le montrera un coup d'oeil même rapide à la Javadoc), ainsi il sera inutile d'en parler dans les sections suivantes.

ReadablePartial

Certaines dates avec lesquelles on travaille dans les applications ne sont pas complètement définies, et à leur place on doit manipuler des instants partiellement définis. Par exemple, parfois tout ce qui vous intéresse est l'année, le mois et le jour, ou bien l'heure, ou juste le jour de la semaine. Les concepteurs de Joda ont modélisé ce concept avec l'interface ReadablePartial, qui est un instant partiellement défini immuable. Les classes LocalDate et LocalTime sont particulèrement utiles pour travailler avec des instants partiellement définis:

  • LocalDate: Cette classe encapsule une combinaison année/mois/jour. C'est pratique pour stocker des dates quand le lieu (autrement dit le fuseau horaire) n'a pas d'importance. Par exemple, la date de naissance stockée dans un certain objet a la valeur 16 avril 1999, et toute la valeur métier réside dans cette information, sans que l'on ait besoin d'en savoir davantage sur cette date (comme le jour de la semaine ou le fuseau horaire du lieu de naissance de la personne). Dans de tels cas, utiliser LocalDateest tout indiqué.

    L'application de démonstration utilise SystemClock pour obtenir une instance de LocalDate initialisée à la date système:

    		LocalDate localDate = SystemFactory.getClock().getLocalDate();
    

    On peut aussi créer une LocalDate en fournissant explicitement les valeurs de chaque champ:

    		LocalDate localDate = new LocalDate(2009, 9, 6);// 6 septembre 2009
    

    LocalDate vient remplacer YearMonthDay, utilisée dans les versions précédentes de Joda.

  • LocalTime: Cette classe encapsule une heure donnée et est utile pour stocker une heure quand le lieu n'a pas d'importance. Par exemple, 23:52 peut représenter un moment important de la journée (disons, le démarrage d'une tâche de sauvegarde de mon système de fichiers), mais il n'est pas lié à un jour particulier et je n'ai par conséquent pas besoin d'en savoir plus sur lui.

    L'application de démonstration utilise SystemClock pour obtenir une instance de LocalTime initialisée à l'heure système:

    		LocalTime localTime = SystemFactory.getClock().getLocalTime();
    

    On peut aussi créer une LocalTime en fournissant explicitement les valeurs de chaque champ:

    		LocalTime localTime = new LocalTime(13, 30, 26, 0);// 13:30:26
    

Intervalles de temps

Déterminer un instant précis ou un instant partiellement défini est utile, mais il est souvent aussi très utile de pouvoir exprimer des intervalles de temps. Joda fournit trois classes pour faciliter ce travail. Vous avez le choix de la classe qui rend le mieux le type d'intervalle que vous voulez exprimer:

  • Duration: représente un intervalle exprimé en millisecondes. Les méthodes de la classe sont capables de le traduire en unités standard telles que secondes, minutes et heures en utilisant des règles de conversion standard (par exemple 60 secondes dans une minutes, et 24 heures par jour).

    On utilise une instance de Duration uniquement quand on souhaite exprimer un intervalle dont le début n'est pas figé, ou qu'il est plus pratique de gérer cet intervalle en millisecondes.

  • Period: représente le même concept que Duration, mais en termes "humains" comme année, mois et semaines.

    On utilise une Period quand on n'a pas besoin de préciser quand la période commence, ou peut-être quand il est plus important de pouvoir accéder aux valeurs des champs encapsulés dans la Period.

  • Interval: représente un intervalle de temps dont le début et la fin sont définis. Un Interval est semi-ouvert, ce qui veut dire que l'instant de début est inclus dans l'intervalle, mais pas l'instant final.

    On utilise un Interval quand il est important de définir les instants de début et de fin.

Manipulation du temps, façon Joda

Maintenant que vous savez instancier quelques-unes des classes les plus utiles de Joda, je vais vous montrer comment les utiliser pour faire des calculs sur les dates. Ensuite nous verrons que Joda interagit facilement avec le JDK.

Calculs de dates

Si vous aviez simplement besoin de stocker des informations de type date/heure, le JDK irait très bien, mais l'utiliser pour effectuer des calculs sur les dates/heures est pénible. C'est là que Joda brille particulièrement. Je vais vous donner quelques exemples.

Supposons que je veuille calculer le dernier jour du mois précédent la date système actuelle. Dans ce cas, je ne veux pas savoir l'heure et tout ce qui m'intéresse est l'année, le mois et le jour, comme dans le Listing 6:

Listing 6. Calculer une date avec Joda

LocalDate now = SystemFactory.getClock().getLocalDate();
LocalDate lastDayOfPreviousMonth =\
  now.minusMonths(1).dayOfMonth().withMaximumValue(); 

Vous vous posez peut-être des questions sur l'appel de dayOfMonth() du Listing 6. C'est ce que Joda appelle une propriété. Une propriété est un attribut d'un objet Joda. Son nom est lié au concept familier qu'elle représente et est utilisé pour accéder à ce concept en vue d'effectuer des calculs. Les propriétés sont la clé de la puissance de Joda pour ce qui est des calculs. Les quatre classes Joda que nous avons vues pour l'instant ont des propriétés. En voici des exemples:

  • yearOfCentury
  • dayOfYear
  • monthOfYear
  • dayOfMonth
  • dayOfWeek

Détaillons l'exemple du Listing 6 pour comprendre de quoi il retourne exactement. Premièrent, j'ôte un mois au mois actuel pour obtenir le mois précédent. Ensuite je demande à la propriété dayOfMonth sa valeur maximale, ce qui nous amène à la fin du mois. Notez que les appels s'enchainent (rappelez-vous que les sous-classes de ReadableInstant sont immuables) et qu'ainsi on a juste besoin de mémoriser le résultat du dernier appel de méthode pour obtenir le résultat du calcul entier.

Je procède souvent de cette manière quand je n'ai pas besoin des résultats intermédiaires d'un calcul. (J'utilise le BigDecimal du JDK de la même manière). Supposons que l'on désire connaitre la date du premier mardi suivant le premier lundi de novembre (de n'importe quelle année). Le Listing 7 montre comment faire:

Listing 7. Calculer de la date du premier mardi suivant le premier lundi de novembre

LocalDate now = SystemFactory.getClock().getLocalDate();
LocalDate electionDate = now.monthOfYear()
 .setCopy(11)        // novembre
 .dayOfMonth()       // Accès à la propriété 'Jour du Mois'
 .withMinimumValue() // prendre sa valeur minimum
 .plusDays(6)        // Ajouter 6 jours
 .dayOfWeek()        // Accès à la propriété 'Jour de la Semaine'
 .setCopy("Monday")  // Le positionner à lundi (arrondi à la valeur inférieure)
 .plusDays(1);       // Nous donne le mardi

Les commentaires du Listing 7 vous aideront à comprendre comment ce code calcule le résultat. La ligne .setCopy("Monday") est la clé de ce fonctionnement. Quelle que soit la valeur de la LocalDate intermédiaire, le fait de positionner sa propriété dayOfWeek à lundi va toujours faire un arrondi à la valeur inférieure, et ainsi comme on a déjà ajouté six jours au premier jour du mois, on obtiendra le premier lundi. Ajouter un jour nous donnera le premier mardi. Joda rend ce genre de calculs facile à faire.

Voici quelques calculs supplémentaires qui sont très faciles à faire en utilisant Joda:

Ce code calcule la date dans deux semaines à partir d'aujourd'hui:

DateTime now = SystemFactory.getClock().getDateTime();
DateTime then = now.plusWeeks(2);

On peut calculer 90 jours à partir de demain de cette façon:

DateTime now = SystemFactory.getClock().getDateTime();
DateTime tomorrow = now.plusDays(1);
DateTime then = tomorrow.plusDays(90);

(Oui, j'aurais pu ajouter 91 jours à , mais où aurait été le plaisir ?)

Voici comment savoir où nous en serons dans 156 secondes:

DateTime now = SystemFactory.getClock().getDateTime();
DateTime then = now.plusSeconds(156);

Et ce code calcule le dernier jour de févrieer il y a cinq ans de cela:

DateTime now = SystemFactory.getClock().getDateTime();
DateTime then = now.minusYears(5) // 5 ans en arrière
               .monthOfYear()     // récupérer la propriété monthOfYear
               .setCopy(2)        // la positionner à février
               .dayOfMonth()      // récupérer la propriété dayofmonth
               .withMaximumValue();// le dernier jour du mois

Je pourrais prendre d'autres exemples encore, mais je pense que vous avez saisi l'idée. Jouez avec l'application de démonstration pour voir par vous-mêmes comme il est amusant de calculer une date quelconque avec Joda.

Interopérabilité avec le JDK

J'ai beaucoup de code qui utilise les classes Date et Calendar du JDK. Mais grâce à Joda, je peux faire toute arithmétique nécessaire puis convertir le résultat vers des classes du JDK. C'est le meilleur des deux mondes ! Toutes les classes Joda que nous avons vues dans cet article peuvent être créées à partir d'une instance de Date ou Calendar, comme vous l'avez vu dans la section Création d'objets Joda-Time. En vertu du même principe, il est possible de créer une instance de Date ou Calendar à partir de toutes les classes Joda que nous avons étudiées.

Le Listing 8 montre qu'il est très facile de passer d'une sous-classe de ReadableInstant vers les classes du JDK:

Listing 8. Obtention d'instances de classes du JDK à partir d'une instance de DateTime

DateTime dateTime = SystemFactory.getClock().getDateTime();
Calendar calendar = dateTime.toCalendar(Locale.getDefault());
Date date = dateTime.toDate();
DateMidnight dateMidnight = SystemFactory.getClock()
  .getDateMidnight();
date = dateMidnight.toDate();

Pour les sous-classes de ReadablePartial, il faut faire une opération supplémentaire, comme le montre le Listing 9:

Listing 9. Création d'une Date représentant une LocalDate

LocalDate localDate = SystemFactory.getClock().getLocalDate();
Date date = localDate.toDateMidnight().toDate();

Pour créer un objet Date qui représente la SystemClock obtenue depuis la SystemClock comme le montre le Listing 9, il faut d'abord la convertir en un objet DateMidnight, et ensuite demander à l'objet DateMidnight son équivalent en Date. (L'objet Date résultant aura bien sûr son heure positionnée à minuit).

L'interopérabilité avec le JDK est intégrée dans l'API de Joda, il n'y a donc pas besoin de modifier vos interfaces si elles sont liées au JDK. On peut, par exemple, utiliser Joda pour faire le travail difficile et garder le JDK pour les interfaces.

Formattage de dates, façon Joda

Le formattage de dates avec le JDK est efficace, mais j'ai toujours pensé qu'il devrait être plus simple. Ici aussi, les concepteurs de Joda ont amélioré les choses. Pour formatter un objet Joda, appelez sa méthode toString() et, si vous le souhaitez, passez lui une chaine de contrôle au standard ISO-8601 ou compréhensible par le JDK pour préciser à Joda comment le formatter. Plus de création d'objets SimpleDateFormat distincts (bien que Joda fournisse une classe DateTimeFormatter pour les masochistes). Un appel à la méthode toString() et c'est fini. Je vais vous donner quelques exemples.

Le Listing 10 utilise les méthodes statiques de ISODateTimeFormat:

Listing 10. Utilisation de ISO-8601

DateTime dateTime = SystemFactory.getClock().getDateTime();
dateTime.toString(ISODateTimeFormat.basicDateTime());
dateTime.toString(ISODateTimeFormat.basicDateTimeNoMillis());
dateTime.toString(ISODateTimeFormat.basicOrdinalDateTime());
dateTime.toString(ISODateTimeFormat.basicWeekDateTime());

Les quatre appels à du Listing 10 donnent respectivement les résultats suivants:

20090906T080000.000-0500
20090906T080000-0500
2009249T080000.000-0500
2009W367T080000.000-0500

Vous pouvez aussi passer des chaines de formattage compatibles avec le SimpleDateFormat du JDK, comme dans le Listing 11:

Listing 11. Passage de chaines dans le style SimpleDateFormat

DateTime dateTime = SystemFactory.getClock().getDateTime();
dateTime.toString("MM/dd/yyyy hh:mm:ss.SSSa");
dateTime.toString("dd-MM-yyyy HH:mm:ss");
dateTime.toString("EEEE dd MMMM, yyyy HH:mm:ssa");
dateTime.toString("MM/dd/yyyy HH:mm ZZZZ");
dateTime.toString("MM/dd/yyyy HH:mm Z");

09/06/2009 02:30:00.000PM
06-Sep-2009 14:30:00
Sunday 06 September, 2009 14:30:00PM
09/06/2009 14:30 America/Chicago
09/06/2009 14:30 -0500

Consultez la Javadoc de joda.time.format.DateTimeFormat pour avoir plus d'informations sur les chaines de formattage compatibles avec SimpleDateForma qu'il est possible de passer à la méthode toString() des objets Joda.

Conclusion

Quand il s'agit de traiter des dates, Joda est un outil incroyablement efficace. Que l'on doive calculer des dates, les afficher ou les analyser, il est très pratique d'avoir Joda dans sa boite à outils. Dans cet article, j'ai montré quelle est l'utilité de Joda en tant que solution alternative à ce que propose le JDK. Ensuite nous avons examiné quelques concepts de Joda, et comment utiliser Joda dans le calcul et le formattage des dates.

Joda-Time a donné naissance à quelques projets apparentés que vous pourriez trouver utiles. Un plugin Joda-Time est désormais disponible pour Grails, le framework de développement Web. Le projet joda-time-jpox vise à ajouter les mappings nécessaire à la persistence d'objets Joda-Time dans le moteur de persistence DataNucleus. Et une implémentation de Joda-Time pour Google Web Toolkit (nommée Goda-Time) a fait quelques progrès au moment de l'écriture de cet article, mais rencontre des problèmes de license. Explorez les Ressources pour en savoir plus.