Java 8 Date und Time API: Neue Datumsfunktionen

Mit Java 8 kommt eine neue, mächtige Date und Time API in dem java.time Paket. Das wurde aber auch Zeit!

Folgende Grafik bietet grundsätzlich einen Überblick über die Struktur der neuen API.

UML Modell - Quelle: heise.de
UML Modell – Quelle: heise.de

LocalDate

Wir schauen uns zunächst java.time.LocalDate an. Ein LocalDate repräsentiert ein einziges Datum mit Jahr, Monat und Tag, also ohne Zeit. Wenn man dazu noch die Zeit benötigt, ist LocalDateTime die Klasse der Wahl, dazu aber später mehr.

// das aktuelle Datum
LocalDate currentDate = LocalDate.now();

// Ist das aktuelle Jahr ein Schaltjahr?
boolean isLeapYear = currentDate.isLeapYear();

// 10.02.2014
LocalDate tenthFeb2014 = LocalDate.of(2014, Month.FEBRUARY, 10);

// Monate starten bei 1, 01.08.2014
LocalDate firstAug2014 = LocalDate.of(2014, 8, 1);

// Der 65. Tag in 2010 (06.03.2010)
LocalDate sixtyFifthDayOf2010 = LocalDate.ofYearDay(2010, 65);

LocalTime

Die Klasse java.time.LocalTime repräsentiert eine Tageszeit (Stunde, Minute, Sekunde, Nanosekunde).

LocalTime currentTime = LocalTime.now(); // Aktuelle Zeit
LocalTime midday = LocalTime.of(12, 0); // 12:00 Uhr
LocalTime afterMidday = LocalTime.of(13, 30, 15); // 13:30:15 Uhr
 
// 12345. Sekunde am Tag (03:25:45 Uhr)
LocalTime fromSecondsOfDay = LocalTime.ofSecondOfDay(12345);

LocalDateTime

Die Klasse LocalDateTime kombiniert LocalTime und LocalDate und bietet ein Datum (Jahr, Monat, Tag) + die Zeit (Stunde, Minute, Sekunde, Nanosekunde).

/ Aktuelles Datum samt Zeit
LocalDateTime currentDateTime = LocalDateTime.now();
 
// 02.10.2014 12:30 Uhr
LocalDateTime secondAug2014 = LocalDateTime.of(2014, 10, 2, 12, 30);
 
// 24.12.2014 - 12:00 Uhr
LocalDateTime christmas2014 = LocalDateTime.of(2014, Month.DECEMBER, 24, 12, 0);

Informationen über das Datum und die Zeit

LocalDate date = LocalDate.of(2014, 2, 15); // 15.02.2014
 
boolean isBefore = LocalDate.now().isBefore(date); // false
 
// Informationen über den Monat
Month february = date.getMonth(); // Februar
int februaryIntValue = february.getValue(); // 2
int minLength = february.minLength(); // 28
int maxLength = february.maxLength(); // 29 (wegen dem Schaltjahr)
Month firstMonthOfQuarter = february.firstMonthOfQuarter(); // Januar, erster Monat im Quartal
 
// Informationen über das Jahr
int year = date.getYear(); // 2014
int dayOfYear = date.getDayOfYear(); // 46
int lengthOfYear = date.lengthOfYear(); // 365
boolean isLeapYear = date.isLeapYear(); // false (kein Schaltjahr)
 
DayOfWeek dayOfWeek = date.getDayOfWeek();
int dayOfWeekIntValue = dayOfWeek.getValue(); // 6
String dayOfWeekName = dayOfWeek.name(); // SATURDAY
 
int dayOfMonth = date.getDayOfMonth(); // 15
LocalDateTime startOfDay = date.atStartOfDay(); // 15.02.2014 00:00 Uhr
 
// Informationen über eine Zeit
LocalTime time = LocalTime.of(15, 30); // 15:30:00 Uhr
int hour = time.getHour(); // 15
int second = time.getSecond(); // 0
int minute = time.getMinute(); // 30
int secondOfDay = time.toSecondOfDay(); // 55800

Datum/Zeit manipulieren

Über die neue API können wir sehr angenehm ein Datum oder eine Zeit manipulieren.

// Morgen
LocalDate tomorrow = LocalDate.now().plusDays(1);
 
