Java LocalTime
Zeiten ohne Datum oder Zeitzone in Java mit LocalTime darstellen.
LocalTime ist das Gegenstück zu LocalDate: eine Tageszeit — Stunde, Minute, Sekunde, Nanosekunde — ohne Datum und ohne Zeitzone. Sie repräsentiert dieselbe Uhrzeitangabe an jedem Kalendertag überall: LocalTime.of(9, 30) ist halb zehn an jedem Tag in jeder Stadt.
Das ist der richtige Typ für eine wiederkehrende Tageszeit — ein Laden öffnet um 09:30, ein täglicher Cron-ähnlicher Job um 03:15, ein Meeting, das unabhängig vom Datum um 14:00 beginnt. Es ist nicht der richtige Typ für „den Moment, in dem der Benutzer heute um 14:30 auf Senden geklickt hat" — dafür braucht man ein Datum und wahrscheinlich eine Zeitzone. Beides zusammen ergibt LocalDateTime, das Thema des nächsten Kapitels.
Erstellen
LocalTime now = LocalTime.now(); // current time in the JVM default zone
LocalTime nine = LocalTime.of(9, 0); // hour, minute
LocalTime nineThirty = LocalTime.of(9, 30, 15); // hour, minute, second
LocalTime nineThirtyNanos = LocalTime.of(9, 30, 15, 500_000_000); // + nanosecond (0 ..999_999_999)
LocalTime parsed = LocalTime.parse("09:30:15"); // ISO-8601 HH:mm[:ss[.nnnnnnnnn]]Die vordefinierten Konstanten sind nützlich für Randbedingungen:
LocalTime.MIDNIGHT // 00:00
LocalTime.NOON // 12:00
LocalTime.MIN // 00:00:00.000000000
LocalTime.MAX // 23:59:59.999999999MIN und MAX sind besonders nützlich, wenn sie mit einem LocalDate kombiniert werden, um einen ganzen Tag abzudecken: LocalDateTime.of(date, LocalTime.MIN) ist „Mitternacht am Beginn des Datums"; LocalTime.MAX ist die letzte darstellbare Nanosekunde des Tages.
Auflösung: Nanosekunden
LocalTime ist auf die Nanosekunde genau — neun Stellen Auflösung (1 Sekunde = 1.000.000.000 ns). Auf den meisten Betriebssystemen beträgt die tatsächliche Uhrenauflösung Millisekunden (1.000.000 ns) oder Mikrosekunden (1.000 ns); die zusätzliche Genauigkeit ist vorhanden, damit der Typ keine Informationen verliert, wenn er mit Systemen interagiert, die Uhren mit höherer Auflösung haben.
Direkte Accessors:
time.getHour(); // 0-23
time.getMinute(); // 0-59
time.getSecond(); // 0-59
time.getNano(); // 0-999_999_999Es gibt kein getMilli(); wenn Millisekunden benötigt werden, teile den Nanowert: time.getNano() / 1_000_000.
24-Stunden-Format, kein AM/PM
LocalTime arbeitet intern im 24-Stunden-Format. LocalTime.of(13, 0) entspricht „13 Uhr" und der Typ kennt kein AM/PM. Das Parsen von Strings mit "AM"/"PM" erfordert einen benutzerdefinierten DateTimeFormatter (das Kapitel Date Parsing behandelt dies) — das Standard-parse unterstützt nur ISO-8601 im 24-Stunden-Format.
Arithmetik und Modifikationen
Dieselbe fluente Form wie bei LocalDate:
time.plusHours(2);
time.plusMinutes(30);
time.plusSeconds(45);
time.plusNanos(500_000);
time.withHour(14); // replace one field
time.withMinute(0);Das Überlaufverhalten: Jede plus/minus-Methode auf LocalTime läuft lautlos um Mitternacht herum. LocalTime.of(23, 0).plusHours(2) ergibt 01:00, nicht „morgen um 01:00" — in LocalTime gibt es kein „morgen". Wenn man wissen möchte, ob ein Überlauf stattgefunden hat, verwendet man LocalDateTime oder rechnet selbst:
LocalTime late = LocalTime.of(23, 0);
LocalTime later = late.plusHours(2); // 01:00 — silently wrapped
// To detect wrap: compare the new value's getHour with what you expected, or use LocalDateTime.Dieser Überlauf ist dokumentiert und beabsichtigt, aber er kann zum Problem werden, wenn man ihn vergisst. Für Berechnungen wie „wann endet diese Schicht?", die Mitternacht überschreiten können, ist LocalDateTime der richtige Typ, nicht LocalTime.
Vergleichen
time.isBefore(other);
time.isAfter(other);
time.compareTo(other);
time.equals(other);Lexikalische Reihenfolge nach hour:minute:second:nano. LocalTime implementiert Comparable<LocalTime>, sodass man eine Liste von Zeiten sortieren oder es direkt als TreeMap-Schlüssel verwenden kann.
Abstände
Duration.between und ChronoUnit.X.between funktionieren beide:
Duration d = Duration.between(start, end);
long minutes = ChronoUnit.MINUTES.between(start, end);
long seconds = ChronoUnit.SECONDS.between(start, end);Das Vorzeichen: positiv, wenn end nach start liegt, sonst negativ. Der Überlauf-Vorbehalt gilt auch hier — Duration.between(LocalTime.of(23, 0), LocalTime.of(1, 0)) ergibt −22 Stunden, nicht +2 Stunden; die API behandelt 01:00 als früher als 23:00 desselben fiktiven Tages. Für „die Schicht ging über Mitternacht hinaus" ist LocalDateTime-basierte Arithmetik das richtige Werkzeug.
Kombinieren mit LocalDate
Die Konvertierung in ein Datum-mit-Zeit ist häufig erforderlich:
LocalDate date = LocalDate.of(2025, 11, 4);
LocalTime time = LocalTime.of(9, 30);
LocalDateTime dt = date.atTime(time); // 2025-11-04T09:30
LocalDateTime dt2 = time.atDate(date); // same thingatTime / atDate sind die Brückenmethoden. Das Ergebnis ist ein LocalDateTime — immer noch keine Zeitzone, aber jetzt an einen Kalendertag gebunden. Das nächste Kapitel geht darauf weiter ein.
Ein praktisches Beispiel: ein kleiner Planungshelfer
Das folgende Programm verwendet LocalTime für eine Art Tagesplan-Aufgabe: Definiere ein „Geschäftszeiten"-Fenster, prüfe, ob ein gegebener Zeitpunkt darin liegt, berechne, wie lange es bis zur nächsten Öffnung dauert, und demonstriere die Mitternachts-Überlauf-Falle.
Was man aus der Ausführung mitnehmen sollte:
LocalTimewird als09:00,17:30,12:30ausgegeben — die kanonische ISO-8601-Form im 24-Stunden-Format. Kein AM/PM im Typ. Wenn man dem Benutzer „5:30 PM" anzeigen möchte, findet man den entsprechenden Formatter im Kapitel Date Formatting; der Typ selbst kennt das nicht.- Die Prüfung „liegt die Zeit im Fenster?" verwendet
!isBefore(open) && !isAfter(close). Das ist das Idiom für halboffene-vs.-geschlossene Intervalle — beide Endpunkte sind eingeschlossen. Für „strikt innerhalb" wechselt man zu den nicht negierten Formen. Duration.between(LocalTime.of(22, 0), LocalTime.of(2, 0))gabPT-20Hzurück, nichtPT4H.LocalTimekennt kein „nächster Tag" — wennendim Uhrzeitvergleich früher alsstartist, wird die Dauer negativ. Für eine Schicht, die Mitternacht überschreitet, wechselt man die Eingaben zuLocalDateTimeund lässt die Datumsangaben die Mehrdeutigkeit auflösen. Das ist die größte Stolperfalle beiLocalTime.LocalTime.of(23, 30).plusHours(2)ergab01:30. Der Überlauf ist lautlos — keine Ausnahme, kein Flag, kein Übertrag ins Datum. Wenn man wissen muss „hat das einen Überlauf verursacht?", verwendet manLocalDateTime. Wenn man wirklich Uhrzeitarithmetik-modulo-24 möchte (z. B. für einen wiederkehrenden Zeitplan), ist der Überlauf das korrekte Verhalten.date.atTime(time)war die kanonische Brücke zuLocalDateTime. Die Spiegelversiontime.atDate(date)liefert dasselbe Ergebnis. Man verwendet diese Methoden ständig, wenn man eine Zeit aus einer Quelle und ein Datum aus einer anderen liest und sie dann zu dem einzelnen Objekt kombiniert, das die nachgelagerte API erwartet.
Was kommt als Nächstes
Das nächste Kapitel, Java LocalDateTime, kombiniert LocalDate und LocalTime zum dritten „lokalen" Typ: ein Datum und eine Uhrzeit, immer noch ohne angehängte Zeitzone. Das ist die natürliche Einheit für „das ist am 4. November um 14:30 Uhr passiert", wenn die Zeitzone irrelevant ist oder separat erfasst wird.