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ć, toInstant
jeś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 Interval
klasy do reprezentowania tej pary Instant
obiektów. Daje to klasa użytecznych metod porównywania takich jak abuts
, overlaps
, contains
i 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 Instant
osi 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 LocalDate
zajęcia i ich atStartOfDay
metodę.
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 Interval
klasy 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ę Instant
obiektów. Możemy wyodrębnić Instant
z naszych ZonedDateTime
obiektó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 Interval
ma określony początek i koniec na osi czasu Wszechświata. To pasuje do naszej potrzeby reprezentowania „dnia”.
Nazywamy tę metodę withTimeAtStartOfDay
zamiast 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();