// Vor 5 Stunden und 30 Minuten
LocalDateTime dateTime = LocalDateTime.now().minusHours(5).minusMinutes(30);

Ebenfalls nützlich zur Manipulation sind die TemporalAdjusters. Dazu importen wir java.time.temporal.TemporalAdjusters.*.

LocalDate date = LocalDate.of(2014, Month.FEBRUARY, 25); // 25.02.2014
 
// Erster Tag im Februar - 01.02.2014
LocalDate firstDayOfMonth = date.with(TemporalAdjusters.firstDayOfMonth());
 
// Letzter Tag im Februar - 28.02.2014
LocalDate lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());

TimeZones/Zeitzonen

Wenn wir mit Zeitzonen in der neuen API arbeiten möchten, können wir java.time.ZonedDateTime oder java.time.OffsetDateTime nutzen.

ZoneId losAngeles = ZoneId.of("America/Los_Angeles");
ZoneId berlin = ZoneId.of("Europe/Berlin");
 
// 20.02.2014 12:00 Uhr
LocalDateTime dateTime = LocalDateTime.of(2014, 02, 20, 12, 0);
 
// 20.02.2014 12:00 Uhr, Europe/Berlin (+01:00)
ZonedDateTime berlinDateTime = ZonedDateTime.of(dateTime, berlin);
 
// 20.02.2014 03:00 Uhr, America/Los_Angeles (-08:00)
ZonedDateTime losAngelesDateTime = berlinDateTime.withZoneSameInstant(losAngeles);
 
int offsetInSeconds = losAngelesDateTime.getOffset().getTotalSeconds(); // -28800
 
// Ein Set von allen verfügbaren Zeitzonen
Set<String> allZoneIds = ZoneId.getAvailableZoneIds();
 
// Mit Offsets arbeiten
LocalDateTime date = LocalDateTime.of(2013, Month.JULY, 20, 3, 30);
ZoneOffset offset = ZoneOffset.of("+05:00");
 
// 20.07.2013 03:30 Uhr +05:00
OffsetDateTime plusFive = OffsetDateTime.of(date, offset);
 
// 19.07.2013 20:30 Uhr -02:00
OffsetDateTime minusTwo = plusFive.withOffsetSameInstant(ZoneOffset.ofHours(-2));

Timestamps/Zeitstempel

Über die Klasse java.time.Instant können wir Timestamps (Zeitstempel) benutzen. Ein solcher Timestamp beginnt seine Zählung ab dem 1. Januar 1970, der auch als EPOCH bekannt ist. Die Werte von Instant können negativ sein. Als Standard wird ISO 8601 verwendet.

// Aktuelle Zeit
Instant now = Instant.now();
 
// Unix timestamp, 01.01.2010 12:00:00 Uhr
Instant fromUnixTimestamp = Instant.ofEpochSecond(1262347200);
 
// Gleiche Zeit in Millisekunden
Instant fromEpochMilli = Instant.ofEpochMilli(1262347200000l);
 
// ISO 8601 parsen
Instant fromIso8601 = Instant.parse("2010-01-01T12:00:00Z");
 
// toString() gibt Zeitstempel in ISO 8601 Format aus, Z.B. 2014-02-15T01:02:03Z
String toIso8601 = now.toString();
 
// Als Unix Zeitstempel
long toUnixTimestamp = now.getEpochSecond();
 
// In Millisekunden
long toEpochMillis = now.toEpochMilli();
 
// Plus/Minus Methoden sind auch hier verfügbar
Instant nowPlusTenSeconds = now.plusSeconds(10);

Periods and Durations/Zeiträume und Dauer

Period (Zeitraum) und Duration (Dauer) sind zwei weitere wichtige Klassen in der neuen API. Ein Zeitraum basiert auf einem Datum (Jahr, Monat, Tag) und eine Dauer basiert auf einer Zeit. Duration (Dauer) wird bei Instants genutzt. Periods und Durations können negativ sein, wenn das erste Datum/die erste Zeit vor dem zweiten liegt.

// Zeiträume
 
LocalDate firstDate = LocalDate.of(2010, 5, 17); // 17.05.2010
LocalDate secondDate = LocalDate.of(2015, 3, 7); // 07.03.2015
Period period = Period.between(firstDate, secondDate);
 
int days = period.getDays(); // 18
int months = period.getMonths(); // 9
int years = period.getYears(); // 4
boolean isNegative = period.isNegative(); // false
 
