Jaki jest najlepszy sposób przekonwertowania java.util.Date
obiektu na nowy JDK 8 / JSR-310 java.time.LocalDate
?
Date input = new Date();
LocalDate date = ???
Krótka odpowiedź
Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Wyjaśnienie
Pomimo swojej nazwy, java.util.Date
reprezentuje natychmiast na linii czasu, a nie „datę”. Rzeczywiste dane przechowywane w obiekcie to long
liczba milisekund od 1970-01-01T00: 00Z (północ na początku 1970 GMT / UTC).
Klasa równoważna do java.util.Date
w JSR-310 jest Instant
, dlatego istnieje wygodna metoda toInstant()
zapewnienia konwersji:
Date input = new Date();
Instant instant = input.toInstant();
java.util.Date
Instancja ma koncepcji strefy czasowej. Może się to wydawać dziwne, jeśli wywołujesz toString()
a java.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 stanu java.util.Date
.
A Instant
także nie zawiera żadnych informacji o strefie czasowej. Dlatego, aby przekonwertować Instant
datę z lokalnej na lokalną, należy określić strefę czasową. Może to być strefa domyślna - ZoneId.systemDefault()
- lub strefa czasowa kontrolowana przez aplikację, na przykład strefa czasowa z preferencji użytkownika. Użyj atZone()
metody, aby zastosować strefę czasową:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
ZonedDateTime
Zawiera stan składają lokalnej daty i godziny, strefy czasowej i przesunięcie od GMT / UTC. W związku z tym datę - LocalDate
- można łatwo wyodrębnić za pomocą toLocalDate()
:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
LocalDate date = zdt.toLocalDate();
Odpowiedź Java 9
W Java SE 9 dodano nową metodę , która nieco upraszcza to zadanie:
Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());
Ta nowa alternatywa jest bardziej bezpośrednia, tworząc mniej śmieci, a zatem powinna działać lepiej.
LocalDate.from(Instant.ofEpochMilli(date.getTime()))
, że jest to odpowiednik twojego, ale bardziej bezpośredni.Date
nie ma pojęcia strefy czasowej,Instant
nie zawiera również informacji o strefie czasowej.LocalDate
API mówi „aktualizuje bez strefy czasowej”. Więc dlaczego konwersji odDate
doInstant
doLocalDate
potrzebatZone(ZoneId.systemDefault())
?LocalDate
iLocalDateTime
nie „przechowuj ani nie reprezentuj czasu ani strefy czasowej” (zob. Javadocs). Chociaż nie przechowują go, klasy reprezentująLocal
datę i / lub godzinę, dlatego konwersja na lokalną datę / godzinę implikuje strefę czasową.Lepszym sposobem jest:
Zalety tej wersji:
działa niezależnie od tego, czy dane wejściowe są instancjami
java.util.Date
lub podklasamijava.sql.Date
(w przeciwieństwie do sposobu @ JodaStephen). Jest to powszechne w przypadku danych pochodzących z JDBC.java.sql.Date.toInstant()
zawsze zgłasza wyjątek.to samo dotyczy JDK8 i JDK7 z backportem JSR-310
Ja osobiście korzystam z klasy użytkowej (ale nie jest ona kompatybilna z backport):
Ta
asLocalDate()
metoda jest tutaj zerowo bezpieczna, używatoLocalDate()
, jeśli dane wejściowe sąjava.sql.Date
(może zostać przesłonięte przez sterownik JDBC, aby uniknąć problemów ze strefą czasową lub niepotrzebnych obliczeń), w przeciwnym razie używa powyższej metody.źródło
DateConvertUtils
.Date.toInstant()
.źródło
SimpleDateFormat
przypadku instancja jest ograniczona do bieżącego wątku. Jest używany w sposób bezpieczny dla wątków. TerazSimpleDateFormat
uchodzi za „drogie instancji” (ze względu na wszystkich wewnętrznych struktur danych potrzebnych), ale nie można dzielić jeden jako „pojedyncza” (bez synchronizacji dostępu do niego), bo to nie jest rzeczywiście thread- bezpieczny. (ThreadLocal
Rozwiązanie może działać, jeśli kod „zanieczyszczający”Thread
w tym był odpowiedzialny za cykl życia wątku ... ale to rzadko się zdarza). Niezręczny. UnikanieSimpleDateFormat
jest powodem korzystania .javax.time
SimpleDateFormat
(który jest wyrzucany), łańcuch pośredni (który jest wyrzucany) i koszt parsowania. To rozwiązanie, ale nie jest zalecane.Jeśli używasz Java 8, odpowiedź @ JodaStephen jest oczywiście najlepsza. Jeśli jednak pracujesz z backportem JSR-310 , niestety musisz zrobić coś takiego:
źródło
źródło
Możesz przekonwertować w jednym wierszu:
źródło
po pierwsze, łatwo jest przekonwertować datę na natychmiastową
Następnie możesz przekonwertować Instant na dowolny interfejs API daty w jdk 8 za pomocą metody ofInstant ():
źródło
import java.sql.Date
w swoim pliku:toInstant()
metodajava.sql.Date
zawsze rzuca.Date
Instancji nie zawierają zbyt czasu wraz z datą, gdyLocalDate
tego nie robi. Możesz więc najpierw przekonwertować go naLocalDateTime
jego metodę,ofInstant()
a następnie, jeśli chcesz go bez czasu, przekonwertować instancję naLocalDate
.źródło
ten format pochodzi z
Date#tostring
źródło
Miałem problemy z implementacją @ JodaStephen na JBoss EAP 6. Więc przepisałem konwersję po Samouczku Java Oracle w http://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html .
źródło
Co jest nie tak z tą 1 prostą linią?
źródło
Rozwiązałem to pytanie za pomocą rozwiązania poniżej
W takim przypadku localDate wydrukuj datę w tym formacie „rrrr-MM-dd”
źródło
java.time
klasy w JDK8, a nie Jody Time.