Migration vers la nouvelle API Java 8 Date Time

Migration vers la nouvelle API Java 8 Date Time

1. Vue d'ensemble

Dans ce didacticiel, vous apprendrez à restructurer votre code afin de tirer parti de la nouvelle API Date Time introduite dans Java 8.

2. Nouvelle API en un coup d'œil

Travailler avec des dates en Java était très difficile. L'ancienne bibliothèque de dates fournie par JDK ne comprenait que trois classes:java.util.Date, java.util.Calendar etjava.util.Timezone.

Celles-ci ne conviennent que pour les tâches les plus élémentaires. Pour tout ce qui est complexe, les développeurs devaient utiliser des bibliothèques tierces ou écrire des tonnes de code personnalisé.

Java 8 introduced a completely new Date Time API (java.util.time.*) qui est vaguement basé sur la bibliothèque Java populaire appelée JodaTime. Cette nouvelle API a considérablement simplifié le traitement de la date et de l'heure et corrigé de nombreuses lacunes de l'ancienne bibliothèque de dates.

1.1. Clarté de l'API

Un premier avantage de la nouvelle API estclarity - l'API est très claire, concise et facile à comprendre. Il n'y a pas beaucoup d'incohérences trouvées dans l'ancienne bibliothèque, telles que la numérotation des champs (dans Calendar, les mois sont basés sur zéro, mais les jours de la semaine sont uniques).

1.2. Flexibilité de l'API

Un autre avantage est la flexibilité -working with multiple representations of time. L'ancienne bibliothèque de dates ne comprenait qu'une seule classe de représentation de l'heure -java.util.Date, qui malgré son nom, est en fait un horodatage. Il ne stocke que le nombre de millisecondes écoulées depuis l'époque Unix.

La nouvelle API a de nombreuses représentations temporelles différentes, chacune adaptée à différents cas d'utilisation:

  • Instant - représente un point dans le temps (horodatage)

  • LocalDate - représente une date (année, mois, jour)

  • LocalDateTime - identique àLocalDate, mais inclut le temps avec une précision nanoseconde

  • OffsetDateTime - identique àLocalDateTime, mais avec décalage de fuseau horaire

  • LocalTime - heure avec une précision nanoseconde et sans informations de date

  • ZonedDateTime - identique àOffsetDateTime, mais comprend un ID de fuseau horaire

  • OffsetLocalTime - identique àLocalTime, mais avec décalage de fuseau horaire

  • MonthDay - mois et jour, sans année ni heure

  • YearMonth - mois et année, sans jour ni heure

  • Duration - durée représentée en secondes, minutes et heures. A une précision nanoseconde

  • Period - durée représentée en jours, mois et années

1.3. Immuabilité et sécurité des fils

Un autre avantage est que toutes les représentations temporelles dans l'API Java 8 Date Time sontimmutable and thus thread-safe.

Toutes les méthodes en mutation renvoient une nouvelle copie au lieu de modifier l'état de l'objet d'origine.

Les anciennes classes telles quejava.util.Date n'étaient pas thread-safe et pouvaient introduire des bogues de concurrence très subtils.

1.4. Chaînage de méthodes

Toutes les méthodes de mutation peuvent être chaînées, ce qui permet d'implémenter des transformations complexes dans une seule ligne de code.

ZonedDateTime nextFriday = LocalDateTime.now()
  .plusHours(1)
  .with(TemporalAdjusters.next(DayOfWeek.FRIDAY))
  .atZone(ZoneId.of("PST"));

2. Exemples

Les exemples ci-dessous montrent comment effectuer des tâches courantes avec l'ancienne et la nouvelle API.

Obtenir l'heure actuelle

// Old
Date now = new Date();

// New
ZonedDateTime now = ZonedDateTime.now();

Représenter une heure précise

// Old
Date birthDay = new GregorianCalendar(1990, Calendar.DECEMBER, 15).getTime();

// New
LocalDate birthDay = LocalDate.of(1990, Month.DECEMBER, 15);

Extraire des champs spécifiques

