Developpez.com

Télécharger gratuitement le magazine des développeurs, le bimestriel des développeurs avec une sélection des meilleurs tutoriels

FAQ Langage JavaConsultez toutes les FAQ

Nombre d'auteurs : 41, nombre de questions : 294, dernière mise à jour : 21 mars 2016  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur le forum Java de http://java.developpez.com ainsi que l'expérience personnelle des auteurs.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant rédacteur, lisez ceci.

Sur ce, nous vous souhaitons une bonne lecture.


SommaireDates (17)
précédent sommaire suivant
 

Il existe plusieurs API pour gérer le temps correctement en Java suivant vos besoins (financier, scientifique, etc.). Nous allons vous présenter ici les plus couramment utilisées :

API classique Date-Time
Cette API est disponible dans presque toutes les versions de Java : la classe java.util.Date a fait son apparition dès le JDK 1.0 tandis que son complément, la classe java.util.Calendar (et ses classes dérivées et associées telles que java.util.TimeZone pour la gestion des fuseaux horaires) est apparue dans le JDK 1.1. Ces classes offrent une gestion du temps basique et, compte tenu de leur ancienneté, contiennent nombre de méthodes dépréciées. Elles sont parfois contre-intuitives à l’utilisation.

Joda-Time
Cette bibliothèque tierce a été développée par Stephen Colebourne pour pallier les défauts et les manques de l'API de gestion du temps incluse du JDK. Il est fortement conseillé de l'utiliser pour toutes les versions de Java antérieures au JDK 8 en remplacement de l'API classique Date-Time. À ce jour (07/2015), la dernière version de Joda-Time requiert au minimum le JDK 5 pour être utilisée.

API java.time
Cette nouvelle API est apparue avec le JDK 8 grâce au projet JSR 310: Date and Time API. Elle est fortement inspirée par Joda-Time ; en effet elle a tout simplement été conçue par le créateur de Joda-Time auquel Oracle a fait appel lorsqu'est venu le temps de repenser l'API de gestion du temps incluse dans le JDK. Cette API n'est cependant pas complètement identique, et ce, pour éviter certains défauts dans la conception initiale de Joda-Time. Des méthodes pont ont été rajoutées aux classes de l'API classique Date-Time pour permettre de convertir ces valeurs en valeurs utilisables par l'API java.time.

Dans les exemples qui suivent, nous nous attacherons à chaque fois à vous présenter les solutions existantes tant pour l'API classique Date-Time que pour la nouvelle API java.time.

Mis à jour le 21 juillet 2015 bouye

Tout d'abord il convient bien de distinguer la notion de date qui représente une date au sens du calendrier (par exemple : 3 avril 2006) et de temps qui correspond le plus souvent à une « heure » dans une journée (par exemple : 15:25:45). Ainsi quand on parle de date Java, il serait plus correct de parler d'instant qui représente un moment sur une ligne temporelle. Et il faut ajouter également une notion de fuseau horaire, de changement d'heure pour des questions d’économie d’énergie, etc. qui permet d'exprimer cet instant dans une valeur humainement compréhensible. Il existe plusieurs manières de représenter un instant en Java :

Nombre
Il est assez courant de représenter un instant sous la forme d'un long qui contient le nombre de millisecondes depuis une date d'origine. Ainsi la méthode System.currentTimeMillis() retourne une date en nombre de millisecondes depuis le 1er janvier 1970 à 00:00:00 GMT ; tandis que la méthode System.nanoTime() retourne une date en nombre de nanosecondes depuis une origine arbitraire (cette seconde méthode est surtout utilisée pour calculer des durées).

Code Java : Sélectionner tout
long maintenant = System.currentTimeMillis();

Attention, cependant le temps retourné par ces méthodes est un temps machine qui ne prend pas en compte des spécificités du temps universel (secondes supplémentaires, etc.).

API classique Date-Time
La classe java.util.Date, présente depuis le JDK 1.0, permet de représenter un instant dans un système de calendrier. Il est possible de l'initialiser avec un nombre de millisecondes ou via une instance de la classe java.util.Calendar ou encore par un formateur de dates.

Code Java : Sélectionner tout
1
2
Date maintenant1 = new Date(System.currentTimeMillis()); 
Date maintenant2 = Calendar.getInstance().getTime();

Attention cette classe est mutable, il est donc possible de changer la valeur qu'elle définit.

java.sql.Date
Cette classe, qui hérite de java.util.Date, permet d'utiliser des dates qui peuvent être utilisées avec des requêtes JDBC sur des bases de données SQL en tant que type SQL DATE. De ce fait, ces dates sont normalisées, c'est-à-dire que les heures, minutes, secondes et millisecondes stockées sont toutes mises à zéro lors de la création de l'instant.

Avertissement : cette classe est souvent source de confusion avec sa classe mère.

