Java 8 Datum – LocalDate, LocalDateTime, Instant

Die Date Time API ist eines der größten Features des Java 8 Releases. Java fehlte von Anfang an ein konsistenter Ansatz für Datum und Uhrzeit, und die Java 8 Date Time API ist eine willkommene Ergänzung zu den Kern-Java-APIs.

Warum brauchen wir eine neue Java Date Time API?

Bevor wir uns die Java 8 Date Time API ansehen, lassen Sie uns sehen, warum wir eine neue API dafür brauchen. Es gab mehrere Probleme mit den vorhandenen Datum- und Zeitklassen in Java, einige davon sind:

  • Java-Datum-Zeit-Klassen sind nicht konsistent definiert, wir haben die Date-Klasse sowohl in den Paketen java.util als auch java.sql. Wiederum sind Formatierungs- und Parse-Klassen im Paket java.text definiert.
  • java.util.Date enthält sowohl Datum als auch Uhrzeitwerte, während java.sql.Date nur Datumswerte enthält. Dass dies im java.sql-Paket liegt, ergibt keinen Sinn. Außerdem haben beide Klassen denselben Namen, was an sich ein sehr schlechtes Design ist.
  • Es gibt keine klar definierten Klassen für Zeit, Zeitstempel, Formatierung und Parsing. Wir haben die abstrakte Klasse java.text.DateFormat für Parsing- und Formatierungsbedürfnisse. Üblicherweise wird die Klasse SimpleDateFormat für Parsing und Formatierung verwendet.
  • Alle Datumsklassen sind veränderlich, daher sind sie nicht thread-sicher. Dies ist eines der größten Probleme mit den Java-Datum- und Kalenderklassen.
  • Die Klasse Date bietet keine Internationalisierung und keine Unterstützung für Zeitzonen. Daher wurden die Klassen java.util.Calendar und java.util.TimeZone eingeführt, aber sie haben auch alle oben aufgeführten Probleme.

Es gibt einige weitere Probleme mit den Methoden, die in den Klassen Date und Calendar definiert sind, aber die oben genannten Probleme zeigen deutlich, dass eine robuste Date-Time-API in Java benötigt wurde. Deshalb spielte Joda Time eine entscheidende Rolle als hochwertiger Ersatz für die Java Date-Time-Anforderungen.

Java 8 Date-Time-Designprinzipien

Die Java 8 Date-Time-API ist eine Implementierung von JSR-310. Sie ist darauf ausgelegt, alle Mängel in den veralteten Date-Time-Implementierungen zu überwinden. Einige der Designprinzipien der neuen Date-Time-API sind:

  1. Unveränderlichkeit: Alle Klassen in der neuen Date-Time-API sind unveränderlich und gut für Mehrfadenumgebungen.

  2. Trennung von Anliegen: Die neue API trennt klar zwischen menschenlesbarer Datum/Uhrzeit und maschinenlesbarer Zeit (Unix-Zeitstempel). Sie definiert separate Klassen für Datum, Uhrzeit, Datum/Uhrzeit, Zeitstempel, Zeitzonen usw.

  3. Klarheit: Die Methoden sind klar definiert und führen in allen Klassen dieselbe Aktion aus. Zum Beispiel gibt es die Methode jetzt(), um die aktuelle Instanz zu erhalten. Es gibt format() und parse() Methoden in all diesen Klassen, anstatt eine separate Klasse dafür zu haben.

    Alle Klassen verwenden das Factory-Muster und das Strategie-Muster zur besseren Handhabung. Nachdem Sie die Methoden in einer der Klassen verwendet haben, wird die Arbeit mit anderen Klassen nicht schwer sein.

  4. Dienstprogrammbetrieb: Alle neuen Date-Time-API-Klassen verfügen über Methoden zur Ausführung gängiger Aufgaben wie Plus, Minus, Formatieren, Parsen, Abrufen des separaten Teils in Datum/Uhrzeit usw.

  5. Erweiterbar: Die neue Date-Time-API funktioniert im ISO-8601-Kalendersystem, aber wir können sie auch mit anderen nicht-ISO-Kalendern verwenden.

Date-Time-API-Pakete

