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.
Początek dnia
Uzyskaj pełny obraz dnia dzisiejszego w strefie czasowej.
Korzystanie z podejścia Half-Open, w którym początek jest włączający, a koniec wyłączny . Takie podejście rozwiązuje lukę w kodzie, która nie uwzględnia ostatniej sekundy dnia.
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 [Afryka / Tunis]
zdtStop.toString () = 2020-01-31T00: 00 + 01: 00 [Afryka / Tunis]
Zobacz te same momenty w UTC.
Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;
start.toString () = 2020-01-29T23: 00: 00Z
stop.toString () = 2020-01-30T23: 00: 00Z
Jeśli chcesz, aby data była wyświetlana przez cały dzień w UTC, a nie w strefie czasowej, użyj 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
Te OffsetDateTime obiekty będą już w UTC, ale możesz wywołać, toInstantjeśli potrzebujesz takich obiektów, które z definicji zawsze znajdują się w UTC.
Instant start = odtStart.toInstant() ;
Instant stop = odtStop.toInstant() ;
start.toString () = 2020-01-29T06: 00: 00Z
stop.toString () = 2020-01-30T06: 00: 00Z
Wskazówka: możesz być zainteresowany dodaniem biblioteki ThreeTen-Extra do swojego projektu, aby użyć jej Intervalklasy do reprezentowania tej pary Instantobiektów. Daje to klasa użytecznych metod porównywania takich jak abuts, overlaps, containsi więcej.
Interval interval = Interval.of( start , stop ) ;
interval.toString () = 2020-01-29T06: 00: 00Z / 2020-01-30T06: 00: 00Z
Wpół otwarty
Odpowiedź przez mprivat jest poprawna. Chodzi mu o to, aby nie próbować uzyskać końca dnia, ale raczej porównać to z „przed rozpoczęciem następnego dnia”. Jego pomysł znany jest jako podejście „Half-Open”, w którym okres czasu ma początek obejmujący, a koniec wyłączny .
- Bieżące ramy daty i czasu w Javie (java.util.Date/Calendar i Joda-Time ) używają milisekund od epoki . Jednak w Javie 8 nowe klasy JSR 310 java.time. * Używają rozdzielczości nanosekund. Każdy kod, który napisałeś w oparciu o wymuszenie liczenia milisekund ostatniej chwili dnia byłby niepoprawny, gdyby został przełączony na nowe klasy.
- Porównywanie danych z innych źródeł staje się błędne, jeśli stosują inne rozwiązania. Na przykład biblioteki uniksowe zwykle wykorzystują całe sekundy, a bazy danych, takie jak Postgres, określają datę i godzinę na mikrosekundy.
- Niektóre zmiany czasu letniego mają miejsce w ciągu północy, co może jeszcze bardziej zmylić sytuację.

Czas Joda- 2.3 oferuje metodę tego samego celu, do otrzymania pierwszej chwili dnia: withTimeAtStartOfDay(). Podobnie w java.time, LocalDate::atStartOfDay.
Wyszukaj w StackOverflow „joda półotwarta”, aby zobaczyć więcej dyskusji i przykładów.
Zobacz ten post, Przedziały czasowe i inne zakresy powinny być w połowie otwarte , autorstwa Billa Schneidera.
Unikaj starszych klas daty i godziny
Klasy java.util.Date i .Calendar są notorycznie kłopotliwe. Unikaj ich.
Użyj klas java.time . Java.time ramy jest oficjalnym następcą bardzo udanego Joda-Time bibliotece.
java.time
Struktura java.time jest wbudowana w Javę 8 i nowsze. Z powrotem przeniesiony do Java 6 i 7 w projekcie ThreeTen-Backport , dodatkowo dostosowany do Androida w projekcie ThreeTenABP .
Na Instantosi czasu znajduje się moment w UTC z rozdzielczością nanosekund .
Instant instant = Instant.now();
Zastosuj strefę czasową, aby uzyskać czas na zegarze ściennym dla niektórych miejscowości.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Aby uzyskać pierwszy moment dnia, przejdź przez LocalDatezajęcia i ich atStartOfDaymetodę.
ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
Korzystając z podejścia Half-Open, uzyskaj pierwszą chwilę następnego dnia.
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );

Obecnie framework java.time nie posiada Intervalklasy opisanej poniżej dla Joda-Time. Jednak projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Wśród jego klas jest Interval. Skonstruuj an Interval, przekazując parę Instantobiektów. Możemy wyodrębnić Instantz naszych ZonedDateTimeobiektów.
Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );
Informacje o java.time
Struktura java.time jest wbudowana w Javę 8 i nowsze. Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.
Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj Stack Overflow, aby znaleźć wiele przykładów i wyjaśnień. Specyfikacja to JSR 310 .
Projekt Joda-Time , obecnie w trybie konserwacji , zaleca migrację do klas java.time .
Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie ma potrzeby stosowania ciągów ani java.sql.*klas. Hibernate 5 i JPA 2.2 obsługują java.time .
Skąd wziąć klasy java.time?
Joda-Time
UPDATE: Projekt Joda-Time jest teraz w trybie konserwacji i zaleca migrację do klas java.time . Zostawiam tę sekcję nietkniętą dla historii.
Joda-Time ma trzy klasy do reprezentowania okres czasu na różne sposoby: Interval, Period, i Duration. An Intervalma określony początek i koniec na osi czasu Wszechświata. To pasuje do naszej potrzeby reprezentowania „dnia”.
Nazywamy tę metodę withTimeAtStartOfDayzamiast ustawiania pory dnia na zera. Z powodu czasu letniego i innych anomalii pierwsza chwila dnia może nie nadejść 00:00:00.
Przykładowy kod wykorzystujący 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 );
Jeśli musisz, możesz przekonwertować plik na java.util.Date.
java.util.Date date = todayStart.toDate();