I. Introduction▲
Dans la partie précédente, nous avons vu tout ce qu'apporte le Projet Lambda à Java. Mais Java 8, ce n'est pas seulement les lambdas et un zeste de programmation fonctionnelle. Ce sont aussi de nombreuses améliorations tout autant révolutionnaires. Il aura fallu plus de dix ans pour que les développeurs soient entendus, mais le jour du salut est bientôt là ; nous allons enfin avoir une API de manipulation de dates digne de ce nom qui va se substituer à JodaTime.
Pour cet article, le JDK 8 build b94 a été utilisé. Le dernier build peut être téléchargé depuis jdk8.java.net.
L'intégralité des sources est disponible via Github.
II. java.time - JSR 310▲
La nouvelle API Date and Time est l'une des fonctionnalités les plus attendues et ce depuis de nombreuses années. Avec les JDK 7 et antérieurs, grâce à la méthode statique System.currentTimeMillis(), il est possible de récupérer le temps écoulé, en millisecondes, depuis le 1er janvier 1970. Si vous préférez utiliser des objets, il y a la classe java.util.Date, dont la plupart des méthodes ont été dépréciées dans le JDK8. Quant à la classe java.util.GregorianCalendar, elle permet d'effectuer - entre autres - des opérations sur les dates, comme ajouter ou soustraire x heures. Dans l'ensemble, ces classes et ces méthodes ne sont pas pratiques à utiliser. De ce fait, l'ancienne API a été délaissée par les développeurs au profit de JodaTime.
Il est donc indiscutable que nous avions besoin de quelque chose de simple à utiliser, de performant et d'objets immuables, dans la continuité de JodaTime. Mais la JSR 310 n'est pas un copier/coller de JodaTime, elle en est seulement inspirée, pour les raisons évoquées dans ce post. Stephen Colebourne, le créateur de JodaTime est aussi coleader de la JSR 310.
II-A. La nouvelle API▲
Cette nouvelle API est basée sur deux différents modèles de conception du temps. Le temps Machine et le temps Humain. Pour une machine, le temps n'est qu'un entier augmentant depuis l'epoch (01 janvier 1970 00h00min00s0ms0ns). Pour un humain en revanche, il s'agit d'une succession de champs ayant une unité (année, mois, jours, heure, etc.).
Les principes architecturaux autour desquels a été conçue la nouvelle API sous les suivants.
- Immuabilité et thread safety : Toutes les classes centrales de l'API Date and Time sont immuables, ce qui nous assure de ne pas avoir à nous soucier de problèmes de concurrence. De plus, qui dit objets immuables, dit des objets simples à créer, à utiliser et à tester.
- Chaînage : les méthodes chaînables rendent le code plus lisible et elles sont aussi plus simples à apprendre. Quant aux méthodes de type factory (par exemple: now(), from(), etc.) elles sont utilisées en lieu et place de constructeurs.
- Clareté : Chaque méthode définie clairement ce qu'elle fait. De plus, hormis dans quelques cas particuliers, passer un paramètre nul à une méthode provoquera la levée d'un NullPointerException. Les méthodes de validation prenant des objets en paramètre et retournant un booléen retournent généralement false lorsque null est passé.
- Extensibilité : Le design pattern Stratégie utilisé à travers l'API permet son extension en évitant toute confusion. Par exemple, bien que les classes de l' API soient basées sur le système de calendrier ISO-8601, nous pouvons aussi utiliser les calendriers non-ISO - tel que le calendrier Impérial Japonais - qui sont inclus dans l'API, ou même créer notre propre calendrier.
II-B. Le temps Machine▲
Pour commencer, voyons deux classes associées au temps machine, java.time.Instant et java.time.Duration.
II-B-1. java.time.Instant▲
La classe java.time.Instant représente un point relatif à l'epoch.
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.
/*
* org.isk.datetime.MachineTimeTest
*/
@Test
public
void
instant
(
) {
//---- Instant.EPOCH
Assert.assertEquals
(
"1970-01-01T00:00:00Z"
, Instant.EPOCH.toString
(
));
Assert.assertEquals
(
Instant.parse
(
"1970-01-01T00:00:00Z"
), Instant.EPOCH);
Assert.assertEquals
(
Instant.ofEpochSecond
(
0
), Instant.EPOCH);
//---- Instant.MIN
Assert.assertEquals
(
Instant.parse
(
"-1000000000-01-01T00:00:00Z"
), Instant.MIN);
//---- Instant.MAX
Assert.assertEquals
(
Instant.parse
(
"+1000000000-12-31T23:59:59.999999999Z"
), Instant.MAX);
//---- Few instance methods
final
Instant instant =
Instant.now
(
);
// prints the current time
// e.g. 2013-05-26T21:37Z (Coordinated Universal Time)
System.out.println
(
"Instant.now() : "
+
instant);
// print the number of nano seconds
System.out.println
(
"Instant.now().getNano() : "
+
instant.getNano
(
));
//-- Working with 2 instants
// 2013-05-26T23:10:40Z & 1530-05-26T23:10:40Z
final
Instant instant20130526_231040 =
Instant.parse
(
"2013-05-26T23:10:40Z"
);
final
Instant instant15300526_231040 =
Instant.parse
(
"1530-05-26T23:10:40Z"
);
// 2013-05-26T23:10:40Z is After 1530-05-26T23:10:40Z
Assert.assertTrue
(
instant20130526_231040.isAfter
(
instant15300526_231040));
// 2013-05-26T23:10:40Z is NOT Before 1530-05-26T23:10:40Z
Assert.assertFalse
(
instant20130526_231040.isBefore
(
instant15300526_231040));
// 2013-05-26T23:10:40Z minus 1 hour (3600s)
Assert.assertEquals
(
Instant.parse
(
"2013-05-26T22:10:40Z"
),
instant20130526_231040.minusSeconds
(
3600
));
}
- Instant.EPOCH : représente l'epoch.
- Instant.MIN : représente la plus petite valeur (pour les dates avant Jésus-Christ).
- Instant.MAX : représente la plus grande valeur possible (31 décembre un trillion).
- Instant.parse() : retourne un objet de type Instant à partir d'une chaîne de caractère représentant une date au format ISO-8601. Si la chaîne de caractères ne représente pas une valeur valide, une exception de type java.time.format.DateTimeParseException sera levée (le standard ISO-8601 spécifie que la lettre “T” désigne l'heure qu'elle précède et “Z” une data UTC).
- Instant.ofEpochSecond()/Instant.ofEpochMilliSecond() : retourne un objet de type Instant à partir d'un offset de x secondes ou millisecondes par rapport à l'epoch.
- Instant.now() : retourne un objet de type Instant représentant la date UTC actuelle.
- Instant.now().getNano() : retourne le nombre de nanosecondes de la date actuelle retournée par Instant.now().
Les méthodes isAfter(), isBefore(), minusSeconds(), etc. font ce que leur nom indique.
La méthode toString() sur une instance d'un objet Instant retourne la date au format ISO-8601.
II-B-2. java.time.Duration▲
La classe java.time.Duration représente une durée.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
/*
* org.isk.datetime.MachineTimeTest
*/
@Test
public
void
duration
(
) {
//---- Duration.ZERO
Assert.assertEquals
(
Duration.parse
(
"PT0S"
), Duration.ZERO);
Assert.assertEquals
(
"PT0S"
, Duration.ZERO.toString
(
));
//---- 2h 5min 30s 345ms = 7_530_345ms
final
Duration duration =
Duration.ofMillis
(
7_530_345
);
Assert.assertEquals
(
"PT2H5M30.345S"
, duration.toString
(
));
Assert.assertEquals
(
7530
, duration.getSeconds
(
));
Assert.assertEquals
(
345000000
, duration.getNano
(
));
}
- Duration.ZERO : représente une durée nulle.
- Duration.parse() : retourne un objet de type Duration à partir d'une chaîne de caractères représentant une durée au format ISO-8601. Si la chaîne de caractères ne représente pas une valeur valide, une exception de type java.time.format.DateTimeParseException sera levée (selon le standard ISO-8601 une durée commence P - pour Period- et est suivie d'une valeur comme 4DT11H9M8S - pour Days, Hours, Minutes et Seconds - où la date et l'heure sont séparées par la lettre “T” - pour Time). Le standard permet aussi de définir un nombre d'années et de mois, ce que ne permet pas la méthode parse().
- Duration.ofMillis() : retourne un objet de type Duration à partir d'une chaîne de caractères représentant une durée en millisecondes.
La classe Duration, à l'instar de Instant, possède différents getters et méthodes de manipulation telles que plusX(), minusX(), etc. où X correspond à Days, Hours, Minutes, etc. ainsi que withY() où Y correspond à Seconds ou Nanos (ces méthodes retournent une copie de la durée ajustée avec la valeur passée en paramètre).
Les classes Instant et Duration étant immuables, les méthodes plusX(), minusX(), withY(), etc. retournent toujours de nouvelles instances.
II-C. Le temps Humain▲
II-C-1. LocalDate, LocalTime, et LocalDateTime▲
Les classes java.time.LocalDate, java.time.LocalTime et java.time.LocalDateTime représentent des dates et heures système sans indication du fuseau horaire.
Les morceaux de code ci-dessous étant suffisamment clairs, je vous invite à les lire ainsi que leurs commentaires associés.
II-C-1-a. Les constantes▲
Divers constantes sont disponibles :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
constants
(
) {
//---- LocalDate
// LocalDate.MIN & LocalDate.MAX
Assert.assertEquals
(
"-999999999-01-01"
, LocalDate.MIN.toString
(
));
Assert.assertEquals
(
"+999999999-12-31"
, LocalDate.MAX.toString
(
));
//---- LocalTime
// LocalTime.MIN & LocalTime.MAX
Assert.assertEquals
(
"00:00"
, LocalTime.MIN.toString
(
));
Assert.assertEquals
(
"23:59:59.999999999"
, LocalTime.MAX.toString
(
));
// LocalTime.NOON & LocalTime.MIDNIGHT
// There is no mention of AM and PM
Assert.assertEquals
(
"12:00"
, LocalTime.NOON.toString
(
));
Assert.assertEquals
(
"00:00"
, LocalTime.MIDNIGHT.toString
(
));
//---- LocalDateTime
// LocalDateTime.MIN & LocalDateTime.MAX
Assert.assertEquals
(
"-999999999-01-01T00:00"
, LocalDateTime.MIN.toString
(
));
Assert.assertEquals
(
"+999999999-12-31T23:59:59.999999999"
, LocalDateTime.MAX.toString
(
));
}
II-C-1-b. La méthode statique now()▲
La méthode statique now() retourne la date du système avec le fuseau horaire pris en compte, sauf si indiqué autrement en paramètre.
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.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
now
(
) {
//---- LocalDate
// Current System Date
// e.g. 2013-05-26
System.out.println
(
"LocalDate.now(): "
+
LocalDate.now
(
));
// Current UTC System Date
// e.g. 2013-05-26
System.out.println
(
"LocalDate.now(Clock.systemUTC()): "
+
LocalDate.now
(
Clock.systemUTC
(
)));
//---- LocalTime
// Current System Time
//e.g. 21:35:45.977
System.out.println
(
"LocalTime.now(): "
+
LocalTime.now
(
));
// Current UTC System Time
//e.g. 19:35:45.977
System.out.println
(
"LocalTime.now(Clock.systemUTC()): "
+
LocalTime.now
(
Clock.systemUTC
(
)));
//---- LocalDateTime
// Current System Date and Time
//e.g. 2013-05-26T21:35:45.977
System.out.println
(
"LocalDateTime.now(): "
+
LocalDateTime.now
(
));
// Current UTC System Date and Time
//e.g. 2013-05-26T19:35:45.977
System.out.println
(
"LocalDateTime.now(Clock.systemUTC()): "
+
LocalDateTime.now
(
Clock.systemUTC
(
)));
}
II-C-1-c. Les méthodes statiques de construction▲
Il est possible de construire des dates à partir de différents formats.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
localDateStaticMethods
(
) {
// LocalDate from a string
final
LocalDate localDateStr =
LocalDate.parse
(
"2013-05-23"
);
Assert.assertEquals
(
"2013-05-23"
, localDateStr.toString
(
));
// LocalDate from 3 integers (year, month, day)
final
LocalDate localDate =
LocalDate.of
(
2013
, 05
, 26
);
Assert.assertEquals
(
"2013-05-26"
, localDate.toString
(
));
// LocalDate with an offset from epoch
final
LocalDate oneHundredDaysBeforeEpoch =
LocalDate.ofEpochDay
(-
1000
);
Assert.assertEquals
(
"1967-04-07"
, oneHundredDaysBeforeEpoch.toString
(
));
// Copy of a LocalDate
final
LocalDate copyLocalDate =
LocalDate.from
(
localDate);
Assert.assertEquals
(
"2013-05-26"
, copyLocalDate.toString
(
));
}
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.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
localTimeStaticMethods
(
) {
// LocalTime from a string
final
LocalTime timeStr1 =
LocalTime.parse
(
"12:35"
);
Assert.assertEquals
(
"12:35"
, timeStr1.toString
(
));
final
LocalTime timeStr2 =
LocalTime.parse
(
"12:35:32.978"
);
Assert.assertEquals
(
"12:35:32.978"
, timeStr2.toString
(
));
// LocalDate from 3 integers (hour, minute, second)
// But can be 2 (hour, minute)
// or 4 (hour, minute, second, nanoseconds)
final
LocalTime timeAsInts =
LocalTime.of
(
10
, 22
, 17
);
Assert.assertEquals
(
"10:22:17"
, timeAsInts.toString
(
));
// LocalTime from a number of seconds after midnight
final
LocalTime oneHourAfterMidnight =
LocalTime.ofSecondOfDay
(
3600
);
Assert.assertEquals
(
"01:00"
, oneHourAfterMidnight.toString
(
));
// Copy of a LocalTime
final
LocalTime copyLocalTime =
LocalTime.from
(
timeAsInts);
Assert.assertEquals
(
"10:22:17"
, copyLocalTime.toString
(
));
}
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
localDateTimeStaticMethods
(
) {
// LocalDateTime from a string
final
LocalDateTime localDateTimeStr =
LocalDateTime.parse
(
"2013-05-26T10:22:17"
);
Assert.assertEquals
(
"2013-05-26T10:22:17"
, localDateTimeStr.toString
(
));
// LocalDate from 5 parameters (year, month, day, hour, minute, second)
// But range from 5 to 7.
// Note : Month is an enum.
final
LocalDateTime localDateTime =
LocalDateTime.of
(
2013
, Month.MAY, 26
, 12
, 05
);
Assert.assertEquals
(
"2013-05-26T12:05"
, localDateTime.toString
(
));
// LocalDateTime from a LocalDate and a LocalTime
final
LocalDate localDate =
LocalDate.of
(
2013
, 05
, 26
);
final
LocalTime localTime =
LocalTime.of
(
12
, 35
);
final
LocalDateTime localDateTimeOfDateAndTime =
LocalDateTime.of
(
localDate, localTime);
Assert.assertEquals
(
"2013-05-26T12:35"
, localDateTimeOfDateAndTime.toString
(
));
// Copy of a LocalDateTime
final
LocalDateTime copyLocalDateTime =
LocalDateTime.from
(
localDateTime);
Assert.assertEquals
(
"2013-05-26T12:05"
, copyLocalDateTime.toString
(
));
}
II-C-1-d. Les méthodes d'instances▲
Les classes LocalDate, LocalTime et LocalDateTime ont différentes méthodes permettant de récupérer une partie de la date, de la tester et d'effectuer des opérations dessus.
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.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
localDateInstanceMethods
(
) {
final
LocalDate localDate =
LocalDate.of
(
2013
, 05
, 26
);
// Year
Assert.assertEquals
(
2013
, localDate.getYear
(
));
// Month
Assert.assertEquals
(
Month.MAY, localDate.getMonth
(
));
Assert.assertEquals
(
5
, localDate.getMonthValue
(
));
// Day
Assert.assertEquals
(
26
, localDate.getDayOfMonth
(
));
Assert.assertEquals
(
DayOfWeek.SUNDAY, localDate.getDayOfWeek
(
));
Assert.assertEquals
(
146
, localDate.getDayOfYear
(
));
// Leap Year
Assert.assertFalse
(
localDate.isLeapYear
(
));
Assert.assertTrue
(
LocalDate.of
(
2004
, 05
, 26
).isLeapYear
(
));
//---- Operations
final
LocalDate localDate2 =
LocalDate.of
(
2013
, 04
, 26
);
// Before, After, Equal, equals
Assert.assertTrue
(
localDate.isAfter
(
localDate2));
Assert.assertFalse
(
localDate.isBefore
(
localDate2));
Assert.assertTrue
(
localDate.isEqual
(
LocalDate.of
(
2013
, 05
, 26
)));
Assert.assertTrue
(
localDate.equals
(
LocalDate.of
(
2013
, 05
, 26
)));
// plus & minus
Assert.assertEquals
(
"2013-04-26"
, localDate.minusMonths
(
1
).toString
(
));
Assert.assertEquals
(
"2013-06-05"
, localDate.plusDays
(
10
).toString
(
));
// Adjusters
Assert.assertEquals
(
"2013-05-01"
, localDate.with
(
TemporalAdjuster.firstDayOfMonth
(
)).toString
(
));
Assert.assertEquals
(
"2013-05-10"
, localDate.withDayOfMonth
(
10
).toString
(
));
}
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.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
localTimeInstanceMethods
(
) {
final
LocalTime localTime =
LocalTime.of
(
12
, 35
, 25
, 452_367_943
);
// Hour, Minute, Second, Nanosecond
Assert.assertEquals
(
12
, localTime.getHour
(
));
Assert.assertEquals
(
35
, localTime.getMinute
(
));
Assert.assertEquals
(
25
, localTime.getSecond
(
));
Assert.assertEquals
(
452_367_943
, localTime.getNano
(
));
//---- Operations
// Before, After, Equal, equals
final
LocalTime localTime2 =
LocalTime.of
(
12
, 35
, 25
, 452_367_942
);
Assert.assertTrue
(
localTime.isAfter
(
localTime2));
Assert.assertFalse
(
localTime.isBefore
(
localTime2));
Assert.assertTrue
(
localTime.equals
(
LocalTime.of
(
12
, 35
, 25
, 452_367_943
)));
/// plus & minus
Assert.assertEquals
(
"12:25:25.452367943"
, localTime.minusMinutes
(
10
).toString
(
));
Assert.assertEquals
(
"17:35:25.452367943"
, localTime.plusHours
(
5
).toString
(
));
// Adjusters
Assert.assertEquals
(
"05:35:25.452367943"
, localTime.withHour
(
5
).toString
(
));
}
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
localDateTimeInstanceMethods
(
) {
final
LocalDate localDate =
LocalDate.of
(
2013
, 05
, 26
);
final
LocalTime localTime =
LocalTime.of
(
12
, 35
, 25
, 452_367_943
);
final
LocalDateTime localDateTime =
LocalDateTime.of
(
localDate, localTime);
// As LocalDate & LocalTime
Assert.assertEquals
(
"2013-05-26"
, localDateTime.toLocalDate
(
).toString
(
));
Assert.assertEquals
(
"12:35:25.452367943"
, localDateTime.toLocalTime
(
).toString
(
));
// Other methods are the same as for LocalDate and LocalTime
}
II-C-2. ZoneId, ZoneOffset, ZonedDateTime, et OffsetDateTime▲
Un fuseau horaire est une zone de la surface de la Terre dans laquelle toutes les localités ont le même temps standard. Chaque fuseau horaire a un identifiant (par exemple Europe/Paris) et un décalage par rapport à UTC/Greenwich (comme +01:00) qui change lorsque l'heure d'été est en vigueur.
II-C-2-a. ZoneId▲
La classe ZoneId représente un identifiant de fuseau horaire et fournit des règles de conversion entre Instant et LocalDateTime.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
zoneId
(
) {
final
ZoneId zoneId =
ZoneId.systemDefault
(
);
final
ZoneRules zoneRules =
zoneId.getRules
(
);
Assert.assertEquals
(
"Europe/Paris"
, zoneId.toString
(
));
Assert.assertEquals
(
"ZoneRules[currentStandardOffset=+01:00]"
, zoneRules.toString
(
));
// DST in effect
Assert.assertTrue
(
zoneRules.isDaylightSavings
(
Instant.parse
(
"2013-05-26T23:10:40Z"
)));
Assert.assertFalse
(
zoneRules.isDaylightSavings
(
Instant.parse
(
"2013-01-26T23:10:40Z"
)));
}
II-C-2-b. ZoneOffset▲
ZoneOffset décrit un offset de fuseau horaire, qui est un temps (généralement en heures) par lequel un fuseau horaire diffère de Greenwich.
2.
3.
4.
5.
6.
7.
8.
9.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
zoneOffset
(
) {
final
ZoneOffset zoneOffset =
ZoneOffset.of
(
"+06:00"
);
Assert.assertEquals
(
"+06:00"
, zoneOffset.toString
(
));
Assert.assertEquals
(
21600
, zoneOffset.getTotalSeconds
(
));
}
II-C-2-c. ZonedDateTime▲
La classe ZonedDateTime représente une date avec un fuseau horaire au format ISO-8601 (par exemple 2012-05-26T10:15:30+02:00 Europe/Paris).
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
zonedDateTime
(
) {
final
LocalDateTime localDateTime =
LocalDateTime.parse
(
"2013-05-26T10:22:17"
);
final
ZoneId zoneId =
ZoneId.of
(
"Europe/Paris"
);
final
ZonedDateTime zonedDateTime =
ZonedDateTime.of
(
localDateTime, zoneId);
Assert.assertEquals
(
"2013-05-26T10:22:17+02:00[Europe/Paris]"
, zonedDateTime.toString
(
));
final
ZoneOffset zoneOffset =
ZoneOffset.from
(
zonedDateTime);
Assert.assertEquals
(
"+02:00"
, zoneOffset.toString
(
));
}
II-C-2-d. OffsetDateTime▲
La classe OffsetDateTime représente une date avec un offset par rapport à Greenwich, au format ISO-8601 (par exemple 2012-05-26T10:15:30+02:00) sans indication de localité.
Les classes ZonedDateTime et OffsetDateTime sont similaires, elles représentent des dates avec des offsets par rapport à Greenwich. Cependant, la classe ZonedDateTime permet d'identifier certaines ambiguïtés. Par exemple, lors d'un changement d'heure, une même heure peut apparaître deux fois à une heure de décalage. La classe OffsetDateTime ne prend pas en compte ce cas, contrairement à ZonedDateTime.
2.
3.
4.
5.
6.
7.
8.
9.
10.
/*
* org.isk.datetime.HumanTimeTest
*/
@Test
public
void
offsetDateTime
(
) {
final
LocalDateTime localDateTime =
LocalDateTime.parse
(
"2013-05-26T10:22:17"
);
final
ZoneOffset zoneOffset =
ZoneOffset.of
(
"+02:00"
);
final
OffsetDateTime offsetDateTime =
OffsetDateTime.of
(
localDateTime, zoneOffset);
Assert.assertEquals
(
"2013-05-26T10:22:17+02:00"
, offsetDateTime.toString
(
));
}
Les méthodes of(), from() et with() sont comparables à celles que nous avons vues dans la partie précédente.
III. Conclusion▲
La nouvelle API Date and Time surmonte divers problèmes des anciennes APIs Date and Time. Elle est organisée autour du package principal java.time et de quatre sous-packages. Même si nous utiliserons le plus souvent les classes Instant, Duration, LocalDate, LocalTime, LocalDateTime, ZoneId, ZoneOffset, ZonedDateTime, et OffsetDateTime, il existe d'autres types qui méritent notre attention.
IV. Remerciements▲
Cet article a été publié avec l'aimable autorisation de la société SoatSoat.
Nous tenons à remercier ced pour sa relecture attentive de cet article et Mickaël Baron pour la mise au gabarit.