tl; dr
LocalDate // Represents an entire day, without time-of-day and without time zone.
.now( // Capture the current date.
ZoneId.of( "Asia/Tokyo" ) // Returns a `ZoneId` object.
) // Returns a `LocalDate` object.
.atStartOfDay( // Determines the first moment of the day as seen on that date in that time zone. Not all days start at 00:00!
ZoneId.of( "Asia/Tokyo" )
) // Returns a `ZonedDateTime` object.
Tagesanfang
Holen Sie sich die volle Länge des heutigen Tages aus einer Zeitzone.
Verwendung des Half-Open-Ansatzes, bei dem der Anfang inklusive und das Ende exklusiv ist . Dieser Ansatz behebt den Fehler in Ihrem Code, der die letzte Sekunde des Tages nicht berücksichtigt.
ZoneId zoneId = ZoneId.of( "Africa/Tunis" ) ;
LocalDate today = LocalDate.now( zoneId ) ;
ZonedDateTime zdtStart = today.atStartOfDay( zoneId ) ;
ZonedDateTime zdtStop = today.plusDays( 1 ).atStartOfDay( zoneId ) ;
zdtStart.toString () = 2020-01-30T00: 00 + 01: 00 [Afrika / Tunis]
zdtStop.toString () = 2020-01-31T00: 00 + 01: 00 [Afrika / Tunis]
Sehen Sie die gleichen Momente in UTC.
Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;
start.toString () = 2020-01-29T23: 00: 00Z
stop.toString () = 2020-01-30T23: 00: 00Z
Wenn Sie den gesamten Tag eines Datums wie in UTC und nicht in einer Zeitzone anzeigen möchten, verwenden Sie OffsetDateTime
.
LocalDate today = LocalDate.now( ZoneOffset.UTC ) ;
OffsetDateTime odtStart = today.atTime( OffsetTime.MIN ) ;
OffsetDateTime odtStop = today.plusDays( 1 ).atTime( OffsetTime.MIN ) ;
odtStart.toString () = 2020-01-30T00: 00 + 18: 00
odtStop.toString () = 2020-01-31T00: 00 + 18: 00
Diese OffsetDateTime
Objekte befinden sich bereits in UTC. Sie können sie jedoch aufrufen, toInstant
wenn Sie solche Objekte benötigen, die sich per Definition immer in UTC befinden.
Instant start = odtStart.toInstant() ;
Instant stop = odtStop.toInstant() ;
start.toString () = 2020-01-29T06: 00: 00Z
stop.toString () = 2020-01-30T06: 00: 00Z
Tipp: Möglicherweise möchten Sie Ihrem Projekt die ThreeTen-Extra- Bibliothek hinzufügen , um deren Interval
Klasse zur Darstellung dieses Objektpaars zu verwenden Instant
. Diese Klasse bietet nützliche Methoden zum Vergleich wie abuts
, overlaps
, contains
und vieles mehr.
Interval interval = Interval.of( start , stop ) ;
interval.toString () = 2020-01-29T06: 00: 00Z / 2020-01-30T06: 00: 00Z
Halb offen
Die Antwort von mprivat ist richtig. Sein Ziel ist es, nicht zu versuchen, das Ende eines Tages zu erreichen, sondern mit "vor Beginn des nächsten Tages" zu vergleichen. Seine Idee ist als "Half-Open" -Ansatz bekannt, bei dem eine Zeitspanne einen Anfang hat, der inklusiv ist, während das Ende exklusiv ist .
- Die aktuellen Datums- und Uhrzeit-Frameworks von Java (java.util.Date/Calendar und Joda-Time ) verwenden beide Millisekunden aus der Epoche . In Java 8 verwenden die neuen JSR 310-Klassen java.time. * Eine Auflösung von Nanosekunden. Jeder Code, den Sie basierend auf dem Erzwingen der Millisekundenzahl des letzten Momentes des Tages geschrieben haben, wäre falsch, wenn Sie zu den neuen Klassen wechseln würden.
- Der Vergleich von Daten aus anderen Quellen wird fehlerhaft, wenn andere Auflösungen verwendet werden. Beispielsweise verwenden Unix-Bibliotheken normalerweise ganze Sekunden, und Datenbanken wie Postgres lösen Datum und Uhrzeit in Mikrosekunden auf.
- Einige Änderungen der Sommerzeit finden über Mitternacht statt, was die Dinge weiter verwirren könnte.
Joda-Time 2.3 bietet genau zu diesem Zweck eine Methode, um den ersten Moment des Tages zu erhalten : withTimeAtStartOfDay()
. Ähnlich in java.time , LocalDate::atStartOfDay
.
Durchsuchen Sie StackOverflow nach "joda half-open" , um weitere Diskussionen und Beispiele zu sehen.
Siehe diesen Beitrag, Zeitintervalle und andere Bereiche sollten von Bill Schneider halb offen sein .
Vermeiden Sie ältere Datums- und Zeitklassen
Die Klassen java.util.Date und .Calendar sind notorisch problematisch. Vermeide sie.
Verwenden Sie java.time- Klassen. Das java.time- Framework ist der offizielle Nachfolger der äußerst erfolgreichen Joda-Time- Bibliothek.
java.time
Das java.time-Framework ist in Java 8 und höher integriert. Back-portiert Java 6 und 7 in dem ThreeTen-Backport - Projekt weiter zu Android angepasst im ThreeTenABP Projekt.
An Instant
ist ein Moment auf der Zeitachse in UTC mit einer Auflösung von Nanosekunden .
Instant instant = Instant.now();
Wenden Sie eine Zeitzone an, um die Wanduhrzeit für einen bestimmten Ort zu ermitteln.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Um den ersten Moment des Tages zu erleben, gehen Sie die LocalDate
Klasse und ihre atStartOfDay
Methode durch.
ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
Holen Sie sich mit dem Half-Open-Ansatz den ersten Moment des folgenden Tages.
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );
Derzeit fehlt dem java.time-Framework eine Interval
Klasse, wie unten für Joda-Time beschrieben. Das ThreeTen-Extra- Projekt erweitert java.time jedoch um zusätzliche Klassen. Dieses Projekt ist das Testfeld für mögliche zukünftige Ergänzungen von java.time. Zu seinen Klassen gehört Interval
. Konstruieren Sie eine, Interval
indem Sie ein Objektpaar übergeben Instant
. Wir können eine Instant
aus unseren ZonedDateTime
Objekten extrahieren .
Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );
Über java.time
Das java.time- Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Legacy - Datum-Zeit - Klassen wie java.util.Date
, Calendar
, & SimpleDateFormat
.
Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .
Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .
Sie können java.time- Objekte direkt mit Ihrer Datenbank austauschen . Verwenden Sie einen JDBC-Treiber, der mit JDBC 4.2 oder höher kompatibel ist . Keine Notwendigkeit für Zeichenfolgen, keine Notwendigkeit für java.sql.*
Klassen. Hibernate 5 und JPA 2.2 unterstützen java.time .
Woher bekomme ich die java.time-Klassen?
Joda-Zeit
UPDATE: Das Joda-Time-Projekt befindet sich jetzt im Wartungsmodus und empfiehlt die Migration zu den Klassen java.time . Ich lasse diesen Abschnitt für die Geschichte intakt.
Joda-Time hat drei Klassen eine Zeitspanne auf verschiedene Weise darstellen: Interval
, Period
, und Duration
. An Interval
hat einen bestimmten Anfang und ein bestimmtes Ende auf der Zeitachse des Universums. Dies passt zu unserem Bedürfnis, "einen Tag" darzustellen.
Wir rufen die Methode auf, withTimeAtStartOfDay
anstatt die Tageszeit auf Null zu setzen. Aufgrund der Sommerzeit und anderer Anomalien ist der erste Moment des Tages möglicherweise nicht der richtige 00:00:00
.
Beispielcode mit Joda-Time 2.3.
DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( timeZone );
DateTime todayStart = now.withTimeAtStartOfDay();
DateTime tomorrowStart = now.plusDays( 1 ).withTimeAtStartOfDay();
Interval today = new Interval( todayStart, tomorrowStart );
Wenn Sie müssen, können Sie in ein java.util.Date konvertieren.
java.util.Date date = todayStart.toDate();