API java.time
À partir du JDK 8, il existe plusieurs classes pour représenter un instant, une date ou un temps. On peut citer par exemple :
  • java.time.Instant - représente un instant donné ;
  • java.time.LocalDate - représente une date sans notion de fuseau horaire (ex. : le 26 octobre 1984, une date d'anniversaire) ;
  • java.time.LocalTime - représente un temps sans notion de fuseau horaire. (ex. : 15:17, l'heure d'un rendez-vous) ;
  • java.time.LocalDateTime - représente une date + temps sans notion de fuseau horaire (ex. : le 22 mars 2012 à 12:30, le jour et l'heure d'un événement) ;
  • java.time.ZonedDateTime - représente une date + temps tout en conservant la notion de fuseau horaire nommé (ex. : le 7 novembre 1963 à 22:48, heure de Europe/Paris) ;
  • java.time.OffsetTime - représente un temps décalé par rapport au fuseau horaire de référence GMT/Greenwich (ex. : 09:25 GTM+02:00) ;
  • java.time.OffsetDateTime - représente une date + temps décalé par rapport au fuseau horaire de référence GMT/Greenwich (ex. : le 22 mars 2012 à 12:30 GTM-05:00).


Code Java : Sélectionner tout
1
2
3
4
5
Instant maintenant = Instant.now(); 
LocalDateTime maintenantIci = LocalDateTime.ofInstant(maintenant, ZoneId.systemDefault()); // L'instant retourné est exprimé dans votre fuseau horaire. 
ZonedDateTime maintenantParis = maintenant.atZone(ZoneId.of("Europe/Paris")); // L'instant retourné est exprimé dans le fuseau horaire de la ville de Paris. 
LocalDate date1 = LocalDate.of(1983, Month.MARCH, 28); 
LocalDate date2 = LocalDate.of(1983, 3, 28); // La même date.

Il existe d'autres classes d'emplois plus spécialisés dans l'API java.time pour gérer des dates :

  • java.time.DayOfWeek - enum qui représente un jour de la semaine (ex. : mercredi) ;
  • java.time.Month - enum qui représente un mois de l’année (ex. : septembre) ;
  • java.time.MonthDay - représente un couple mois + jour, indépendamment de l’année (ex. : le 15 avril) ;
  • java.time.Year - représente une année (ex. : 1998) ;
  • java.time.YearMonth - représente un couple année + mois ( ex. : mars 2007).


Ces classes sont immuables et toute opération de modification retourne en fait une nouvelle instance de la classe.

Mis à jour le 21 juillet 2015 bouye

Attention, lorsque vous définissez des dates en utilisant l'API classique Date-Time via la classe Calendar, la valeur du mois de janvier est 0 et non pas 1 ! Ceci est une source courante d'erreurs et de frustrations.

Code Java : Sélectionner tout
1
2
3
Calendar calendrier = Calendar.getInstance();  
calendrier.set(2010, 1, 1); // Erreur: ceci est le 1er février !!!!!!!! 
calendrier.set(2010, 0, 1); // Ceci est le 1er janvier !

De manière similaire, lorsque vous récupérez le mois courant dans le calendrier, il faut penser à ajouter 1 pour faire vos calculs ou affichages :

Code Java : Sélectionner tout
int mois = calendier.get(Calendar.MONTH) + 1; // Car janvier = 0 !

Attention également : dans la nouvelle API java.time, lorsque vous devez utiliser des valeurs numériques, le mois de janvier vaut 1 et non pas 0 !

Code Java : Sélectionner tout
1
2
LocalDate date = LocalDate.of(2010, 0, 1); // Erreur : ceci lève une DateTimeException ! 
LocalDate date = LocalDate.of(2010, 1, 1); // Ceci est le 1er janvier !

Mis à jour le 23 juillet 2015 bouye

La durée représente le nombre de secondes, millisecondes ou nanosecondes entre deux temps. Il existe plusieurs manières de représenter des durées en Java :

Nombres
De manière traditionnelle, en Java, les durées sont souvent représentées sous la forme de nombres de type int ou long qui contiennent un nombre de secondes, millisecondes ou de nanosecondes. Ainsi, la méthode System.currentTimeMillis(), qui retourne une date en nombre de millisecondes depuis le 1er janvier 1970, est souvent utilisée pour faire des calculs de durée d’exécution.

Par exemple :

Code Java : Sélectionner tout
1
2
3
4
long debut = System.currentTimeMillis(); 
// Traitement. 
long fin = System.currentTimeMillis(); 
long duree = fin - debut; // Durée du traitement en millisecondes.

À noter toutefois que la valeur retournée par l'appel à System.currentTimeMillis() a une granularité qui dépend de celle du système d'exploitation sous-jacent,

De la même manière, System.nanoTime() retourne une date en nanosecondes depuis une origine arbitraire, mais en utilisant une granularité qui peut être plus fine (mais pas obligatoirement), peut être également utilisée à cet effet :

Code Java : Sélectionner tout
1
2
3
4
long debut = System.nanoTime(); 
// Traitement. 
long fin = System.nanoTime(); 
long duree = fin - debut; // Durée du traitement en nanosecondes.

API java.time
Depuis le JDK 8, il est possible d'utiliser la classe java.time.Duration pour représenter une durée en secondes, mais avec une précision de l'ordre de la nanoseconde. Cette classe stocke en effet deux valeurs sous forme de long : le nombre de secondes et le nombre de nanosecondes sous la seconde.

On peut donc désormais écrire :

Code Java : Sélectionner tout
1
2
3
4
long debut = System.nanoTime(); 
// Traitement. 
long fin = System.nanoTime(); 
Duration duree = Duration.ofNanos(fin - debut); // Durée du traitement en nanosecondes.

Les durées stockées sont, de plus immuables, et il n'est pas possible de les modifier après leur création. La classe Duration met cependant à disposition des méthodes prêtes à l'emploi permettant de faire des opérations sur les durées.

Par exemple :

Code Java : Sélectionner tout
1
2
3
Duration duree = Duration.ofMinutes(5) 
    .plusDays(5) 
    .plusHours(2);

Ici, chaque opération provoque la création d'une nouvelle instance de la classe.

Attention : une durée d'une journée fait exactement 24 heures. La durée ne tient pas compte du fuseau horaire ou du passage à l'heure d’économie d’énergie.

Mis à jour le 21 juillet 2015 bouye

Une période définit la durée entre deux dates en années, mois et jours. De telles périodes peuvent être, par exemple, utilisées pour planifier des rendez-vous dans un emploi du temps ou encore calculer le nombre de jours restant jusqu’à une date anniversaire dans un calendrier.

API java.time
Depuis le JDK 8, il est possible de représenter des périodes entre deux dates dans un calendrier grâce à la classe java.time.Period. Cette classe permet de définir des périodes qui prennent en compte le changement d'heure pour l’économie d’énergie ou encore des temps locaux spécifiques dus aux fuseaux horaires.

Par exemple, pour calculer le nombre de jours d'ici à votre prochain anniversaire :

Code Java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
LocalDate aujourdhui = LocalDate.now(); 
LocalDate anniversaire = LocalDate.of(1976, Month.SEPTEMBER, 7); 
LocalDate prochainAnniversaire = anniversaire.withYear(aujourdhui.getYear()); 
// Si l'anniversaire a déjà eu lieu cette année, on rajoute 1 an à la date. 
if (prochainAnniversaire.isBefore(aujourdhui) || prochainAnniversaire.isEqual(aujourdhui)) { 
    prochainAnniversaire = prochainAnniversaire.plusYears(1); 
} 
Period periode = Period.between(aujourdhui, prochainAnniversaire); // Période entre les deux indicateurs temporels. 
long nbJours = ChronoUnit.DAYS.between(aujourdhui, prochainAnniversaire); // Nombre exact de jours entre les deux indicateurs temporels. 
System.out.printf("Votre prochain anniversaire sera dans %d mois et %d jour(s) (%d jour(s) au total)", periode.getMonths(), periode.getDays(), nbJours).println();

Ici, nous utilisons des instances de la classe LocalDate qui ne conservent pas d'information sur le fuseau horaire. Mais si vous êtes nés dans un fuseau horaire différent de celui dans lequel vous vivez, votre calcul sera plus exact en utilisant des instances de ZonedDateTime pour le calcul de la période.

Attention : une période d'une journée tient compte des modifications du calendrier comme le changement d'heure pour l’économie d’énergie.

Mis à jour le 22 juillet 2015 bouye

Il existe plusieurs systèmes de calendrier à travers le monde : le calendrier grégorien utilisé dans le monde occidental, mais également le calendrier julien (orthodoxe), copte, hébreu, musulman, chinois, japonais impérial, etc. sans parler de calendriers passés utilisés par des civilisations désormais éteintes comme le calendrier maya, ou même des systèmes abandonnés tels que le calendrier républicain, etc. Ces systèmes différents ont tous des concepts différents sur le début de l’année, le nombre de mois dans une année, le nombre de jours dans un mois ou encore le nombre de jours dans une semaine ou le premier jour de la semaine. Il existe plusieurs manières de manipuler des systèmes de calendrier dans Java :

API classique Date-Time
Depuis le JDK 1.1, la classe abstraite java.util.Calendar définit des méthodes génériques d’accès et de gestion de calendriers. La classe java.util.GregorianCalendar représente la seule implémentation concrète de cette classe fournie avec le JDK. Elle implémente le calendrier grégorien proleptique.

Code Java : Sélectionner tout
Calendar calendrier = Calendar.getInstance(); // Retourne un calendrier grégorien proleptique.

À partir du JDK 8, la liste complète des calendriers supportés par le JDK est accessible en invoquant la méthode Calendar.getAvailableCalendarTypes(). Il est possible d'utiliser le calendrier impérial japonais ou le calendrier thaï bouddhiste qui reposent tous deux sur le calendrier grégorien en utilisant la classe Calendar.Builder.

Code Java : Sélectionner tout
1
2
3
4
Calendar calendrierImperial = new Calendar.Builder() 
    .setCalendarType("japanese") 
    .setFields(YEAR, 1, DAY_OF_YEAR, 1) 
    .build();

Pour utiliser d'autres types de calendriers, vous devrez vous reposer sur des bibliothèques tierces compatibles avec l'API Calendar.

API java.time
Par défaut, les instants et dates créés avec l'API java.time incluse dans le JDK 8 sont au format ISO-8601, c'est-à-dire de facto dans un calendrier grégorien proleptique. D'ailleurs, la plupart des classes de base de cette API ne se réfèrent pas à une classe centrale permettant de manipuler le calendrier comme peut le faire la gestion classique des dates avec la classe Calendar.

Cependant, le package java.time.chrono contient des classes qui permettent d'utiliser des instants et dates de manière plus neutre et indépendamment du calendrier ISO. Cette API fournit l’implémentation de plusieurs « chronologies » pour supporter divers calendriers tels que le calendrier ISO (le calendrier utilisé par défaut par l'API java.time), le calendrier musulman, le calendrier japonais impérial (ères Meiji 6 et ultérieures), le calendrier chinois de Taïwan, et le calendrier thaï bouddhiste :

