Używam nowego pakietu java.time w Javie 8. Mam starszą bazę danych, która daje mi java.util.Date
, którą konwertuję na Instant
.Java 8 java.time: Dodawanie TemporalUnit w Instant a LocalDateTime
Co próbuję zrobić, to dodać okres czasu, który jest oparty na innej flagi bazy danych. Mogę dodać dni, tygodnie, miesiące lub lata. Nie chcę dbać o to, co dodaję, i chciałbym móc dodać więcej opcji w przyszłości.
Moja pierwsza myśl to Instant.plus()
, ale to daje mi UnsupportedTemporalTypeException
dla wartości większych niż jeden dzień. Natychmiast wydaje się, że nie obsługuje operacji na dużych jednostkach czasu. W porządku, cokolwiek, LocalDateTime
robi.
Więc to daje mi ten kod:
private Date adjustDate(Date myDate, TemporalUnit unit){
Instant instant = myDate.toInstant();
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
dateTime = dateTime.plus(1, unit);
Instant updatedInstant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
return new Date(dueInstant.toEpochMilli());
}
Teraz, to jest mój pierwszy raz przy użyciu nowego API czasu, więc może coś przeoczyć tutaj. Ale wydaje mi się, że niezgrabne muszę iść:
Date --> Instant --> LocalDateTime --> do stuff--> Instant --> Date.
Nawet gdybym nie musiał używać daty część, ja nadal uważam, że to było trochę niezręczne. Moje pytanie brzmi: czy robię to całkowicie źle i jaki jest najlepszy sposób na zrobienie tego?
Edit: Rozszerzając dyskusji w komentarzach.
Myślę, że mam teraz lepszy pomysł na temat tego, w jaki sposób LocalDateTime i Instant są odtwarzane za pomocą java.util.Date i java.sql.Timestamp. Dziękuję wszystkim.
Teraz bardziej praktyczna uwaga. Załóżmy, że użytkownik przesyła mi datę z dowolnego miejsca na świecie, z dowolnej strefy czasowej. Wysyłają mi 2014-04-16T13:00:00
, które można przeanalizować w LocalDateTime. Następnie konwertuję to bezpośrednio na java.sql.Timestamp i zachowuję w mojej bazie danych.
Teraz, bez robienia czegokolwiek innego, wyciągam mój java.sql.timestamp z mojej bazy danych, konwertuję na LocalDateTime
przy użyciu timestamp.toLocalDateTime()
. Wszystko dobrze. Następnie zwracam tę wartość do mojego użytkownika, używając formatu ISO_DATE_TIME. Wynikiem jest 2014-04-16T09:00:00
.
Zakładam, że ta różnica wynika z pewnego rodzaju niejawnej konwersji do/z UTC. Myślę, że moja domyślna strefa czasowa może zostać zastosowana do wartości (EDT, UTC-4), co wyjaśniałoby, dlaczego liczba jest wyłączona o 4 godziny.
Nowe pytanie (pytania). Gdzie odbywa się ukryta zamiana czasu lokalnego na UTC? Jaki jest lepszy sposób na zachowanie stref czasowych. Czy nie powinienem iść bezpośrednio z czasu lokalnego jako ciąg (2014-04-16T13: 00: 00) do LocalDateTime
? Czy powinienem oczekiwać strefy czasowej od danych wejściowych użytkownika?
Jaką wartość ma Pan reprezentować? 'Instant' nie * logicznie * wie o systemie kalendarzy - to tylko punkt w czasie - więc dodanie miesiąca do niego nie ma sensu. Powinieneś również dokładnie rozważyć, czy * naprawdę * chcesz korzystać ze strefy czasowej systemu - czy chcesz uzyskać różne wyniki dla tych samych wartości, w zależności od tego, gdzie pracujesz? –
@JonSkeet Czy byłoby bardziej odpowiednie arbitralne wybieranie identyfikatora strefy? Zawsze GMT czy coś? Wygląda na to, że może to pochodzić z własnego zestawu problemów. Być może problemem jest to, że nie wiem, jak reprezentować moje java.util.date. Mam punkt w czasie. Jeśli spełnione są określone warunki, chcę zmienić ten punkt na jeden miesiąc (lub dzień, rok, cokolwiek) w przyszłości. – jacobhyphenated
Korzystanie z UTC może być najlepszą opcją, ale naprawdę musisz pomyśleć o swoich wymaganiach. Co to znaczy zmienić punkt w czasie (bez strefy czasowej lub kalendarza) o jeden miesiąc? –