Period twoMonthsAndFiveDays = Period.ofMonths(2).plusDays(5);
LocalDate sixthOfJanuary = LocalDate.of(2014, 1, 6);
 
// Zwei Monate und 5 Tage zum 06.01.2014 hinzufügen -> 11.03.2014
LocalDate eleventhOfMarch = sixthOfJanuary.plus(twoMonthsAndFiveDays);
 
 
// Dauer
 
Instant firstInstant= Instant.ofEpochSecond( 1294881180 ); // 13.01.2011 01:13 Uhr
Instant secondInstant = Instant.ofEpochSecond(1294708260); // 11.01.2011 01:11 Uhr
 
Duration between = Duration.between(firstInstant, secondInstant);
 
// Negativ, da firstInstant weiter in der Zukunft ist als secondInstant (-172920)
long seconds = between.getSeconds();
 
// Ergebnis in Minuten (2882)
long absoluteResult = between.abs().toMinutes();
 
// Zwei Stunden in Sekunden (7200)
long twoHoursInSeconds = Duration.ofHours(2).getSeconds();

Formatieren und Parsen

Über die Methoden format() und parse() lassen sich Datum und Zeit formatieren und parsen.

// 01.04.2014 10:45 uhr
LocalDateTime dateTime = LocalDateTime.of(2014, Month.APRIL, 1, 10, 45);
 
// Als ISO-Datum formatieren (20140220)
String asBasicIsoDate = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE);
 
// Als ISO-Wochendatum formatieren (2014-W08-4)
String asIsoWeekDate = dateTime.format(DateTimeFormatter.ISO_WEEK_DATE);
 
// Als ISO-Zeit formatieren (2014-02-20T20:04:05.867)
String asIsoDateTime = dateTime.format(DateTimeFormatter.ISO_DATE_TIME);
 
// Mithilfe eines eigenen Patterns formatieren (01/04/2014)
String asCustomPattern = dateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
 
// Deutsche (lokalisiert) Formatierung (1. April 2014)
String germanDate = dateTime.format(DateTimeFormatter.ofPattern("d. MMMM yyyy", new Locale("de")));
 
// Deutsche Formatierung, abgekürzt (01.04.14 10:45)
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
    .withLocale(new Locale("de"));
String germanDateTime = dateTime.format(formatter);
 
// Datum parsen
LocalDate fromIsoDate = LocalDate.parse("2014-01-20");
LocalDate fromIsoWeekDate = LocalDate.parse("2014-W14-2", DateTimeFormatter.ISO_WEEK_DATE);
LocalDate fromCustomPattern = LocalDate.parse("20.01.2014", DateTimeFormatter.ofPattern("dd.MM.yyyy"));

Konvertieren

Wir brauchen natürlich auch noch eine Option zum Konvertieren von dem alten Standard zur neuen API und umgekehrt.

// LocalDate/LocalTime <-> LocalDateTime
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTimeFromDateAndTime = LocalDateTime.of(date, time);
LocalDate dateFromDateTime = LocalDateTime.now().toLocalDate();
LocalTime timeFromDateTime = LocalDateTime.now().toLocalTime();
 
// Instant <-> LocalDateTime
Instant instant = Instant.now();
LocalDateTime dateTimeFromInstant = LocalDateTime.ofInstant(instant, ZoneId.of("America/Los_Angeles"));
Instant instantFromDateTime = LocalDateTime.now().toInstant(ZoneOffset.ofHours(-2));
 
// Von alten Date/Calendar/Timezone Klassen konvertieren
Instant instantFromDate = new Date().toInstant();
Instant instantFromCalendar = Calendar.getInstance().toInstant();
ZoneId zoneId = TimeZone.getDefault().toZoneId();
ZonedDateTime zonedDateTimeFromGregorianCalendar = new GregorianCalendar().toZonedDateTime();
 
// Zu alten Klassen konvertieren
Date dateFromInstant = Date.from(Instant.now());
TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("America/Los_Angeles"));
GregorianCalendar gregorianCalendar = GregorianCalendar.from(ZonedDateTime.now());

Quellen

Als Hauptquelle für diesen Artikel über die Java 8 Date und Time API und für die Codebeispiele dient mscharhag.com.

Comments

comments

Leave a Reply