Code Java : Sélectionner tout
1
2
Locale locale = Locale.forLanguageTag("en-US-u-ca-islamic-umalqura"); 
Chronology chrono = Chronology.ofLocale(locale);

La liste complète des chronologies supportées par le JDK est accessible en invoquant la méthode Chronology.getAvailableChronologies().

Pour utiliser d'autres types de chronologies, vous devrez vous reposer sur des bibliothèques tierces compatibles avec l'API Chronology.

Mis à jour le 21 juillet 2015 bouye

La conversion d'une Date en String est délicate au premier abord. En effet, le format des dates est très différent d'une langue à l'autre. Heureusement, les fonctions d'internationalisation de Java vont faire le travail à notre place.

API classique Date-Time
Dans l'API classique, cette conversion se fait grâce à la classe abstraite java.text.DateFormat.

Code java : Sélectionner tout
1
2
3
4
5
Locale locale = Locale.getDefault(); // Langue actuelle. 
DateFormat dateFormat1 = DateFormat.getDateInstance(DateFormat.FULL, locale); 
System.out.println(dateFormat1.format(maDate)); // Ex. : lundi 1 janvier 2002 
DateFormat dateFormat2 = DateFormat.getDateInstance(DateFormat.SHORT , locale); 
System.out.println(dateFormat2.format(maDate)); // Ex. : 01/01/2002