Die Java 8 Date-Time-API besteht aus folgenden Paketen.

  1. java.time: Dies ist das Basismodul der neuen Java-Date-Time-API. Alle wichtigen Basisklassen gehören zu diesem Paket, wie LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration usw. Alle diese Klassen sind unveränderlich und threadsicher. In den meisten Fällen werden diese Klassen für die Bearbeitung gängiger Anforderungen ausreichen.
  2. java.time.chrono: Dieses Paket definiert generische APIs für nicht-ISO-Kalendersysteme. Wir können die Klasse AbstractChronology erweitern, um unser eigenes Kalendersystem zu erstellen.
  3. java.time.format: Dieses Paket enthält Klassen, die zur Formatierung und zum Parsen von Datum-Zeit-Objekten verwendet werden. In den meisten Fällen verwenden wir sie nicht direkt, da die Hauptklassen im java.time-Paket Formatierung und Parse-Methoden bereitstellen.
  4. java.time.temporal: Dieses Paket enthält temporäre Objekte, die wir verwenden können, um spezifische Daten oder Zeiten im Zusammenhang mit Datum-/Zeitobjekten herauszufinden. Zum Beispiel können wir diese verwenden, um den ersten oder letzten Tag des Monats herauszufinden. Sie können diese Methoden leicht identifizieren, weil sie immer das Format „withXXX“ haben.
  5. Paket java.time.zone: Dieses Paket enthält Klassen zur Unterstützung verschiedener Zeitzonen und ihrer Regeln.

Beispiele für Java 8 Datum-Zeit-API-Klassen

Wir haben uns die wichtigsten Teile der Java-Datum-Zeit-API angesehen. Es ist jetzt an der Zeit, sich die wichtigsten Klassen der Datum-Zeit-API mit Beispielen anzusehen.

1. LocalDate

LocalDate ist eine unveränderliche Klasse, die ein Datum im Standardformat JJJJ-MM-TT darstellt. Wir können die Methode now() verwenden, um das aktuelle Datum zu erhalten. Wir können auch Eingabeargumente für Jahr, Monat und Tag bereitstellen, um eine LocalDate-Instanz zu erstellen.

Diese Klasse bietet eine überladene Methode für now(), bei der wir ZoneId übergeben können, um Daten in einer bestimmten Zeitzone zu erhalten. Diese Klasse bietet die gleiche Funktionalität wie java.sql.Date.

package com.journaldev.java8.time;

import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;

/**
 * LocalDate Beispiele
 * @author pankaj
 *
 */
public class LocalDateExample {

	public static void main(String[] args) {
		
		//Aktuelles Datum
		LocalDate today = LocalDate.now();
		System.out.println("Current Date="+today);
		
		//Erstellung von LocalDate durch Bereitstellung von Eingabeargumenten
		LocalDate firstDay_2014 = LocalDate.of(2014, Month.JANUARY, 1);
		System.out.println("Specific Date="+firstDay_2014);
		
		
		//Versuch, Datum durch Bereitstellung ungültiger Eingaben zu erstellen
		//LocalDate feb29_2014 = LocalDate.of(2014, Month.FEBRUARY, 29);
		//Ausnahme im Thread "main" java.time.DateTimeException: 
		//Ungültiges Datum '29. Februar', da '2014' kein Schaltjahr ist
		
		//Aktuelles Datum in "Asia/Kolkata", Sie können es aus der ZoneId-Javadoc erhalten
		LocalDate todayKolkata = LocalDate.now(ZoneId.of("Asia/Kolkata"));
		System.out.println("Current Date in IST="+todayKolkata);

		//java.time.zone.ZoneRulesException: Unbekannte Zeitzone-ID: IST
		//LocalDate todayIST = LocalDate.now(ZoneId.of("IST"));
		
		//Datum von dem Basistag erhalten, d.h. 01/01/1970
		LocalDate dateFromBase = LocalDate.ofEpochDay(365);
		System.out.println("365th day from base date= "+dateFromBase);
		
		LocalDate hundredDay2014 = LocalDate.ofYearDay(2014, 100);
		System.out.println("100th day of 2014="+hundredDay2014);
	}

}

Die Erklärung der LocalDate-Methoden ist in den Kommentaren enthalten. Wenn wir dieses Programm ausführen, erhalten wir die folgende Ausgabe.

Current Date=2014-04-28
Specific Date=2014-01-01
Current Date in IST=2014-04-29
365th day from base date= 1971-01-01
100th day of 2014=2014-04-10

2. LocalTime

