Java 8 a ajouté une nouvelle API Java.time == == pour travailler avec les dates et les heures ( JSR 31 ).
J'ai la date et l'heure sous forme de chaîne (par exemple, "2014-04-08 12:30"
). Comment puis-je obtenir une instance LocalDateTime
à partir de la chaîne donnée?
Après avoir fini de travailler avec l'objet LocalDateTime
: Comment puis-je reconvertir l'occurrence LocalDateTime
en une chaîne de même format que celui présenté ci-dessus?
Date et heure de l'analyse syntaxique
Pour créer un objet LocalDateTime
à partir d'une chaîne, vous pouvez utiliser la méthode statique LocalDateTime.parse()
. Il faut une chaîne et un DateTimeFormatter
en paramètre. DateTimeFormatter
est utilisé pour spécifier le modèle de date/heure.
String str = "1986-04-08 12:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(str, formatter);
Date et heure du formatage
Pour créer une chaîne formatée à partir d'un objet LocalDateTime
, vous pouvez utiliser la méthode format()
.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.of(1986, Month.APRIL, 8, 12, 30);
String formattedDateTime = dateTime.format(formatter); // "1986-04-08 12:30"
Notez que certains formats de date/heure couramment utilisés sont prédéfinis en tant que constantes dans DateTimeFormatter
. Par exemple, l'utilisation de DateTimeFormatter.ISO_DATE_TIME
pour formater l'instance LocalDateTime
à partir de la racine entraînerait la chaîne "1986-04-08T12:30:00"
.
Les méthodes parse()
et format()
sont disponibles pour tous les objets liés à la date/heure (par exemple, LocalDate
ou ZonedDateTime
).
Vous pouvez également utiliser LocalDate.parse()
ou LocalDateTime.parse()
sur un String
sans lui attribuer de motif, si String
est au format format ISO-8601 .
par exemple,
String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
System.out.println("Date: " + aLD);
String strDatewithTime = "2015-08-04T10:11:30";
LocalDateTime aLDT = LocalDateTime.parse(strDatewithTime);
System.out.println("Date with Time: " + aLDT);
Sortie ,
Date: 2015-08-04
Date with Time: 2015-08-04T10:11:30
et utilisez DateTimeFormatter
uniquement si vous devez traiter d’autres modèles de date. Par exemple, dd MMM uuuu représente le jour du mois (deux chiffres), trois lettres du nom du mois (janvier, février, mars, ...) et une année à quatre chiffres:
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
String anotherDate = "04 Aug 2015";
LocalDate lds = LocalDate.parse(anotherDate, dTF);
System.out.println(anotherDate + " parses to " + lds);
Sortie
04 Aug 2015 parses to 2015-08-04
rappelez-vous également que l'objet DateTimeFormatter
est bidirectionnel; il peut à la fois analyser l’entrée et formater la sortie.
String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
System.out.println(aLD + " formats as " + dTF.format(aLD));
Sortie
2015-08-04 formats as 04 Aug 2015
(voir complète liste des modèles pour le formatage et l'analyse DateFormatter )
Symbol Meaning Presentation Examples
------ ------- ------------ -------
G era text AD; Anno Domini; A
u year year 2004; 04
y year-of-era year 2004; 04
D day-of-year number 189
M/L month-of-year number/text 7; 07; Jul; July; J
d day-of-month number 10
Q/q quarter-of-year number/text 3; 03; Q3; 3rd quarter
Y week-based-year year 1996; 96
w week-of-week-based-year number 27
W week-of-month number 4
E day-of-week text Tue; Tuesday; T
e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
F week-of-month number 3
a am-pm-of-day text PM
h clock-hour-of-am-pm (1-12) number 12
K hour-of-am-pm (0-11) number 0
k clock-hour-of-am-pm (1-24) number 0
H hour-of-day (0-23) number 0
m minute-of-hour number 30
s second-of-minute number 55
S fraction-of-second fraction 978
A milli-of-day number 1234
n nano-of-second number 987654321
N nano-of-day number 1234000000
V time-zone ID zone-id America/Los_Angeles; Z; -08:30
z time-zone name zone-name Pacific Standard Time; PST
O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00;
X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15;
x zone-offset offset-x +0000; -08; -0830; -08:30; -083015; -08:30:15;
Z zone-offset offset-Z +0000; -0800; -08:00;
p pad next pad modifier 1
' escape for text delimiter
'' single quote literal '
[ optional section start
] optional section end
# reserved for future use
{ reserved for future use
} reserved for future use
Les deux réponses ci-dessus expliquent très bien la question concernant les modèles de chaîne. Cependant, juste au cas où vous travailleriez avec ISO 8601 , il n’est pas nécessaire d’appliquer DateTimeFormatter
puisque LocalDateTime est déjà préparé pour cela:
Convertissez LocalDateTime en fuseau horaire Chaîne ISO8601
LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneOffset.UTC); //you might use a different zone
String iso8601 = zdt.toString();
Convertissez une chaîne ISO8601 en un LocalDateTime
String iso8601 = "2016-02-14T18:32:04.150Z";
ZonedDateTime zdt = ZonedDateTime.parse(iso8601);
LocalDateTime ldt = zdt.toLocalDateTime();
L'analyse d'une chaîne avec la date et l'heure à un moment donné (Java l'appelle un " Instant
") est assez compliquée. Java s’est attaqué à ce problème dans plusieurs itérations. Le dernier, _Java.time
_ et _Java.time.chrono
_, couvre presque tous les besoins (sauf Dilatation du temps :)).
Cependant, cette complexité crée beaucoup de confusion.
La clé pour comprendre l'analyse de la date est la suivante:
LocalDateTime
, ZonedDateTime
et al. si compliquéIl y a fuseaux horaires . Un fuseau horaire est fondamentalement une "bande" * [1] de la surface de la Terre dont les autorités respectent les mêmes règles en matière de décalage horaire. Cela inclut les règles de l'heure d'été.
Les fuseaux horaires changent avec le temps pour différentes régions, principalement en fonction de qui conquiert qui. Et les règles d'un fuseau horaire changement dans le temps également.
Il y a des décalages horaires. Ce n'est pas la même chose que les fuseaux horaires, car un fuseau horaire peut être p. Ex. "Prague", mais avec décalage entre l'heure d'été et l'heure d'hiver.
Si vous obtenez un horodatage avec un fuseau horaire, le décalage peut varier en fonction de la période de l’année. Au cours de l’heure bissextile, l’horodatage peut indiquer 2 heures différentes. ne peut pas être converti de manière fiable.
Remarque: Par horodatage , j'entends "une chaîne contenant une date et/ou une heure, éventuellement avec un fuseau horaire et/ou un décalage horaire".
Plusieurs fuseaux horaires peuvent partager le même décalage horaire pour certaines périodes. Par exemple, le fuseau horaire GMT/UTC est identique au fuseau horaire "Londres" lorsque le décalage de l'heure d'été n'est pas en vigueur.
Pour compliquer un peu les choses (mais ce n'est pas très important pour votre cas d'utilisation):
2040-12-31 24:00:00
_ peut être une date-heure valide.) Cela nécessite des mises à jour régulières des métadonnées que les systèmes utilisent pour que les conversions de date soient correctes. Par exemple. sous Linux, vous obtenez des mises à jour régulières des packages Java incluant ces nouvelles données.Les mises à jour ne conservent pas toujours le comportement précédent pour les horodatages historiques et futurs. Il peut donc arriver que l'analyse des deux horodatages autour d'un changement de fuseau horaire les comparant peut donner des résultats différents lors de l'exécution sur des versions différentes du logiciel. Cela s'applique également à la comparaison entre le fuseau horaire affecté et un autre fuseau horaire.
Si cela devait causer un bogue dans votre logiciel, envisagez d’utiliser un horodatage ne comportant pas de règles aussi compliquées, comme horodatage UNIX .
En raison de 7, pour les dates futures, nous ne pouvons pas convertir les dates exactement avec certitude. Ainsi, par exemple, l'analyse actuelle de _8524-02-17 12:00:00
_ peut être désactivée quelques secondes après l'analyse suivante.
Java.util.Date
_, avec une approche un peu naïve, en supposant qu'il ne reste que l'année, le mois, le jour et l'heure. Cela n'a pas suffi rapidement.Java.sql.Date
_ a été introduit assez tôt, avec ses propres limites.Calendar
a été introduite.Java.time
_Lorsque vous utilisez une chaîne d'horodatage, vous devez savoir quelles informations elle contient. C'est le point crucial. Si vous n'obtenez pas ce droit, vous vous retrouvez avec des exceptions cryptiques telles que "Impossible de créer Instant" ou " Décalage de zone manquant "ou" identificateur de zone inconnue ", etc.
Contient-il la date et l'heure?
At-il un décalage horaire?
Un décalage temporel est la partie _+hh:mm
_. Parfois, _+00:00
_ peut être remplacé par Z
en tant que 'temps zoulou', UTC
en temps universel coordonné ou GMT
en temps de Greenwich. Ceux-ci définissent également le fuseau horaire.
Pour ces horodatages, vous utilisez OffsetDateTime
.
At-il un fuseau horaire?
Pour ces horodatages, vous utilisez ZonedDateTime
.
La zone est spécifiée soit par
La liste des fuseaux horaires est compilée par un "base de données TZ" , soutenu par ICAAN.
Selon le javadoc de ZoneId
, les identifiants de zone peuvent également être spécifiés en tant que Z
et décalés. Je ne sais pas comment cela correspond à de vraies zones. Si l'horodatage, qui n'a qu'une TZ, tombe dans une heure bissextile de changement de décalage horaire, alors il est ambigu et l'interprétation est sujette à ResolverStyle
, voir ci-dessous.
S'il n'a ni , alors le contexte manquant est supposé ou négligé. Et le consommateur doit décider. Donc, il doit être analysé comme LocalDateTime
et converti en OffsetDateTime
en ajoutant les informations manquantes:
Duration
), ou lorsque vous ne le savez pas et que cela n'a pas vraiment d'importance (par exemple, les horaires des bus locaux).Information sur le temps partiel
LocalDate
, LocalTime
, OffsetTime
, MonthDay
, Year
ou YearMonth
.Si vous avez les informations complètes, vous pouvez obtenir un Java.time.Instant
. Ceci est également utilisé en interne pour convertir entre OffsetDateTime
et ZonedDateTime
.
Il existe une documentation complète sur DateTimeFormatter
qui permet à la fois d'analyser une chaîne d'horodatage et de la formater en chaîne.
Le DateTimeFormatter
s pré-créé devrait couvrir tous les formats d'horodatage standard. Par exemple, _ISO_INSTANT
_ peut analyser _2011-12-03T10:15:30.123457Z
_.
Si vous avez un format spécial, alors vous pouvez créer votre propre DateTimeFormatter (qui est également un analyseur syntaxique).
_private static final DateTimeFormatter TIMESTAMP_PARSER = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SX"))
.toFormatter();
_
Je recommande de regarder le code source de DateTimeFormatter
et de m'inspirer pour en construire un en utilisant DateTimeFormatterBuilder
. Pendant que vous y êtes, jetez également un coup d'oeil à ResolverStyle
qui contrôle si l'analyseur est LENIENT, SMART ou STRICT pour les formats et les informations ambiguës.
Maintenant, l’erreur la plus fréquente est d’entrer dans la complexité de TemporalAccessor
. Cela vient de la façon dont les développeurs étaient habitués à travailler avec SimpleDateFormatter.parse(String)
. À droite, DateTimeFormatter.parse("...")
vous donne TemporalAccessor
.
_// No need for this!
TemporalAccessor ta = TIMESTAMP_PARSER.parse("2011-... etc");
_
Mais, avec les connaissances de la section précédente, vous pouvez facilement analyser le type dont vous avez besoin:
_OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z", TIMESTAMP_PARSER);
_
Vous n'avez pas non plus besoin de DateTimeFormatter
. Les types que vous souhaitez analyser ont les méthodes parse(String)
.
_OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z");
_
En ce qui concerne TemporalAccessor
, vous pouvez l’utiliser si vous avez une vague idée des informations contenues dans la chaîne et que vous souhaitez prendre une décision au moment de l’exécution.
J'espère avoir apporté un peu de compréhension à votre âme :)
Remarque: Il existe un backport de _Java.time
_ to Java 6 et 7: ThreeTen-Backport . Pour Android il a ThreeTenABP .
[1] Non seulement ce ne sont pas des rayures, mais il y a aussi des extrêmes étranges. Par exemple, certaines îles voisines du Pacifique ont des fuseaux horaires de +14: 00 et -11: 00. Cela signifie que, même si sur une île, il y a le 1er mai à 15 heures, sur une autre île pas si loin, il est toujours le 30 avril 12 PM (si j'ai bien compté :))