Si vous souhaitez utiliser un format de sortie plus exotique, vous pouvez accéder directement à la classe java.text.SimpleDateFormat.

Code java : Sélectionner tout
1
2
DateFormat dateFormat3 = new SimpleDateFormat("hh'h'mm dd-MM-yy"); 
System.out.println(dateFormat2.format(maDate)); // Ex. : "23h59 31-12-2000"

La javadoc de la classe java.text.SimpleDateFormat décrit le format d'une date, et des lettres à utiliser pour caractériser le jour, le mois, etc.

API java.time
Les classes permettant de gérer des dates disposent de la méthode format() acceptant une instance de la classe java.time.format.DateTimeFormatter qui se chargera de convertir la date reçue.

Code Java : Sélectionner tout
1
2
String value1 = LocalDate.format(DateTimeFormatter.ISO_LOCAL_DATE); 
String value2 = LocalDate.format(DateTimeFormatter.ofPattern("d MMM yyyy"));

La javadoc de la classe java.time.format.DateTimeFormatte décrit le format d'une date, et des lettres à utiliser pour caractériser le jour, le mois, etc.

java.util.Formatter
La classe java.util.Formatter ainsi que les classes et méthodes apparentées (String.format(), PrintStream.printf()) permettent de formater des dates et temps qui proviennent des API classiques Date-Time ou de la nouvelle API java.time. Ainsi, il est possible de faire :

Code Java : Sélectionner tout
1
2
System.out.printf("%tT", calendar.getTime()).println(); // Affiche l'heure en utilisant l'API classique Date-Time. 
System.out.printf("%tT", LocalTime.now()).println(); // Affiche l'heure en utilisant l'API java.time.

La javadoc de la classe java.util.Formatter décrit le format d'une date, et des lettres à utiliser pour caractériser le jour, le mois, etc.

java.text.MessageFormat
La classe java.text.MessageFormat permet de formater des dates qui proviennent de l'API classique Date-Time. Par contre, les dates provenant de l'API java.time ne sont pas supportées.

Code Java : Sélectionner tout
System.out.println(MessageFormat.format("{0, time}", calendar.getTime()));  // Affiche l'heure en utilisant l'API classique Date-Time.

La javadoc de la classe java.text.MessageFormat décrit le format d'une date, et des lettres à utiliser pour caractériser le jour, le mois, etc.

Mis à jour le 22 juillet 2015 bouye

De la même manière, convertir une chaîne de caractères en date dépend fortement à la fois du format et de la langue utilisée :

API classique Date-Time
Depuis le JDK 1.1, pour convertir une instance de String en Date, il faut connaître le format de la date. Par défaut, une seule classe dans l'API gère les formats de date : la classe java.text.SimpleDateFormat. On utilise le parser de date pour effectuer la conversion. Voici une méthode générique :

Code java : Sélectionner tout
1
2
3
4
public static Date stringToDate(String sDate, String sFormat) throws Exception { 
    SimpleDateFormat sdf = new SimpleDateFormat(sFormat); 
    return sdf.parse(sDate); 
}

Le parser déclenche une exception de type java.text.ParseException quand la chaîne ne respecte pas le format. La javadoc de la classe java.text.SimpleDateFormat décrit le format d'une date, et des lettres à utiliser pour caractériser le jour, le mois,etc.

