Un guide de SimpleDateFormat

1. Introduction

Dans ce didacticiel, nous allons faire une visite détaillée de la classe SimpleDateFormat .

Nous examinerons les styles d' instanciation et de formatage simples ainsi que les méthodes utiles que la classe expose pour gérer les paramètres régionaux et les fuseaux horaires .

2. Instanciation simple

Voyons d'abord comment instancier un nouvel objet SimpleDateFormat .

Il y a 4 constructeurs possibles - mais conformément au nom, gardons les choses simples. Tout ce dont nous avons besoin pour commencer est une représentation String d'un modèle de date que nous voulons .

Commençons par un modèle de date séparé par des tirets comme ceci:

"dd-MM-yyyy"

Cela formatera correctement une date commençant par le jour du mois en cours, le mois en cours de l'année et enfin l'année en cours. Nous pouvons tester notre nouveau formateur avec un simple test unitaire. Nous allons instancier un nouvel objet SimpleDateFormat et transmettre une date connue:

SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); assertEquals("24-05-1977", formatter.format(new Date(233345223232L))); 

Dans le code ci-dessus, le formateur convertit les millisecondes comme l ong en une date lisible par l'homme - le 24 mai 1977.

2.1. Méthodes d'usine

Bien que SimpleDateFormat soit une classe pratique pour créer rapidement un formateur de date, nous sommes encouragés à utiliser les méthodes de fabrique de la classe DateFormat getDateFormat () , getDateTimeFormat () , getTimeFormat () .

L'exemple ci-dessus est un peu différent lors de l'utilisation de ces méthodes d'usine:

DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT); assertEquals("5/24/77", formatter.format(new Date(233345223232L)));

Comme nous pouvons le voir ci-dessus, le nombre d'options de mise en forme est prédéterminé par les champs de la classe DateFormat . Cela limite largement nos options de formatage disponibles, c'est pourquoi nous nous en tiendrons à SimpleDateFormat dans cet article.

2.2. Fil-Sécurité

Le JavaDoc pour SimpleDateFormat indique explicitement:

Les formats de date ne sont pas synchronisés. Il est recommandé de créer des instances de format distinctes pour chaque thread. Si plusieurs threads accèdent à un format simultanément, il doit être synchronisé en externe.

Les instances SimpleDateFormat ne sont donc pas sûres pour les threads et nous devons les utiliser avec précaution dans des environnements concurrents.

La meilleure approche pour résoudre ce problèmeest de les utiliser en combinaison avec un ThreadLocal . De cette façon, chaque thread se retrouve avec sa propre instance SimpleDateFormat , et le manque de partage rend le programme thread-safe:

private final ThreadLocal formatter = ThreadLocal .withInitial(() -> new SimpleDateFormat("dd-MM-yyyy"));

L'argument de la méthode withInitial est un fournisseur d' instances SimpleDateFormat . Chaque fois que ThreadLocal a besoin de créer une instance, il utilisera ce fournisseur.

Ensuite, nous pouvons utiliser le formateur via l' instance ThreadLocal :

formatter.get().format(date)

La méthode ThreadLocal.get () initialise le SimpleDateFormat pour le thread actuel dans un premier temps, puis réutilise cette instance.

Nous appelons cette technique le confinement des threads car nous limitons l'utilisation de chaque instance à un thread spécifique.

Il existe deux autres approches pour s'attaquer au même problème:

  • Utilisation de blocs synchronisés ou ReentrantLock s
  • Création d'instances jetables de SimpleDateFormat à la demande

Ces deux approches ne sont pas recommandées: la première subit un impact significatif sur les performances lorsque la contention est élevée, et la seconde crée de nombreux objets, exerçant une pression sur le garbage collection.

Il est intéressant de mentionner que, depuis Java 8, une nouvelle classe DateTimeFormatter a été introduite . La nouvelle classe DateTimeFormatter est immuable et thread-safe. Si nous travaillons avec Java 8 ou version ultérieure, l'utilisation de la nouvelle classe DateTimeFormatter est recommandée.

