2016-04-05 10 views
24

Klasa ma metodę o nazwie toInstant(), która konwertuje instancję Date na java.time.Instant.UnsupportedOperationException - Dlaczego nie można wywołać metody toInstant() w java.sql.Date?

Klasa java.sql.Date rozszerza klasę java.util.Date, ale gdy próbuję zadzwonić toInstant() na java.sql.Date, otrzymam UnsupportedOperationException.

Dlaczego toInstant() jest nieobsługiwaną operacją na java.sql.Date?

Co to jest "poprawny" sposób konwersji java.sql.Date na java.time.Instant?

Odpowiedz

12

Sprawdź JavaDoc

Od sql.Date nie posiada składnik czasu, nie ma możliwości, aby przekształcić go time.Instant

Ta metoda zawsze generuje UnsupportedOperationException i powinny nie być stosowane, ponieważ SQL Data wartości nie mają składnika czasu.

+1

Teraz pytanie brzmi: dlaczego został zaprojektowany w ten sposób. Można sobie wyobrazić, że jest domyślny, a czas ustawiony jest na 0. Nie można znaleźć niczego na liście mailingowej. – Tunaki

+2

@Tunaki Logika sprawia, że ​​myślę, że to dlatego, że klasa nadrzędna 'util.Date' ma publiczną metodę' toInstant', która nie powinna być używana przez klasę potomną. Więc zamiast robić "końcowy" (aby zachować logikę dziedziczenia), woleli opcję nadpisania go i uczynienia go bezużytecznym. –

+0

@Tunaki prawdopodobnie dlatego, że jak zauważysz, każda konwersja na Instant wymagałaby arbitralnego ustawienia pewnych danych (czasu, strefy czasowej). – assylias

13

java.sql.Date obsługuje tylko datę, miesiąc i rok. Nie obsługuje informacji o czasie.

Dlatego właśnie java.sql.Date.toInstant() zgłasza wyjątek UnsupportedOperationException. Java 8 Instant zawiera informacje o dacie/czasie.

java.util.Date zawiera informacje o dacie i godzinie, więc java.util.Date.toInstant() działa!

Można zrobić tak:

new java.util.Date(sqlDate.getTime()).toInstant() 

Aktualizacja:

Instant.ofEpochMilli(sqlDate.getTime()); 

// OR 
new java.util.Date(sqlDate.getTime()).toInstant(); 

zwróci sam wynik, ponieważ toInstant() zadzwonić Instant.ofEpochMilli (getTime()) wewnętrznie.

public Instant toInstant() { 
    return Instant.ofEpochMilli(getTime()); 
} 
+0

Co jest bardziej "poprawne"? 'Instant.ofEpochMilli (sqlDate.getTime());' lub 'new java.util.Date (sqlDate.getTime()). ToInstant();' –

+0

Nie można przekonwertować wartości java.sql.Date na wersję błyskawiczną bez dostarczanie strefy czasowej. Wywoływanie getTime() w java.sql.Date jest bez znaczenia. Jak wskazano w innych komentarzach, java.sql.Date jest tylko datą lokalną i nie stanowi chwili w czasie. –

+0

Nie zadzwoniłem doInstant na datę java sql. Zrobiłem zadzwonić doInstant na datę java util i to jest w porządku dla sprawy. – Loc

9

Odpowiedzi udzielone do tej pory aż do teraz skoncentrować się na szczegółach, które java.sql.Date nie ma informacji o czasie. To prawda, ale nie jest to prawdziwy lub wystarczający powód, dla którego ten typ nie może zaoferować bezpośredniej konwersji na Instant. Niestety błąd documentation of Java-8 powoduje, że ten sam błąd pozwala użytkownikom myśleć, że problem jest spowodowany brakującymi informacjami o czasie.

Pod względem koncepcyjnym typ java.sql.Date reprezentuje typ lokalny. Modeluje datę kalendarzową, która może być inna w dowolnym regionie naszego globu. Ale Instant jest taki sam na całym świecie. Użytkownicy potrzebują strefy czasowej lub strefy czasowej, aby wykonać konwersję.

Tragicznie typ java.sql.Date dziedziczy po java.util.Date, który jest typem globalnym (podobny do instant). Jednak to dziedziczenie naprawdę oznacza dziedziczenie implementacji, a nie dziedziczenie typu. Jeszcze jeden powód, aby rozważyć projekt tych starych klas JDBC, które mają zostać zerwane.Dlatego rzeczywiście jest możliwe użycie hacka do owinięcia java.sql.Date za pomocą metody getTime() wewnątrz instancji java.util.Date, która ostatecznie umożliwia bezpośrednią konwersję w jednej chwili. Ale: Ta konwersja domyślnie używa domyślnej strefy czasowej systemu.

Jak poprawnie przekonwertować w sposób pedantyczny? Rozważmy documentation of Java-8 które ponownie tutaj wskazuje we właściwym kierunku:

java.sql.Date sqlDate = ...; 
LocalDate calendarDate = sqlDate.toLocalDate(); 
ZonedDateTime zdt = calendarDate.atStartOfDay(ZoneId.of("Europe/Paris")); 
Instant instant = zdt.toInstant(); 
24

Prawidłowe odwzorowanie między java.sql.Date i java.time jest LocalDate:

LocalDate date = sqlDate.toLocalDate(); 

Jeśli naprawdę musi można następnie wyznaczyć Instant , chociaż dodatkowe informacje (czas) będą arbitralne. Na przykład:

Instant i = date.atStartOfDay(ZoneOffset.UTC).toInstant(); 
+0

Chciałbym móc przyjąć dwie odpowiedzi ... To doskonale odpowiada na drugą część mojego pytania, ale główne pytanie brzmiało: dlaczego nie można wywołać 'toInstant()' na 'java.sql.Date', więc musiałem zaakceptuj odpowiedź [@YassinHajaj] (http://stackoverflow.com/users/5050667/yassin-hajaj) (http://stackoverflow.com/a/36435570/2561365). Ta odpowiedź wymaga więcej upvotes. –

Powiązane problemy