API java.time
Les classes permettant de gérer des dates disposent de plusieurs variantes de la méthode parse() acceptant une chaîne de caractères au format ISO ou une chaîne quelconque accompagnée d'une instance de la classe java.time.format.DateTimeFormatter qui se chargera de parser la chaîne reçue.

Code Java : Sélectionner tout
1
2
3
LocalDate date1 = LocalDate.parse("1959-07-09"); // Date au format ISO (équivalent à DateTimeFormatter.ISO_LOCAL_DATE). 
LocalDate date2 = LocalDate.parse("19590709", DateTimeFormatter.BASIC_ISO_DATE); // Date au format basic ISO. 
LocalDate date3 = LocalDate.parse(sDate, DateTimeFormatter.ofPattern(sFormat)); // Date avec un format personnalisé.

Le formateur déclenche une exception de type java.time.format.DateTimeParseException quand la chaîne ne respecte pas le format. La javadoc de la classe java.time.format.DateTimeFormatte décrit le format d'une date, et des lettres à utiliser pour caractériser le jour, le mois, etc.

Mis à jour le 22 juillet 2015 bouye

API classique Date-Time
La méthode getDisplayName() de la classe Calendar permet d'obtenir le nom, l’abréviation ou l'initiale du jour de la semaine en question en fonction d'un style et d'une Locale correspondant à la langue désirée.

Code Java : Sélectionner tout
1
2
3
4
5
6
System.out.println(calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.NARROW_FORMAT, Locale.FRENCH)); // Affiche "L". 
System.out.println(calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.FRENCH)); // Affiche "lun." (avec un 'l' minuscule et un '.' à la fin). 
System.out.println(calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.FRENCH)); // Affiche "lundi" (avec un 'l' minuscule). 
System.out.println(calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.NARROW_FORMAT, Locale.US)); // Affiche "M". 
System.out.println(calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.US)); // Affiche "Mon". 
System.out.println(calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US)); // Affiche "Monday".

Il est également possible d'utiliser la classe java.text.SimpleDateFormat pour récupérer le nom du jour de la semaine dans une langue spécifique :

Code Java : Sélectionner tout
1
2
3
String value1 = new SimpleDateFormat("E").format(date);  // Nom court. 
String value2 = new SimpleDateFormat("EEE").format(date);  // Nom abrégé. 
String value3 = new SimpleDateFormat("EEEE").format(date); // Nom long.

API java.time
À partir du JDK 8, il est possible d'utiliser l'enum java.time.DayOfWeek qui définit des constantes pour chacun des sept jours de la semaine. Il est possible d'obtenir le nom, l’abréviation ou l'initiale du jour de la semaine en question en invoquant la méthode getDisplayName() de cette classe et en fournissant en paramètre une instance de la classe java.time.format.TextStyle définissant le style désiré ainsi que la Locale correspondant à la langue désirée.

Code Java : Sélectionner tout
1
2
3
4
5
6
7
DayOfWeek lundi = DayOfWeek.MONDAY; 
System.out.println(lundi.getDisplayName(TextStyle.NARROW, Locale.FRENCH)); // Affiche "L". 
System.out.println(lundi.getDisplayName(TextStyle.SHORT, Locale.FRENCH));  // Affiche "lun." (avec un 'l' minuscule et un '.' à la fin). 
System.out.println(lundi.getDisplayName(TextStyle.FULL, Locale.FRENCH)); // Affiche "lundi" (avec un 'l' minuscule). 
System.out.println(lundi.getDisplayName(TextStyle.NARROW, Locale.US)); // Affiche "M". 
System.out.println(lundi.getDisplayName(TextStyle.SHORT, Locale.US)); // Affiche "Mon". 
System.out.println(lundi.getDisplayName(TextStyle.FULL, Locale.US)); // Affiche "Monday".

Mis à jour le 22 juillet 2015 bouye

API classique Date-Time
La méthode getDisplayName() de la classe Calendar permet d'obtenir le nom, l’abréviation ou l'initiale du mois en question en fonction d'un style et d'une Locale correspondant à la langue désirée.

Code Java : Sélectionner tout
1
2
3
4
5
6
System.out.println(calendar.getDisplayName(Calendar.MONTH, Calendar.NARROW_FORMAT, Locale.FRENCH)); // Affiche "F". 
System.out.println(calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.FRENCH)); // Affiche "févr." (avec un 'f' minuscule et un '.' à la fin).  
System.out.println(calendar.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.FRENCH)); // Affiche "février" (avec un 'f' minuscule). 
System.out.println(calendar.getDisplayName(Calendar.MONTH, Calendar.NARROW_FORMAT, Locale.US)); // Affiche "F". 
System.out.println(calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.US)); // Affiche "Feb". 
System.out.println(calendar.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.US)); // Affiche "February".

Il est également d'utiliser la classe java.text.SimpleDateFormat pour récupérer le nom des mois de l’année dans une langue spécifique :

Code Java : Sélectionner tout
1
2
3
String value1 = new SimpleDateFormat("M").format(date);  // Nom court. 
String value2 = new SimpleDateFormat("MM").format(date);  // Nom abrégé. 
String value3 = new SimpleDateFormat("MMMM").format(date); // Nom long.

