Quelle est la meilleure façon de convertir une chaîne de caractères au format 2 janvier 2010 en une date en Java ?
En fin de compte, je veux décomposer le mois, le jour et l'année sous forme d'entiers afin de pouvoir utiliser les fonctions suivantes
Date date = new Date();
date.setMonth()..
date.setYear()..
date.setDay()..
date.setlong currentTime = date.getTime();
pour convertir la date en heure.
C'est la manière forte, et ces méthodes de setter java.util.Date
ont été dépréciées depuis Java 1.1 (1997). [Il suffit de formater la date avec SimpleDateFormat
en utilisant un modèle de format correspondant à la chaîne d'entrée][1].
Dans votre cas spécifique de "2 janvier 2010" comme chaîne d'entrée :
MMMM
.d
pour cela.yyyy
.String string = "January 2, 2010";
DateFormat format = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH);
Date date = format.parse(string);
System.out.println(date); // Sat Jan 02 00:00:00 GMT 2010
Notez l'importance de l'argument explicite Locale
. Si vous l'omettez, alors il utilisera la [locale par défaut][2] qui n'est pas nécessairement l'anglais tel qu'il est utilisé dans le nom du mois de la chaîne d'entrée. Si la locale ne correspond pas à la chaîne d'entrée, alors vous obtiendrez une java.text.ParseException
même si le modèle de format semble valide.
Voici un extrait pertinent de [la javadoc][1], listant tous les modèles de format disponibles :
Letter Date or Time Component Presentation Examples
------ ---------------------- ------------------ -------------------------------------
G Era designator Text AD
y Year Year 1996; 96
Y Week year Year 2009; 09
M/L Month in year Month July; Jul; 07
w Week in year Number 27
W Week in month Number 2
D Day in year Number 189
d Day in month Number 10
F Day of week in month Number 2
E Day in week Text Tuesday; Tue
u Day number of week Number 1
a Am/pm marker Text PM
H Hour in day (0-23) Number 0
k Hour in day (1-24) Number 24
K Hour in am/pm (0-11) Number 0
h Hour in am/pm (1-12) Number 12
m Minute in hour Number 30
s Second in minute Number 55
S Millisecond Number 978
z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone RFC 822 time zone -0800
X Time zone ISO 8601 time zone -08; -0800; -08:00
Notez que les motifs sont sensibles à la casse et que les motifs textuels de quatre caractères ou plus représentent la forme complète ; sinon, une forme courte ou abrégée est utilisée si elle est disponible. Ainsi, par exemple, MMMMM
ou plus est inutile.
Voici quelques exemples de motifs SimpleDateFormat
valides pour analyser une chaîne de caractères donnée en date :
Input string Pattern
------------------------------------ ----------------------------
2001.07.04 AD at 12:08:56 PDT yyyy.MM.dd G 'at' HH:mm:ss z
Wed, Jul 4, '01 EEE, MMM d, ''yy
12:08 PM h:mm a
12 o'clock PM, Pacific Daylight Time hh 'o''clock' a, zzzz
0:08 PM, PDT K:mm a, z
02001.July.04 AD 12:08 PM yyyyy.MMMM.dd GGG hh:mm aaa
Wed, 4 Jul 2001 12:08:56 -0700 EEE, d MMM yyyy HH:mm:ss Z
010704120856-0700 yyMMddHHmmssZ
2001-07-04T12:08:56.235-0700 yyyy-MM-dd'T'HH:mm:ss.SSSZ
2001-07-04T12:08:56.235-07:00 yyyy-MM-dd'T'HH:mm:ss.SSSXXX
2001-W27-3 YYYY-'W'ww-u
Une note importante est que SimpleDateFormat
n'est pas thread safe. En d'autres termes, vous ne devez jamais le déclarer et l'assigner en tant que variable statique ou d'instance pour ensuite le réutiliser dans différentes méthodes/threads. Vous devez toujours la créer à l'état neuf dans la portée locale de la méthode.
Si vous utilisez Java 8 ou une version plus récente, utilisez [DateTimeFormatter
][3] (également ici, cliquez sur le lien pour voir tous les formateurs prédéfinis et les modèles de format disponibles ; [le tutoriel est disponible ici][4]). Cette nouvelle API est inspirée de [JodaTime][5].
String string = "January 2, 2010";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
LocalDate date = LocalDate.parse(string, formatter);
System.out.println(date); // 2010-01-02
Remarque : si votre modèle de format contient également la partie temps, utilisez [LocalDateTime#parse(text, formatter)
][6] au lieu de [LocalDate#parse(text, formatter)
][7]. Et si votre modèle de format contient également le fuseau horaire, utilisez [ZonedDateTime#parse(text, formatter)
][8] à la place.
Voici un extrait pertinent de [la javadoc][3], qui liste tous les modèles de format disponibles :
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;
Notez qu'il a plusieurs [formateurs prédéfinis][9] pour les modèles les plus populaires. Ainsi, au lieu de par exemple DateTimeFormatter.ofPattern("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
, vous pourriez utiliser DateTimeFormatter.RFC_1123_DATE_TIME
. Ceci est possible car ils sont, contrairement à SimpleDateFormat
, thread safe. Vous pouvez donc aussi définir les vôtres, si nécessaire.
Pour un format de chaîne d'entrée particulier, vous n'avez pas besoin d'utiliser un DateTimeFormatter
explicite : une date standard [ISO 8601][10], comme 2016-09-26T17:44:57Z, peut être analysée directement avec [LocalDateTime#parse(text)
][11] car elle utilise déjà le formateur [ISO_LOCAL_DATE_TIME
][12]. De même, [LocalDate#parse(text)
][13] analyse une date ISO sans la composante temporelle (voir [ISO_LOCAL_DATE
][14]), et [ZonedDateTime#parse(text)
][15] analyse une date ISO avec un décalage et un fuseau horaire ajouté (voir [ISO_ZONED_DATE_TIME
][16]).
[1] : http://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html [2] : http://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#getDefault-- [3] : https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html [4] : https://docs.oracle.com/javase/tutorial/datetime/iso/format.html [5] : http://www.joda.org/joda-time/ [6] : https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#parse-java.lang.CharSequence-java.time.format.DateTimeFormatter- [7] : https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#parse-java.lang.CharSequence-java.time.format.DateTimeFormatter- [8] : https://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html#parse-java.lang.CharSequence-java.time.format.DateTimeFormatter- [9] : https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#predefined [10] : https://en.wikipedia.org/wiki/ISO_8601 [11] : https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#parse-java.lang.CharSequence- [12] : https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE_TIME [13] : https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#parse-java.lang.CharSequence- [14] : https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE [15] : https://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html#parse-java.lang.CharSequence- [16] : https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_ZONED_DATE_TIME
Ah oui, la discussion sur la date en Java, encore une fois. Pour gérer la manipulation des dates, nous utilisons [Date][1], [Calendar][2], [GregorianCalendar][3] et [SimpleDateFormat][4]. Par exemple, en utilisant votre date de janvier comme entrée :
Calendar mydate = new GregorianCalendar();
String mystring = "January 2, 2010";
Date thedate = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH).parse(mystring);
mydate.setTime(thedate);
//breakdown
System.out.println("mydate -> "+mydate);
System.out.println("year -> "+mydate.get(Calendar.YEAR));
System.out.println("month -> "+mydate.get(Calendar.MONTH));
System.out.println("dom -> "+mydate.get(Calendar.DAY_OF_MONTH));
System.out.println("dow -> "+mydate.get(Calendar.DAY_OF_WEEK));
System.out.println("hour -> "+mydate.get(Calendar.HOUR));
System.out.println("minute -> "+mydate.get(Calendar.MINUTE));
System.out.println("second -> "+mydate.get(Calendar.SECOND));
System.out.println("milli -> "+mydate.get(Calendar.MILLISECOND));
System.out.println("ampm -> "+mydate.get(Calendar.AM_PM));
System.out.println("hod -> "+mydate.get(Calendar.HOUR_OF_DAY));
Ensuite, vous pouvez la manipuler avec quelque chose comme :
Calendar now = Calendar.getInstance();
mydate.set(Calendar.YEAR,2009);
mydate.set(Calendar.MONTH,Calendar.FEBRUARY);
mydate.set(Calendar.DAY_OF_MONTH,25);
mydate.set(Calendar.HOUR_OF_DAY,now.get(Calendar.HOUR_OF_DAY));
mydate.set(Calendar.MINUTE,now.get(Calendar.MINUTE));
mydate.set(Calendar.SECOND,now.get(Calendar.SECOND));
// or with one statement
//mydate.set(2009, Calendar.FEBRUARY, 25, now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
System.out.println("mydate -> "+mydate);
System.out.println("year -> "+mydate.get(Calendar.YEAR));
System.out.println("month -> "+mydate.get(Calendar.MONTH));
System.out.println("dom -> "+mydate.get(Calendar.DAY_OF_MONTH));
System.out.println("dow -> "+mydate.get(Calendar.DAY_OF_WEEK));
System.out.println("hour -> "+mydate.get(Calendar.HOUR));
System.out.println("minute -> "+mydate.get(Calendar.MINUTE));
System.out.println("second -> "+mydate.get(Calendar.SECOND));
System.out.println("milli -> "+mydate.get(Calendar.MILLISECOND));
System.out.println("ampm -> "+mydate.get(Calendar.AM_PM));
System.out.println("hod -> "+mydate.get(Calendar.HOUR_OF_DAY));
[1] : http://download.oracle.com/javase/1.4.2/docs/api/java/util/Date.html [2] : http://download.oracle.com/javase/6/docs/api/java/util/Calendar.html [3] : http://download.oracle.com/javase/6/docs/api/java/util/GregorianCalendar.html [4] : http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html
Pendant que nous traitons la classe SimpleDateFormat, il est important de se rappeler que Date n'est pas thread-safe et que vous ne pouvez pas partager un seul objet Date avec plusieurs threads.
Il existe également une grande différence entre "m" et "M", la minuscule étant utilisée pour les minutes et la majuscule pour le mois. Il en va de même pour "d" et "D". Cela peut causer des bogues subtils qui sont souvent négligés. Voir [Javadoc][1] ou [Guide to Convert String to Date in Java][2] pour plus de détails.
[1] : http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html [2] : http://javarevisited.blogspot.com/2011/09/step-by-step-guide-to-convert-string-to.html