LocalTime ist eine unveränderliche Klasse, deren Instanz eine Zeit im menschenlesbaren Format darstellt. Ihr Standardformat ist hh:mm:ss.zzz. Genau wie LocalDate bietet diese Klasse Unterstützung für Zeitzonen und die Erstellung einer Instanz durch Übergeben von Stunde, Minute und Sekunde als Eingabeargumente.

package com.journaldev.java8.time;

import java.time.LocalTime;
import java.time.ZoneId;

/**
 * LocalTime Beispiele
 * @author pankaj
 *
 */
public class LocalTimeExample {

	public static void main(String[] args) {
		
		//Aktuelle Zeit
		LocalTime time = LocalTime.now();
		System.out.println("Current Time="+time);
		
		//Erstellen von LocalTime durch Bereitstellung von Eingabeargumenten
		LocalTime specificTime = LocalTime.of(12,20,25,40);
		System.out.println("Specific Time of Day="+specificTime);
		
		
		//Versuchen Sie, die Zeit durch Bereitstellung ungültiger Eingaben zu erstellen
		//LocalTime ungültigeZeit = LocalTime.of(25,20);
		//Ausnahme im Thread "main" java.time.DateTimeException: 
		//Ungültiger Wert für Stunde des Tages (gültige Werte 0 - 23): 25
		
		//Aktuelles Datum in "Asia/Kolkata", Sie können es aus der ZoneId-Javadoc erhalten
		LocalTime timeKolkata = LocalTime.now(ZoneId.of("Asia/Kolkata"));
		System.out.println("Current Time in IST="+timeKolkata);

		//java.time.zone.ZoneRulesException: Unbekannte Zeitzonen-ID: IST
		//LocalTime heuteIST = LocalTime.now(ZoneId.of("IST"));
		
		//Abrufen des Datums vom Basisdatum, d. h. 01.01.1970
		LocalTime specificSecondTime = LocalTime.ofSecondOfDay(10000);
		System.out.println("10000th second time= "+specificSecondTime);

	}

}

Ausgabe:

Current Time=15:51:45.240
Specific Time of Day=12:20:25.000000040
Current Time in IST=04:21:45.276
10000th second time= 02:46:40

3. LocalDateTime

LocalDateTime ist ein unveränderliches Datum-Zeit-Objekt, das ein Datum und eine Uhrzeit mit dem Standardformat yyyy-MM-dd-HH-mm-ss.zzz darstellt. Es bietet eine Factory-Methode, die LocalDate- und LocalTime-Eingabeargumente akzeptiert, um eine LocalDateTime-Instanz zu erstellen.

package com.journaldev.java8.time;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset;

public class LocalDateTimeExample {

	public static void main(String[] args) {
		
		//Aktuelles Datum
		LocalDateTime today = LocalDateTime.now();
		System.out.println("Current DateTime="+today);
		
		//Aktuelles Datum unter Verwendung von LocalDate und LocalTime
		today = LocalDateTime.of(LocalDate.now(), LocalTime.now());
		System.out.println("Current DateTime="+today);
		
		//Erstellen von LocalDateTime durch Bereitstellung von Eingabeargumenten
		LocalDateTime specificDate = LocalDateTime.of(2014, Month.JANUARY, 1, 10, 10, 30);
		System.out.println("Specific Date="+specificDate);
		
		
		//Versuch, ein Datum durch Bereitstellung ungültiger Eingaben zu erstellen
		//LocalDateTime feb29_2014 = LocalDateTime.of(2014, Month.FEBRUARY, 28, 25,1,1);
		//Ausnahme im Thread "main" java.time.DateTimeException: 
		//Ungültiger Wert für HourOfDay (gültige Werte 0 - 23): 25

		
		//Aktuelles Datum in "Asia/Kolkata", Sie können es aus der ZoneId-Javadoc erhalten
		LocalDateTime todayKolkata = LocalDateTime.now(ZoneId.of("Asia/Kolkata"));
		System.out.println("Current Date in IST="+todayKolkata);

		//java.time.zone.ZoneRulesException: Unbekannte Zeitzonen-ID: IST
		//LocalDateTime todayIST = LocalDateTime.now(ZoneId.of("IST"));
		
		//Abrufen des Datums vom Basisdatum d. h. 01.01.1970
		LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(10000, 0, ZoneOffset.UTC);
		System.out.println("10000th second time from 01/01/1970= "+dateFromBase);

	}

}