API java.time
À partir du JDK 8, il est possible d'utiliser l'enum java.time.Month qui définit des constantes pour chacun des douze mois de l’année. Il est possible d'obtenir le nom, l’abréviation ou l'initiale du mois en question en invoquant la méthode getDisplayName() de cette classe et en fournissant en paramètre une instance de la classe java.time.format.TextStyle définissant le style désiré ainsi que la Locale correspondant à la langue désirée.

Code Java : Sélectionner tout
1
2
3
4
5
6
7
Month fevrier = Month.FEBRUARY; 
System.out.println(fevrier.getDisplayName(TextStyle.NARROW, Locale.FRENCH)); // Affiche "F". 
System.out.println(fevrier.getDisplayName(TextStyle.SHORT, Locale.FRENCH)); // Affiche "févr." (avec un 'f' minuscule et un '.' à la fin).  
System.out.println(fevrier.getDisplayName(TextStyle.FULL, Locale.FRENCH)); // Affiche "février" (avec un 'f' minuscule). 
System.out.println(fevrier.getDisplayName(TextStyle.NARROW, Locale.US)); // Affiche "F". 
System.out.println(fevrier.getDisplayName(TextStyle.SHORT, Locale.US)); // Affiche "Feb". 
System.out.println(fevrier.getDisplayName(TextStyle.FULL, Locale.US)); // Affiche "February".

Mis à jour le 22 juillet 2015 bouye

Il arrive parfois qu'une année soit bissextile et contienne un jour de plus durant le mois de février ce qui peut fausser des calculs.

API classique Date-Time
Pour déterminer si une année est bissextile, vous pouvez invoquer la méthode isLeapYear() sur une instance de la classe java.util.GregorianCalendar et en lui passant en paramètre l’année à tester . Cette méthode retourne true si le test réussit et false dans le cas contraire.

Code Java : Sélectionner tout
1
2
boolean anneeBissextile = new GregorianCalendar() 
    .isLeapYear(2012); // Vaut true.

API java.time
À partir du JDK 8, pour déterminer si une année est bissextile, vous pouvez invoquer la méthode isLeap() sur une instance de la classe java.time.Year. Cette méthode retourne true si le test réussit et false dans le cas contraire.

Code Java : Sélectionner tout
1
2
boolean anneeBissextile = Year.of(2012) 
    .isLeap(); // Vaut true.

Mis à jour le 22 juillet 2015 bouye

Compte tenu de l'existence des années bissextiles, certains couples mois + jour, de type java.util.MonthDay peuvent ne pas être valides d'une année à une autre.

API java.time
À partir du JDK 8, il est possible de vérifier si ces dates sont valides en invoquant leur méthode isValidYear() et en passant en paramètre l’année à tester. Cette méthode retourne true si le test réussit et false dans le cas contraire.

Code Java : Sélectionner tout
1
2
MonthDay date = MonthDay.of(Month.FEBRUARY, 29); 
boolean jourValide = date.isValidYear(2010); // Vaut false.

Mis à jour le 22 juillet 2015 bouye

Le nombre de jours du mois de février peut être variable d'une année à une autre si l’une de ces années est bissextile ou pas. De plus, il est toujours préférable de ne pas se reposer sur des constantes « écrites en dur » dans le programme.

API classique Date-Time
Il est possible d'invoquer la méthode getActualMaximum() de la classe java.util.Calendar et en lui passant en paramètre la valeur Calendar.DAY_OF_MONTH pour connaître le nombre de jours maximum du mois courant de l’année courante du calendrier.

Code Java : Sélectionner tout
1
2
3
4
5
6
Calendar calendar = Calendar.getInstance(); 
calendar.set(Calendar.YEAR, 2010); 
calendar.set(Calendar.MONTH, Calendar.FEBRUARY); 
int jours1 = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); // Vaut 28 
calendar.set(Calendar.YEAR, 2012); 
int jours2 = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); // Vaut 29

API java.time
À partir du JDK 8, il est possible de connaitre le nombre de jours dans un mois en invoquant la méthode lengthOfMonth() d'un couple année + mois contenu dans un objet de type java.time.YearMonth. Ce résultat tient compte des années bissextiles.

Code Java : Sélectionner tout
1
2
3
4
YearMonth date1 = YearMonth.of(2010, Month.FEBRUARY); 
System.out.printf("%s: %d", date1, date1.lengthOfMonth()).println(); // Affiche "2010-02: 28". 
YearMonth date2 = YearMonth.of(2012, Month.FEBRUARY); 
System.out.printf("%s: %d", date2, date2.lengthOfMonth()).println(); // Affiche "2012-02: 29".

Mis à jour le 22 juillet 2015 bouye

API java.time
À partir du JDK 8, la nouvelle API permet de faire très facilement des opérations sur les dates, le temps et les instants. Chaque classe de date dispose d’opérandes permettant de composer de nouvelles valeurs ou de convertir d'un type vers un autre en utilisant une syntaxe fluent.

Code Java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
LocalDate aujourdhui = LocalDate.now(); 
LocalDate demain = aujourdhui.plusDays(1); 
LocalDate hier = aujourdhui.minusDays(1); 
LocalDate dansUnMois = aujourdhui.plusMonths(1); // Calcule correctement les jours du mois. 
System.out.println(aujourdhui); 
System.out.println(demain); 
System.out.println(hier); 
System.out.println(dansUnMois); 
LocalDateTime maintenant = LocalDateTime.now(); 
LocalDateTime avant = maintenant.minusHours(4) 
        .plusMinutes(30) 
        .minusWeeks(7); 