// Old
int month = new GregorianCalendar().get(Calendar.MONTH);

// New
Month month = LocalDateTime.now().getMonth();

Ajouter et soustraire du temps

// Old
GregorianCalendar calendar = new GregorianCalendar();
calendar.add(Calendar.HOUR_OF_DAY, -5);
Date fiveHoursBefore = calendar.getTime();

// New
LocalDateTime fiveHoursBefore = LocalDateTime.now().minusHours(5);

Modifier des champs spécifiques

// Old
GregorianCalendar calendar = new GregorianCalendar();
calendar.set(Calendar.MONTH, Calendar.JUNE);
Date inJune = calendar.getTime();

// New
LocalDateTime inJune = LocalDateTime.now().withMonth(Month.JUNE.getValue());

Tronquer

La troncature réinitialise tous les champs horaires inférieurs au champ spécifié. Dans l'exemple ci-dessous, les minutes et tout ce qui suit sont mis à zéro

// Old
Calendar now = Calendar.getInstance();
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
Date truncated = now.getTime();

// New
LocalTime truncated = LocalTime.now().truncatedTo(ChronoUnit.HOURS);

Conversion de fuseau horaire

// Old
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeZone(TimeZone.getTimeZone("CET"));
Date centralEastern = calendar.getTime();

// New
ZonedDateTime centralEastern = LocalDateTime.now().atZone(ZoneId.of("CET"));

Obtenir l'intervalle de temps entre deux points dans le temps

// Old
GregorianCalendar calendar = new GregorianCalendar();
Date now = new Date();
calendar.add(Calendar.HOUR, 1);
Date hourLater = calendar.getTime();
long elapsed = hourLater.getTime() - now.getTime();

// New
LocalDateTime now = LocalDateTime.now();
LocalDateTime hourLater = LocalDateTime.now().plusHours(1);
Duration span = Duration.between(now, hourLater);

Formatage et analyse de l'heure

DateTimeFormatter est un remplacement de l'ancien SimpleDateFormat qui est thread-safe et fournit des fonctionnalités supplémentaires.

// Old
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date now = new Date();
String formattedDate = dateFormat.format(now);
Date parsedDate = dateFormat.parse(formattedDate);

// New
LocalDate now = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String formattedDate = now.format(formatter);
LocalDate parsedDate = LocalDate.parse(formattedDate, formatter);

Nombre de jours dans un mois

// Old
Calendar calendar = new GregorianCalendar(1990, Calendar.FEBRUARY, 20);
int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

// New
int daysInMonth = YearMonth.of(1990, 2).lengthOfMonth();

3. Interagir avec l'ancien code

Dans de nombreux cas, un utilisateur peut avoir besoin d’assurer l’interopérabilité avec les bibliothèques tierces qui reposent sur l’ancienne bibliothèque de dates.

En Java 8, les anciennes classes de la bibliothèque de dates ont été étendues avec des méthodes qui les convertissent en objets correspondants de la nouvelle API Date. Les nouvelles classes offrent des fonctionnalités similaires.

Instant instantFromCalendar = GregorianCalendar.getInstance().toInstant();
ZonedDateTime zonedDateTimeFromCalendar = new GregorianCalendar().toZonedDateTime();
Date dateFromInstant = Date.from(Instant.now());
GregorianCalendar calendarFromZonedDateTime = GregorianCalendar.from(ZonedDateTime.now());
Instant instantFromDate = new Date().toInstant();
ZoneId zoneIdFromTimeZone = TimeZone.getTimeZone("PST").toZoneId();

4. Conclusion

Dans cet article, nous avons exploré la nouvelle API Date Time disponible dans Java 8. Nous avons examiné ses avantages par rapport à l’API déconseillée et souligné les différences à l’aide de multiples exemples.

Notez que nous avons à peine effleuré les fonctionnalités de la nouvelle API Date Time. Assurez-vous de lire la documentation officielle pour découvrir la gamme complète d'outils proposés par la nouvelle API.

Des exemples de code peuvent être trouvés dans lesGitHub project.