In allen drei Beispielen haben wir gesehen, dass bei der Bereitstellung ungültiger Argumente zum Erstellen von Datum/Uhrzeit eine java.time.DateTimeException ausgelöst wird, die eine RuntimeException ist, sodass wir sie nicht explizit abfangen müssen.

Wir haben auch festgestellt, dass wir Datum-/Uhrzeitdaten erhalten können, indem wir ZoneId übergeben. Sie können die Liste der unterstützten ZoneId-Werte aus ihrer Java-Dokumentation erhalten. Wenn wir die obige Klasse ausführen, erhalten wir die folgende Ausgabe.

Current DateTime=2014-04-28T16:00:49.455
Current DateTime=2014-04-28T16:00:49.493
Specific Date=2014-01-01T10:10:30
Current Date in IST=2014-04-29T04:30:49.493
10000th second time from 01/01/1970= 1970-01-01T02:46:40

4. Instant

Die Instant-Klasse wird verwendet, um mit einem maschinenlesbaren Zeitformat zu arbeiten. Instant speichert Datum und Uhrzeit im Unix-Zeitstempelformat.

package com.journaldev.java8.time;

import java.time.Duration;
import java.time.Instant;

public class InstantExample {

	public static void main(String[] args) {
		//Aktueller Zeitstempel
		Instant timestamp = Instant.now();
		System.out.println("Current Timestamp = "+timestamp);
		
		//Instant aus Zeitstempel
		Instant specificTime = Instant.ofEpochMilli(timestamp.toEpochMilli());
		System.out.println("Specific Time = "+specificTime);
		
		//Dauerbeispiel
		Duration thirtyDay = Duration.ofDays(30);
		System.out.println(thirtyDay);
	}

}

Ausgabe:

Current Timestamp = 2014-04-28T23:20:08.489Z
Specific Time = 2014-04-28T23:20:08.489Z
PT720H

Java 8-Datums-API-Dienstprogramme

Die meisten der Prinzipklassen für Datum und Uhrzeit bieten verschiedene Hilfsmethoden wie Plus/Minus Tage, Wochen, Monate usw. Es gibt einige andere Hilfsmethoden zum Anpassen des Datums mithilfe von TemporalAdjuster und zum Berechnen des Zeitraums zwischen zwei Daten.

package com.journaldev.java8.time;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.temporal.TemporalAdjusters;

public class DateAPIUtilities {

	public static void main(String[] args) {
		
		LocalDate today = LocalDate.now();
		
		//Holen Sie das Jahr und überprüfen Sie, ob es ein Schaltjahr ist
		System.out.println("Year "+today.getYear()+" is Leap Year? "+today.isLeapYear());
		
		//Vergleichen Sie zwei LocalDate auf Vorher und Nachher
		System.out.println("Today is before 01/01/2015? "+today.isBefore(LocalDate.of(2015,1,1)));
		
		//Erstellen Sie LocalDateTime aus LocalDate
		System.out.println("Current Time="+today.atTime(LocalTime.now()));
		
		//Plus- und Minusoperationen
		System.out.println("10 days after today will be "+today.plusDays(10));
		System.out.println("3 weeks after today will be "+today.plusWeeks(3));
		System.out.println("20 months after today will be "+today.plusMonths(20));

		System.out.println("10 days before today will be "+today.minusDays(10));
		System.out.println("3 weeks before today will be "+today.minusWeeks(3));
		System.out.println("20 months before today will be "+today.minusMonths(20));
		
		//Temporal Adjusters zum Anpassen der Daten
		System.out.println("First date of this month= "+today.with(TemporalAdjusters.firstDayOfMonth()));
		LocalDate lastDayOfYear = today.with(TemporalAdjusters.lastDayOfYear());
		System.out.println("Last date of this year= "+lastDayOfYear);
		
		Period period = today.until(lastDayOfYear);
		System.out.println("Period Format= "+period);
		System.out.println("Months remaining in the year= "+period.getMonths());		
	}
}

Output:

Year 2014 is Leap Year? false
Today is before 01/01/2015? true
Current Time=2014-04-28T16:23:53.154
10 days after today will be 2014-05-08
3 weeks after today will be 2014-05-19
20 months after today will be 2015-12-28
10 days before today will be 2014-04-18
3 weeks before today will be 2014-04-07
20 months before today will be 2012-08-28
First date of this month= 2014-04-01
Last date of this year= 2014-12-31
Period Format= P8M3D
Months remaining in the year= 8