System.out.println(maintenant); 
System.out.println(avant);

L'API calcule correctement la notion humaine d’année ou de mois pour retourner le résultat attendu :

Code Java : Sélectionner tout
1
2
3
4
LocalDate date1 = LocalDate.of(2012, Month.JANUARY, 31); // 31 janvier 2012. 
LocalDate date2 = date1.plusMonths(1); // 29 février 2012 (année bissextile). 
LocalDate date3 = date1.plusMonths(2); // 31 mars 2012. 
LocalDate date4 = date1.plusMonths(3); // 30 avril 2012.

Attention : les classes de l'API étant immuables, chaque opération entraîne la construction d'un nouvel objet.

Mis à jour le 23 juillet 2015 bouye

API classique Date-Time
Il faut effectuer un calcul assez fastidieux entre deux calendriers mis aux dates correctes :

Code Java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Date naissance = new SimpleDateFormat("yyyy-MM-dd").parse("1976-09-07"); 
int annees = 0; 
int mois = 0; 
int jours = 0; 
// Calendrier pour la naissance. 
Calendar calendrierNaissance = Calendar.getInstance(); 
calendrierNaissance.setTimeInMillis(naissance.getTime()); 
// Calendrier pour le jour courant. 
long maintenant = System.currentTimeMillis(); 
Calendar calendrierMaintenant = Calendar.getInstance(); 
calendrierMaintenant.setTimeInMillis(maintenant); 
// Calcul du nombre d’années. 
annees = calendrierMaintenant.get(Calendar.YEAR) - calendrierNaissance.get(Calendar.YEAR); 
int moisMaintenant = calendrierMaintenant.get(Calendar.MONTH) + 1; 
int moisNaissance = calendrierNaissance.get(Calendar.MONTH) + 1; 
// Calcul du nombre de mois. 
mois = moisMaintenant - moisNaissance; 
// Si la différence est négative, réduire l’année de 1 et calculer le nombre de mois. 
if (mois < 0) { 
    annees--; 
    mois = 12 - moisNaissance + moisMaintenant; 
    if (calendrierMaintenant.get(Calendar.DATE) < calendrierNaissance.get(Calendar.DATE)) { 
        mois--; 
    } 
} else if (mois == 0 && calendrierMaintenant.get(Calendar.DATE) < calendrierNaissance.get(Calendar.DATE)) { 
    annees--; 
    mois = 11; 
} 
// Calcul du nombre de jours. 
if (calendrierMaintenant.get(Calendar.DATE) > calendrierNaissance.get(Calendar.DATE)) { 
    jours = calendrierMaintenant.get(Calendar.DATE) - calendrierNaissance.get(Calendar.DATE); 
} else if (calendrierMaintenant.get(Calendar.DATE) < calendrierNaissance.get(Calendar.DATE)) { 
    int aujourdhui = calendrierMaintenant.get(Calendar.DAY_OF_MONTH); 
    calendrierMaintenant.add(Calendar.MONTH, -1); 
    jours = calendrierMaintenant.getActualMaximum(Calendar.DAY_OF_MONTH) - calendrierNaissance.get(Calendar.DAY_OF_MONTH) + aujourdhui; 
} else { 
    jours = 0; 
    if (mois == 12) { 
        annees++; 
        mois = 0; 
    } 
} 
System.out.printf("Vous avez %d an(s) (%1$d an(s) %2$d mois %3$d jour(s)) ", annees, mois, jours).println();

API java.time
À partir du JDK 8, pour calculer votre âge, il suffit de calculer une Period entre votre date de naissance et la date du jour.

Code Java : Sélectionner tout
1
2
3
4
LocalDate aujourdhui = LocalDate.now(); 
LocalDate naissance = LocalDate.of(1976, Month.SEPTEMBER, 7); 
Period periode = Period.between(naissance, aujourdhui); 
System.out.printf("Vous avez %d an(s) (%1$d an(s) %2$d mois %3$d jour(s)) ", periode.getYears(), periode.getMonths(), periode.getDays()).println();

Mis à jour le 23 juillet 2015 bouye

API classique Date-Time
Pour connaître la liste des identifiants des fuseaux horaires, vous devez invoquer la méthode statique getAvailableIDs() de la classe java.util.TimeZone. Cette méthode retourne une instance de String[].

Code Java : Sélectionner tout
String[] idFuseauxHoraires = TimeZone.getAvailableIDs();

API java.time
Pour connaitre la liste des identifiants des fuseaux horaires, vous devez invoquer la méthode statique getAvailableZoneIds() de la classe java.time.ZoneId. Cette méthode retourne une instance de Set<String> modifiable et non ordonnée qui est une copie de la définition interne.

Code Java : Sélectionner tout
Set<String> idFuseauxHoraires = ZoneId.getAvailableZoneIds();

Mis à jour le 23 juillet 2015 bouye

