Java 8 ma zupełnie nowy interfejs API dla daty i godziny. Jedną z najbardziej przydatnych klas w tym interfejsie API jest LocalDateTime
przechowywanie niezależnej od strefy czasowej wartości daty z czasem.
Prawdopodobnie miliony linii kodu używają java.util.Date
do tego celu starszej klasy . W związku z tym podczas łączenia starego i nowego kodu konieczna będzie konwersja między nimi. Ponieważ wydaje się, że nie ma bezpośrednich metod osiągnięcia tego celu, w jaki sposób można to zrobić?
Odpowiedzi:
Krótka odpowiedź:
Objaśnienie: (na podstawie tego pytania o
LocalDate
)Pomimo swojej nazwy,
java.util.Date
reprezentuje natychmiast na linii czasu, a nie „datę”. Rzeczywiste dane przechowywane w obiekcie tolong
liczba milisekund od 1970-01-01T00: 00Z (północ na początku 1970 GMT / UTC).Klasa równoważna
java.util.Date
w JSR-310 jestInstant
, dlatego istnieją wygodne metody zapewnienia konwersji do iz powrotem:java.util.Date
Instancja ma koncepcji strefy czasowej. Może się to wydawać dziwne, jeśli wywołujesztoString()
ajava.util.Date
, ponieważtoString
dotyczy ono strefy czasowej. Jednak ta metoda faktycznie używa domyślnej strefy czasowej Javy w locie, aby podać ciąg. Strefa czasowa nie jest częścią rzeczywistego stanujava.util.Date
.A
Instant
także nie zawiera żadnych informacji o strefie czasowej. Tak więc, aby przekonwertować zInstant
lokalnej daty i godziny, konieczne jest określenie strefy czasowej. Może to być strefa domyślna -ZoneId.systemDefault()
- lub strefa czasowa kontrolowana przez aplikację, na przykład strefa czasowa z preferencji użytkownika.LocalDateTime
ma wygodną metodę fabryczną, która zajmuje zarówno strefę czasową, jak i strefę czasową:Odwrotnie
LocalDateTime
strefa czasowa jest określana przez wywołanieatZone(ZoneId)
metody.ZonedDateTime
Można następnie przekształcić bezpośrednio doInstant
:Pamiętaj, że konwersja z
LocalDateTime
naZonedDateTime
może potencjalnie spowodować nieoczekiwane zachowanie. Wynika to z faktu, że nie każda lokalna data i godzina istnieją z powodu czasu letniego. Jesienią / jesienią zachodzi nakładanie się lokalnej linii czasowej, w której ta sama lokalna data i godzina występuje dwukrotnie. Wiosną jest przerwa, w której godzina znika. Zobacz Javadoc z,atZone(ZoneId)
aby uzyskać więcej definicji konwersji.Podsumowując, jeśli podróżujesz w obie strony
java.util.Date
doLocalDateTime
iz powrotemjava.util.Date
, możesz skończyć z inną chwilą ze względu na czas letni.Informacje dodatkowe: Jest jeszcze jedna różnica, która wpłynie na bardzo stare daty.
java.util.Date
używa kalendarza, który zmienia się 15 października 1582 r., z wcześniejszymi datami, używając kalendarza juliańskiego zamiast kalendarza gregoriańskiego. Dla kontrastu,java.time.*
używa systemu kalendarza ISO (odpowiednik gregoriański) przez cały czas. W większości przypadków system kalendarzowy ISO jest tym, czego potrzebujesz, ale możesz zobaczyć dziwne efekty podczas porównywania dat sprzed 1582 roku.źródło
java.util.Date
że nie zawiera strefy czasowej, ale drukuje ją podczastoString()
. Oficjalna dokumentacja wydarzenia nie mówi tego wyraźnie podczas pisania.LocalDateTime.ofInstant(date.toInstant()...
nie zachowuje się tak, jak można by się tego naiwnie spodziewać. Na przykładnew Date(1111-1900,11-1,11,0,0,0);
stanie się1111-11-17 23:53:28
korzystać z tego podejścia. Spójrz na implementację,java.sql.Timestamp#toLocalDateTime()
jeśli potrzebujesz wyniku1111-11-11 00:00:00
z poprzedniego przykładu.java.sql.Date#toInstant
rzucaUnsupportedOperationException
. Więc nie używajtoInstant
w RowMapper najava.sql.ResultSet#getDate
.Oto, co wymyśliłem (i podobnie jak wszystkie zagadki związane z datą i godziną, prawdopodobnie zostanie to obalone na podstawie dziwnej regulacji strefy czasowej-leapyear-światła dziennego: D)
Round-tripping:
Date
<<->>LocalDateTime
Dany:
Date date = [some date]
(1)
LocalDateTime
<<Instant
<<Date
(2)
Date
<<Instant
<<LocalDateTime
Przykład:
Dany:
(1)
LocalDateTime
<<Instant
<<Date
:Utwórz
Instant
zDate
:Utwórz
Date
zInstant
(nie konieczne, ale do ilustracji):Utwórz
LocalDateTime
zInstant
(2)
Date
<<Instant
<<LocalDateTime
Utwórz
Instant
zLocalDateTime
:Utwórz
Date
zInstant
:Dane wyjściowe to:
źródło
Instant.ofEpochMilli(date.getTime())
zróbdate.toInstant()
toInstant()
wygląda ładnie, ale nie udaje sięjava.sql.Date
, arggggh! Jest więc w końcu łatwiejszy w użyciuInstant.ofEpochMilli(date.getTime())
.Znacznie wygodniejszy sposób, jeśli masz pewność, że potrzebujesz domyślnej strefy czasowej:
źródło
podczas konwersji z nowego API LocalDateTime na java.util.date wydaje się, że:
odwróconą konwersję można (miejmy nadzieję) osiągnąć w podobny sposób ...
mam nadzieję, że to pomoże...
źródło
Wszystko jest tutaj: http://blog.progs.be/542/date-to-java-time
Odpowiedź z „potknięciem w obie strony” nie jest dokładna: kiedy to zrobisz
jeśli strefą czasową systemu nie jest UTC / GMT, zmieniasz godzinę!
źródło
Najszybszym sposobem na
LocalDateTime
->Date
jest:Date.from(ldt.toInstant(ZoneOffset.UTC))
źródło
Nie jestem pewien, czy jest to najprostszy lub najlepszy sposób, czy też są jakieś pułapki, ale działa:
źródło
LocalDateTime
doDate
. W przejściach czasu letniegoLocalDateTime
może nie istnieć lub może wystąpić dwukrotnie. Musisz ustalić, co chcesz się wydarzyć w każdym przypadku.GregorianCalendar
należy do starego niezręcznego API, które nowyjava.time
API zamierza zastąpićJeśli korzystasz z Androida i używasz threetenbp , możesz użyć
DateTimeUtils
zamiast tego.dawny:
nie możesz używać,
Date.from
ponieważ jest obsługiwany tylko w API 26+źródło