Wie konvertiert man in Java am besten eine Zeichenkette im Format 2. Januar 2010 in ein Datumsformat?
Letztendlich möchte ich den Monat, den Tag und das Jahr als ganze Zahlen auflösen, damit ich die
Date date = new Date();
date.setMonth()..
date.setYear()..
date.setDay()..
date.setlong currentTime = date.getTime();
das Datum in die Zeit umrechnen kann.
Das ist der harte Weg, und diese java.util.Date
Setter Methoden sind seit Java 1.1 (1997) veraltet. Formatieren Sie das Datum einfach mit SimpleDateFormat
unter Verwendung eines Formatmusters, das auf die Eingabezeichenkette passt.
In Ihrem speziellen Fall von "2. Januar 2010" als Eingabezeichenfolge:
MMMM
für ihnString 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
Beachten Sie die Bedeutung des expliziten Arguments Locale
. Wenn Sie es weglassen, wird das Standardgebietsschema verwendet, das nicht unbedingt Englisch ist, wie es im Monatsnamen der Eingabezeichenkette verwendet wird. Wenn das Gebietsschema nicht mit der Eingabezeichenkette übereinstimmt, würden Sie verwirrenderweise eine java.text.ParseException
erhalten, auch wenn das Formatmuster gültig zu sein scheint.
Hier ist ein relevanter Auszug aus der javadoc, der alle verfügbaren Formatmuster auflistet:
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
Beachten Sie, dass bei den Mustern zwischen Groß- und Kleinschreibung unterschieden wird und dass textbasierte Muster mit vier oder mehr Zeichen die vollständige Form darstellen; andernfalls wird eine Kurz- oder abgekürzte Form verwendet, sofern verfügbar. So ist z.B. MMMMM
oder mehr unnötig.
Hier sind einige Beispiele für gültige SimpleDateFormat
-Muster, um eine gegebene Zeichenkette in ein Datum zu zerlegen:
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
Ein wichtiger Hinweis ist, dass SimpleDateFormat
nicht thread-sicher ist. Mit anderen Worten, Sie sollten sie niemals als statische oder Instanzvariable deklarieren und zuweisen und sie dann in verschiedenen Methoden/Threads wiederverwenden. Sie sollten sie immer ganz neu innerhalb des lokalen Bereichs der Methode erstellen.
Wenn Sie mit Java 8 oder neuer arbeiten, dann verwenden Sie DateTimeFormatter
(auch hier, klicken Sie auf den Link, um alle vordefinierten Formatierer und verfügbaren Formatmuster zu sehen; das Tutorial ist hier verfügbar). Diese neue API ist inspiriert von JodaTime.
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
Hinweis: Wenn Ihr Formatierungsmuster zufällig auch den Zeitteil enthält, dann verwenden Sie LocalDateTime#parse(text, formatter)
anstelle von LocalDate#parse(text, formatter)
. Und wenn Ihr Formatierungsmuster zufällig auch die Zeitzone enthält, dann verwenden Sie stattdessen ZonedDateTime#parse(text, formatter)
.
Hier ist ein relevanter Auszug aus der javadoc, der alle verfügbaren Formatierungsmuster auflistet:
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;
Bitte beachten Sie, dass es mehrere vordefinierte Formatierer für die gängigsten Muster gibt. So könnte man statt z.B. DateTimeFormatter.ofPattern("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
, DateTimeFormatter.RFC_1123_DATE_TIME
verwenden. Dies ist möglich, weil sie im Gegensatz zu SimpleDateFormat
thread-sicher sind. Sie könnten also auch Ihre eigene definieren, falls nötig.
Für ein bestimmtes Eingabe-String-Format müssen Sie keinen expliziten DateTimeFormatter
verwenden: ein Standard-ISO 8601 Datum, wie 2016-09-26T17:44:57Z, kann direkt mit LocalDateTime#parse(text)
geparst werden, da es bereits den ISO_LOCAL_DATE_TIME
Formatter verwendet. Ähnlich parst LocalDate#parse(text)
ein ISO-Datum ohne die Zeitkomponente (siehe ISO_LOCAL_DATE
), und ZonedDateTime#parse(text)
parst ein ISO-Datum mit einem Offset und einer Zeitzone (siehe ISO_ZONED_DATE_TIME
).
Ach ja, die Java-Datumsdiskussion, mal wieder. Für die Datumsmanipulation verwenden wir Date, Calendar, GregorianCalendar und SimpleDateFormat. Zum Beispiel mit Ihrem Januar-Datum als Eingabe:
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));
Dann können Sie das mit etwas wie:
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));
Bei der Beschäftigung mit der Klasse SimpleDateFormat ist es wichtig, sich daran zu erinnern, dass Date nicht thread-sicher ist und man ein einzelnes Date-Objekt nicht mit mehreren Threads teilen kann.
Außerdem gibt es einen großen Unterschied zwischen "m" und "M", wobei die Kleinschreibung für Minuten und die Großschreibung für Monat verwendet wird. Das gleiche gilt für "d" und "D". Dies kann zu subtilen Fehlern führen, die oft übersehen werden. Siehe Javadoc oder Guide to Convert String to Date in Java für weitere Details.