Java 8 Datum Parsen und Formatieren

Es ist sehr üblich, ein Datum in verschiedene Formate zu formatieren und dann einen String zu parsen, um die Datum-Zeit-Objekte zu erhalten.

package com.journaldev.java8.time;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class DateParseFormatExample {

	public static void main(String[] args) {
		
		//Formatbeispiele
		LocalDate date = LocalDate.now();
		//Standardformat
		System.out.println("Default format of LocalDate="+date);
		//Spezifisches Format
		System.out.println(date.format(DateTimeFormatter.ofPattern("d::MMM::uuuu")));
		System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE));
		
		
		LocalDateTime dateTime = LocalDateTime.now();
		//Standardformat
		System.out.println("Default format of LocalDateTime="+dateTime);
		//Spezifisches Format
		System.out.println(dateTime.format(DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss")));
		System.out.println(dateTime.format(DateTimeFormatter.BASIC_ISO_DATE));
		
		Instant timestamp = Instant.now();
		//Standardformat
		System.out.println("Default format of Instant="+timestamp);
		
		//Parse-Beispiele
		LocalDateTime dt = LocalDateTime.parse("27::Apr::2014 21::39::48",
				DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss"));
		System.out.println("Default format after parsing = "+dt);
	}

}

Output:

Default format of LocalDate=2014-04-28
28::Apr::2014
20140428
Default format of LocalDateTime=2014-04-28T16:25:49.341
28::Apr::2014 16::25::49
20140428
Default format of Instant=2014-04-28T23:25:49.342Z
Default format after parsing = 2014-04-27T21:39:48

Java-Datums-API Legacy-Datum-Zeit-Unterstützung

Legacy-Datum-/Zeit-Klassen werden in fast allen Anwendungen verwendet, daher ist eine Rückwärtskompatibilität ein Muss. Deshalb gibt es mehrere Hilfsmethoden, mit denen wir Legacy-Klassen in neue Klassen und umgekehrt konvertieren können.

package com.journaldev.java8.time;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class DateAPILegacySupport {

	public static void main(String[] args) {
		
		//Datum zu Instant
		Instant timestamp = new Date().toInstant();
		//Jetzt können wir Instant in LocalDateTime oder andere ähnliche Klassen konvertieren
		LocalDateTime date = LocalDateTime.ofInstant(timestamp, 
						ZoneId.of(ZoneId.SHORT_IDS.get("PST")));
		System.out.println("Date = "+date);
		
		//Kalender zu Instant
		Instant time = Calendar.getInstance().toInstant();
		System.out.println(time);
		//Zeitzone zu ZoneId
		ZoneId defaultZone = TimeZone.getDefault().toZoneId();
		System.out.println(defaultZone);
		
		//ZonedDateTime aus einem bestimmten Kalender
		ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();
		System.out.println(gregorianCalendarDateTime);
		
		//Datum-API zu Legacy-Klassen
		Date dt = Date.from(Instant.now());
		System.out.println(dt);
		
		TimeZone tz = TimeZone.getTimeZone(defaultZone);
		System.out.println(tz);
		
		GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);
		System.out.println(gc);
		
	}

}

Output:

Date = 2014-04-28T16:28:54.340
2014-04-28T23:28:54.395Z
America/Los_Angeles
2014-04-28T16:28:54.404-07:00[America/Los_Angeles]
Mon Apr 28 16:28:54 PDT 2014
sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]
java.util.GregorianCalendar[time=1398727734404,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2014,MONTH=3,WEEK_OF_YEAR=18,WEEK_OF_MONTH=5,DAY_OF_MONTH=28,DAY_OF_YEAR=118,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=28,SECOND=54,MILLISECOND=404,ZONE_OFFSET=-28800000,DST_OFFSET=3600000]

Wie Sie sehen können, sind die toString()-Methoden der Legacy-Klassen TimeZone und GregorianCalendar zu umfangreich und nicht benutzerfreundlich.

Fazit

I like this new Date Time API a lot. Some of the most used classes will be LocalDate and LocalDateTime. It’s very easy to work with the new classes. And, having similar methods that does a particular job makes it easy to find. It will take some time from moving legacy classes to new Date Time classes, but I believe it will be worth the time and effort.

Source:
https://www.digitalocean.com/community/tutorials/java-8-date-localdate-localdatetime-instant