La gestion des fuseaux horaires devient importante lorsque vous devez interagir avec des dates relevées à divers lieux de la planète et qui ne sont pas forcement toutes exprimées dans le même référentiel. Par exemple, si vous planifiez un voyage, il est important de ne pas se tromper sur les dates de départ et d’arrivée d'un vol !

API Date-Time
Lorsque la date est créée à partir d'une instance de Calendar, il est possible de spécifier un fuseau horaire sur le calendrier en utilisant la classe java.util.TimeZone. Lors de la création du fuseau horaire, vous pouvez fournir soit un des noms conventionnels du fuseau horaire (ex. : "Europe/Paris") soit un décalage horaire par rapport au fuseau horaire de référence GMT (ex. : "GMT+1");

Code Java : Sélectionner tout
1
2
3
4
5
6
Calendar calendrier = Calendar.getInstance(); 
calendrier.setTimeZone(TimeZone.getTimeZone("Pacific Standard Time")); // Le fuseau horaire est celui de la côte Ouest nord-américaine. 
calendrier.set(2010, 4, 23, 9, 1, 2); // 0 est le mois de janvier. 
calendrier.set(Calendar.MILLISECOND, 0); 
Date date = calendrier.getTime(); 
System.out.printf("%tc", date).println(); // La date sera imprimée dans votre fuseau horaire actuel, le jour et l'heure affichés peuvent donc apparaître différents de ceux saisis plus haut.

Lorsque la date est créée à partir d'une chaîne de caractères, il est possible de spécifier le fuseau horaire sur le formateur :

Code Java : Sélectionner tout
1
2
3
4
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); 
format.setTimeZone(TimeZone.getTimeZone("Pacific Standard Time")); // Le fuseau horaire est celui de la côte Ouest nord-américaine. 
Date date = format.parse("2010-05-23T09:01:02"); 
System.out.printf("%tc", date).println(); // La date sera imprimée dans votre fuseau horaire actuel, le jour et l'heure affichés peuvent donc apparaître différents de ceux saisis plus haut.

Il est également possible de spécifier le fuseau horaire dans le format :

Code Java : Sélectionner tout
1
2
3
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss z"); 
Date date = format.parse("2010-05-23T09:01:02 Pacific Standard Time"); // Le fuseau horaire est celui de la côte Ouest nord-américaine. 
System.out.printf("%tc", date).println(); // La date sera imprimée dans votre fuseau horaire actuel, le jour et l'heure affichés peuvent donc apparaître différents de ceux saisis plus haut.

API java.time
À partir du JDK 8, il est possible de stocker des dates contenant des informations de fuseau horaire dans les classes OffsetTime et OffsetDateTime et ZoneDateTime tandis que les définitions des fuseaux horaires sont stockées dans la classe ZoneId.

Code Java : Sélectionner tout
1
2
3
4
ZoneId zoneId = ZoneId.of("America/Los_Angeles"); 
// Ou : 
// ZoneId zoneId = ZoneId.of("PST", ZoneId.SHORT_IDS); 
ZonedDateTime date = ZonedDateTime.of(1995, 10, 8, 15, 20, 50, 0, zoneId);

Il est possible de construire une ZonedDateTime à partir d'un Instant ou d'une LocalDateTime en lui affectant un fuseau horaire nommé :

Code Java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
ZoneId zoneId = ZoneId.of("America/Los_Angeles"); 
Instant maintenant = Instant.now(); 
ZonedDateTime maintenantLA = maintenant.atZone(zoneId); 
// Ou : 
// ZonedDateTime maintenantLA = ZonedDateTime.ofInstant(maintenant, zoneId); 
System.out.println(maintenant); 
System.out.println(maintenantLA); 
LocalDateTime dateBase = LocalDateTime.parse("2010-05-23T09:01:02"); 
ZonedDateTime dateLA = baseDate.atZone(zoneId); 
// Ou : 
// ZonedDateTime dateLA = ZonedDateTime.of(baseDate, zoneId); 
System.out.println(dateBase ); 
System.out.println(dateLA );

Il est également possible de parser directement une chaîne de caractères contenant une information sur le fuseau horaire :

Code Java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
// Format ISO 
ZonedDateTime zonedDate = ZonedDateTime.parse("2010-05-23T09:01:02-07:00[America/Los_Angeles]"); 
OffsetDateTime offsetDate = OffsetDateTime.parse("2010-05-23T09:01:02-07:00"); 
System.out.println(zonedDate); 
System.out.println(offsetDate); 
// Formats personnalisés. 
ZonedDateTime dateFormatPerso1 = ZonedDateTime.parse("2010-05-23 09:01:02 America/Los_Angeles", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV")); 
ZonedDateTime dateFormatPerso2 = ZonedDateTime.parse("2010-05-23 09:01:02 Pacific Standard Time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss zzzz")); 
System.out.println(dateFormatPerso1); 
System.out.println(dateFormatPerso2);

Ici, offsetDate ne conserve que l'information de décalage par rapport au fuseau horaire de référence ; le passage à l'heure d’économie d’énergie n'est donc pas pris en compte.
Code Java : Sélectionner tout
Set<String> idFuseauxHoraires = ZoneId.getAvailableZoneIds();

Mis à jour le 23 juillet 2015 bouye

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2016 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

 
Responsable bénévole de la rubrique Java : Mickael Baron -