Mam converter w którym robię instant.toEpochMilli()
i w sumie dostawałem dobry czas w mojej strefie aż do momentu gdy podbiłem jave do 21 springa do 6.1.2 a springboota do 3.2.1 i od tego momentu już dostaje o 1h do przodu, why?
Jeżeli Java działa w kontenerze to coś mi w głowie świta że był taki problem. Po prostu ustaw to jawnie i będzie po kłopocie: https://www.baeldung.com/java-jvm-time-zone
0xmarcin napisał(a):
Jeżeli Java działa w kontenerze to coś mi w głowie świta że był taki problem. Po prostu ustaw to jawnie i będzie po kłopocie: https://www.baeldung.com/java-jvm-time-zone
Chcę po prostu aby data z bazy była taka sama jak z mojego API (w bazie chyba mam dobrą strefę bo jak robię select now()
to zwraca aktualną datę)
Próbowałem już z -Duser.timezone="Europe/Warsaw"
, nawet dodałem dodatkowo TimeZone.setDefault(TimeZone.getTimeZone("Europe/Warsaw"));
a i tak po podbiciu javy do 21 i springa mam po instant.toEpochMilli()
o 1h do przodu
Możliwe, że konwersja zachodzi między time zone serwera bazodanowego oraz klientem (sterownikiem JDBC). Bazy TZ są od czasu do czasu aktualizowane, może trafiłęś w taką aktualizację.
a) na której wersji było ok?
b) jaka baza? jaka tz ustawiona na bazie?
c) jaki sterownik bazodanowy? (wersja)
d) jakie masz locale ustawione na maszynie, z której uruchamiasz jvm'a
e) czy używasz tej samej bazy do reprodukcji problemu (między java21 a javaXYZ? )
yarel napisał(a):
Możliwe, że konwersja zachodzi między time zone serwera bazodanowego oraz klientem (sterownikiem JDBC). Bazy TZ są od czasu do czasu aktualizowane, może trafiłęś w taką aktualizację.
a) na której wersji było ok?
b) jaka baza? jaka tz ustawiona na bazie?
c) jaki sterownik bazodanowy? (wersja)
d) jakie masz locale ustawione na maszynie, z której uruchamiasz jvm'a
e) czy używasz tej samej bazy do reprodukcji problemu (między java21 a javaXYZ? )
korzystam z jdbc, hibernate (org.hibernate.orm.hibernate-core:6.4.4.Final), gdy na mysql robię select now()
to mam aktualną datę. Wszędzie w apce mam "Europe/Warsaw". na java 18 było OK a na 21 się pomieszało, baza podpięta cały czas ta sama
Z dokumentacji:
The java.time.Instant.toEpochMilli() method converts this instant to the number of milliseconds from the epoch of 1970-01-01T0000Z.
Jeżeli korzystasz ze Swagger/OpenAPI sprawdź jaki tam typ jest użyty, może biblioteka lub JSON serializer jest ustwaiony tak żeby zwracać w UTC?
0xmarcin napisał(a):
Z dokumentacji:
The java.time.Instant.toEpochMilli() method converts this instant to the number of milliseconds from the epoch of 1970-01-01T0000Z.
Jeżeli korzystasz ze Swagger/OpenAPI sprawdź jaki tam typ jest użyty, może biblioteka lub JSON serializer jest ustwaiony tak żeby zwracać w UTC?
nie używam żadnych swaggerów.
Jak napisałem w komentarzu wyżej:
przed podbiciem, czyli java 18
Instant i = getDateFromDB();
System.out.println(i); //zwraca 2024-02-19T08:00:10Z
System.out.println(i.toEpochMilli()); //zwraca 1708329610000
po podbiciu, czyli java 21:
Instant i = getDateFromDB();
System.out.println(i); //zwraca 2024-02-19T09:00:10Z
System.out.println(i.toEpochMilli()); //zwraca 1708333210000
Wygląda na problem generowany przez sterownik JDBC.
Moja hipoteza robocza:
a) podbicie wersji springa i springboota skutkuje podbiciem wersji sterownika JDBC do wersji 8.3.0 (https://docs.spring.io/spring-boot/docs/current/reference/html/dependency-versions.html)
b) Twoje obecna konfiguracja połączenia do bazy danych (którą się nie pochwaliłeś w tym wątku), może operować na właściwościach, które w wersji 8+ zostały usunięte ( https://dev.mysql.com/doc/connectors/en/connector-j-upgrading-to-8.0.html)
Wersja 8+ jedzie na ustawieniach domyślnych i robi jakąś konwersję z time zone bazy do domyślnej time zony sterownika.
A jak jest zapisana data w bazie? Tzn. jaki typ i jaka wartość?
wartek01 napisał(a):
A jak jest zapisana data w bazie? Tzn. jaki typ i jaka wartość?
typ to datetime
a wartość to 2024-02-19 09:00:10
I teraz jak uzyskać tą samą datę w zwrotce api przy java 21 i najnowszym springu?
Nie masz problemu z Instant.toEpochMilli()
tylko z tym jak JDBC / cokolwiek w środku tego getDateFromDB()
interpretuje datę z bazy i tworzy z tego Instant
. Sterownik JDBC, ustawienie połączenia z bazą, czy jakiś kod którego nam tu nie pokazałeś.
I teraz jak uzyskać tą samą datę w zwrotce api przy java 21 i najnowszym springu?
Co to za baza, MySQL? Jak ustawiasz połączenie do bazy, może możesz tam też ustawić timezone? Czy z podbiciem javy do 21 zmieniła ci się wersja JDBC? Co jest w środku tego getDateFromDB()
?
W ogóle to trzymanie czasu w bazie w lokalnej strefie czasowej, gdzie informacja jaka to strefa czasowa wynika jedynie z ustawienia strefy czasowej serwera to kiepski pomysł. I ja się nie dziwię, że jeden rabin ("Java 18") odczyta tak, a drugi rabin ("Java 21") odczyta inaczej. Lepiej trzymać to jako UTC albo jakiś typ z informacją o strefie czasowej. Ale to dygresja.
spróbuj ustawić na twoją strefę tego propertiesa: spring.jpa.properties.hibernate.jdbc.time_zone=UTC
(podmień UTC)