Jak przekonwertować java.sql.timestamp na LocalDate (java8) java.time?

Odpowiedzi:

196

Możesz to zrobić:

timeStamp.toLocalDateTime().toLocalDate();

Pamiętaj, że do konwersji timestamp.toLocalDateTime() zostanie użyta Clock.systemDefaultZone()strefa czasowa. To może być to, czego chcesz, ale nie musi.

asylias
źródło
1
Został dodany w Javie 8.
assylias
54
Uwaga, timestamp.toLocalDateTime()metoda użyje strefy czasowej systemDefault do wykonania konwersji. To może być to, czego chcesz, ale nie musi.
jacobhyphenated
1
@jacobhyphenated prosimy o przesłanie odpowiedzi, używając wyraźnej strefy czasowej. Dzięki!
user482745
Komentarz @ jacobhyphenated jest tutaj niezwykle ważny, stąd liczba głosów za nim. Zobacz moją odpowiedź, aby poznać szczegóły stackoverflow.com/a/57101544/2032701
Ruslan
@jacobhyphenated, LocalDateTimezawsze używa domyślnej strefy czasowej systemu. To właśnie oznacza „Lokalny” w jego nazwie.
M. Prochorow
21

Przyjęta odpowiedź nie jest idealna, więc zdecydowałem się dodać moje 2 centy

timeStamp.toLocalDateTime().toLocalDate();

jest ogólnie złym rozwiązaniem , nie jestem nawet pewien, dlaczego dodali tę metodę do JDK, ponieważ robi to naprawdę zagmatwane, wykonując niejawną konwersję przy użyciu strefy czasowej systemu. Zwykle, gdy używa się tylko klas daty java8, programista jest zmuszony do określenia strefy czasowej, co jest dobrą rzeczą.

Dobre rozwiązanie to

timestamp.toInstant().atZone(zoneId).toLocalDate()

Gdzie zoneId to strefa czasowa, której chcesz użyć, zazwyczaj jest to ZoneId.systemDefault (), jeśli chcesz użyć strefy czasowej systemu lub strefy czasowej zakodowanej na stałe, takiej jak ZoneOffset.UTC

Ogólne podejście powinno być

  1. Uwolnij się od nowych klas daty java8, używając klasy, która jest bezpośrednio powiązana, np. W naszym przypadku java.time.Instant jest bezpośrednio powiązany z java.sql.Timestamp , tzn. Nie są potrzebne żadne konwersje stref czasowych między nimi.
  2. Użyj dobrze zaprojektowanych metod w tej klasie java8, aby postępować właściwie. W naszym przypadku atZone (zoneId) jasno określiło , że robimy konwersję i używamy do tego określonej strefy czasowej.
Rusłan
źródło
1
Nie zgadzam się. Znacznik czasu (a także data) nie zawierają żadnych informacji o strefie. LocalDate nie zawiera żadnych informacji o strefie, więc są one równoważne. Konwersja między nimi może odbywać się niezależnie od określonej strefy. Konwersja do ZonedDateTime przed konwersją do LocalDate dodaje strefę czasową, a następnie ją wyłącza - znacznie bardziej prawdopodobne jest, że wystąpi nieprzyjemny - trudny do znalezienia - błąd, robiąc to w ten sposób.
AutomatedMike
5
@AutomatedMike Timestamp (a także Date) reprezentują punkt w czasie UTC. LocalDate nie reprezentuje punktu w czasie, ale raczej czas widoczny na zegarze ściennym. Przeczytaj ich javadoc. „Konwersja między nimi może odbywać się niezależnie od określonej strefy” - nieprawda , new Timestamp (0L) .toLocalDateTime () zwraca „1970-01-01T03: 00” dla mojej moskiewskiej strefy czasowej. Wynik może być inny w Twojej strefie czasowej.
Ruslan
1
@AutomatedMike Nawet jeśli pozbędziesz się czasu, wykonując toLocalDate (), łatwo jest udowodnić, że dzień może być zły, jeśli Timestamp miał czas około północy, na przykład nowy Timestamp (1000 * 60 * 60 * 23) .toLocalDateTime (). ToLocalDate Funkcja () zwraca „1970-01-02” dla mojej strefy czasowej w Moskwie, gdy jest to „1970-01-01” czasu UTC.
Ruslan
1
@AutomatedMike „dodaje strefę czasową, a następnie ją zdejmuje” - nie chodzi o dodawanie i usuwanie strefy czasowej, ale raczej o konwersję między różnymi pojęciami przy użyciu wyraźnej strefy czasowej. Kontrastuje to z przykładami z moich dwóch poprzednich komentarzy, w których strefa czasowa jest stosowana niejawnie .
Ruslan
7

Lekko rozszerzę odpowiedź @assylias, aby uwzględnić strefę czasową. Istnieją co najmniej dwa sposoby uzyskania LocalDateTime dla określonej strefy czasowej.

Możesz użyć strefy czasowej setDefault dla całej aplikacji. Powinien zostać wywołany przed jakąkolwiek konwersją znacznika czasu -> java.time:

public static void main(String... args) {
    TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");
    TimeZone.setDefault(utcTimeZone);
    ...
    timestamp.toLocalDateTime().toLocalDate();
}

Lub możesz użyć łańcucha toInstant.atZone:

timestamp.toInstant()
        .atZone(ZoneId.of("UTC"))
        .toLocalDate();
Pavel
źródło