3. Analyse des dates

SimpleDateFormat et DateFormat nous permettent non seulement de formater les dates, mais nous pouvons également inverser l'opération. En utilisant la méthode parse , nous pouvons entrer la représentation String d'une date et renvoyer l' équivalent de l'objet Date :

SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); Date myDate = new Date(233276400000L); Date parsedDate = formatter.parse("24-05-1977"); assertEquals(myDate.getTime(), parsedDate.getTime());

Il est important de noter ici que le modèle fourni dans le constructeur doit être au même format que la date analysée à l'aide de la méthode parse .

4. Modèles date-heure

SimpleDateFormat fournit une vaste gamme d'options différentes lors du formatage des dates. Bien que la liste complète soit disponible dans les JavaDocs, explorons certaines des options les plus couramment utilisées:

Lettre Composant de date Exemple
M Mois 12; déc
y an 94
journée 23; lun
H heure 03
m minute 57

La sortie renvoyée par le composant date dépend également fortement du nombre de caractères utilisés dans la chaîne . Par exemple, prenons le mois de juin. Si nous définissons la chaîne de date comme:

"MM"

Ensuite, notre résultat apparaîtra sous la forme du code numérique - 06. Cependant, si nous ajoutons un autre M à notre chaîne de date:

"MMM"

Ensuite, la date formatée qui en résulte apparaît sous la forme du mot Jun .

5. Application des paramètres régionaux

La classe SimpleDateFormat prend également en charge un large éventail de paramètres régionaux définis lorsque le constructeur est appelé.

Mettons cela en pratique en formatant une date en français. Nous allons instancier un objet SimpleDateFormat tout en fournissant Locale.FRANCE au constructeur.

SimpleDateFormat franceDateFormatter = new SimpleDateFormat("EEEEE dd-MMMMMMM-yyyy", Locale.FRANCE); Date myWednesday = new Date(1539341312904L); assertTrue(franceDateFormatter.format(myWednesday).startsWith("vendredi"));

En fournissant une date donnée, un mercredi après-midi, nous pouvons affirmer que notre franceDateFormatter a correctement formaté la date. La nouvelle date commence correctement par Vendredi -Français pour mercredi!

Il convient de noter un petit problème dans la version Locale du constructeur - alors que de nombreux paramètres régionaux sont pris en charge, une couverture complète n'est pas garantie . Oracle recommande d'utiliser les méthodes de fabrique sur la classe DateFormat pour garantir la couverture des paramètres régionaux.

6. Modification des fuseaux horaires

Puisque SimpleDateFormat étend la classe DateFormat , nous pouvons également manipuler le fuseau horaire à l'aide de la méthode setTimeZone . Jetons un coup d'œil à cela en action:

Date now = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEEE dd-MMM-yy HH:mm:ssZ"); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Europe/London")); logger.info(simpleDateFormat.format(now)); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("America/New_York")); logger.info(simpleDateFormat.format(now));

In the above example, we supply the same Date to two different time zones on the same SimpleDateFormat object. We've also added the ‘Z' character to the end of the pattern String to indicate the time zone differences. The output from the format method is then logged for the user.

Hitting run, we can see the current times relative to the two time zones:

INFO: Friday 12-Oct-18 12:46:14+0100 INFO: Friday 12-Oct-18 07:46:14-0400

7. Summary

In this tutorial, we've taken a deep dive into the intricacies of SimpleDateFormat.

We've looked at how to instantiate SimpleDateFormat as well as how the pattern String impacts how the date is formatted.

Nous avons joué avec le changement des paramètres régionaux de la chaîne de sortie avant de finalement expérimenter l' utilisation des fuseaux horaires .

Comme toujours, le code source complet peut être trouvé sur GitHub.