2017-12-14 136 views
5

Czy ktoś może wyjaśnić, dlaczego tak jest? Dlaczego istnieje 24-minutowe przesunięcie w tym czasie i jak sobie z nim radzić?java.sql.Timestamp niepoprawny czas analizy

Scala 2.12 i Java 8.

scala> java.sql.Timestamp.valueOf("1900-01-01 00:59:00") 
res22: java.sql.Timestamp = 1900-01-01 00:59:00.0 

scala> java.sql.Timestamp.valueOf("1900-01-01 01:00:00") 
res23: java.sql.Timestamp = 1900-01-01 01:24:00.0 

scala> java.sql.Timestamp.valueOf("1900-01-01 01:14:00") 
res24: java.sql.Timestamp = 1900-01-01 01:38:00.0 

scala> java.sql.Timestamp.valueOf("1900-01-01 01:20:00") 
res25: java.sql.Timestamp = 1900-01-01 01:44:00.0 

scala> java.sql.Timestamp.valueOf("1900-01-01 01:23:00") 
res26: java.sql.Timestamp = 1900-01-01 01:47:00.0 

scala> java.sql.Timestamp.valueOf("1900-01-01 01:24:00") 
res27: java.sql.Timestamp = 1900-01-01 01:24:00.0 

scala> java.sql.Timestamp.valueOf("1900-01-01 01:30:00") 
res28: java.sql.Timestamp = 1900-01-01 01:30:00.0 
+0

Jakie jest Twoje miejsce zamieszkania? Przechodząc tylko przez Java 8, bez Scala, nie mogę odtworzyć tego w moim locale (en_US). – rgettman

+1

@rgettman 'ZoneId.systemDefault' zwraca' Europe/Warsaw' –

+0

Powieliłem problem za pomocą 'System.setProperty (" user.timezone "," Europe/Warsaw ");' ... wygląda jak błąd dla mnie, i w przeszłości występowały błędy strefy czasowej. Przechodząc przez kod biblioteki wygląda na to, że może zaistnieć fałszywe przejście w bazie danych zoneinfo dla tego okresu. Potrzeba trochę pracy, aby to zweryfikować, i niestety nie mam teraz czasu. –

Odpowiedz

4

spojrzeć na definicję strefy czasowej w bazie danych stref czasowych IANA:

# Zone NAME   GMTOFF RULES FORMAT [UNTIL] 
Zone Europe/Warsaw 1:24:00 -  LMT  1880 
         1:24:00 -  WMT  1915 Aug 5 # Warsaw Mean Time 
         1:00 C-Eur CE%sT 1918 Sep 16 3:00 
         2:00 Poland EE%sT 1922 Jun 
         1:00 Poland CE%sT 1940 Jun 23 2:00 
         1:00 C-Eur CE%sT 1944 Oct 
         1:00 Poland CE%sT 1977 
         1:00 W-Eur CE%sT 1988 
         1:00 EU CE%sT 

W roku 1900 Polska miała przesunięcie strefy czasowej o jedną godzinę i 24 minuty od UTC, tj. Wykorzystali lokalny średni czas słoneczny. To było zanim standardowe strefy czasowe zostały wprowadzone 5 sierpnia 1915 roku.

To musi być, że karmisz PostgreSQL a timestamp without time zone, który jest interpretowany w lokalnej strefie czasowej (z przesunięciem 1:24).

Ktoś (scala?) Następnie konwertuje ten znacznik czasu z powrotem na znacznik czasu w lokalnej strefie czasowej, ale błędnie używa przesunięcia o jedną godzinę.

Nie wiem dokładnie, jak to naprawić, ale użyć timestamp without time zone całej lub naprawić składnik, który uważa, że ​​czas polskiej został zniwelowany 1 godzinę od UTC w 1900.

+0

Prawidłowo: moja Java 8 nie zna żadnego przejścia w roku 1900. Najwcześniejsza znana jest w 1915: Przejście [Nakładanie w dniach 1915-08-05T00: 00 + 01: 24 do +01: 00]. –

+0

Dzięki. Wygląda na to, że Java to problem. Tak więc jedyną pozostałą opcją jest uniknięcie 'timestamp ze strefą czasową'. –

+0

Przypuszczam, że możesz użyć timestamp-with-timezone w swojej bazie danych, jeśli możesz użyć 'java.time.Instant' do zapisywania i pobierania (lub' String' jeśli wszystko inne zawiedzie, ale wolisz 'Instant'). –

2

O ile mogę powiedzieć istnieją dwa błędy tutaj. Oba są (jeśli mam rację) w klasie java.util.Date, nadklasa java.sql.Timestamp.

Po pierwsze, nie ma przesunięcia czasowego w Warszawie w roku 1900. Najwcześniejsze przejście, o którym wie moja Java 8, nastąpiło w 1915 roku. Więc Warszawa była przesunięta o 1:24 od GMT przez cały czas z.

Próbowałem:

TimeZone.setDefault(TimeZone.getTimeZone("Europe/Warsaw")); 
    ZoneOffset offset0124 = ZoneOffset.ofHoursMinutes(1, 24); 

    System.out.println("" + new Date(0, 0, 1, 0, 59) 
      + " -> " + new Date(0, 0, 1, 0, 59).toInstant().atOffset(offset0124)); 
    System.out.println("" + new Date(0, 0, 1, 1, 14) 
      + " -> " + new Date(0, 0, 1, 1, 14).toInstant().atOffset(offset0124)); 
    System.out.println("" + new Date(0, 0, 1, 1, 24) 
      + " -> " + new Date(0, 0, 1, 1, 24).toInstant().atOffset(offset0124)); 

Drukuje:

Mon Jan 01 00:59:00 CET 1900 -> 1900-01-01T01:23+01:24 
Mon Jan 01 01:38:00 CET 1900 -> 1900-01-01T01:38+01:24 
Mon Jan 01 01:24:00 CET 1900 -> 1900-01-01T01:24+01:24 

metody Timestamp.valueOf Metoda używana pośrednio korzysta z przestarzałej Date konstruktora, tak więc jestem (nie dokładnie taki sam konstruktor, ja używam tego bez sekund, ufając, że nie robi różnicy). będę komentować powyższych trzech przypadkach zacofanych:

  • 1:24 jest obsługiwane prawidłowo, mamy czas oczekiwany zarówno z Date.toString() i od OffsetDateTime.
  • 1:14 jest postrzegany jako 1:38, 24 minuty później. To dla mnie wygląda jak błąd.
  • 0:59 jest postrzegana jako 1:23, także 24 minuty później. Możemy to zobaczyć z OffsetDateTime. Ten sam błąd. Jednak Date.toString() produkuje 00:59 zgodnie z oczekiwaniami. To wydaje mi się być drugim błędem, który w jakiś sposób rekompensuje pierwszy. Nie sprawdziłem, ale podejrzewam, że źródło tego błędu powoduje również nieprawidłowe zachowanie się.

Jako czek obliczyłem różnicę między waszymi obiektami Timestamp z 0:59 i 1:24. Pożądany wynik to 25 minut lub 1 500 000 milisekund.Kod jest:

System.out.println(java.sql.Timestamp.valueOf("1900-01-01 01:24:00").getTime() 
      - java.sql.Timestamp.valueOf("1900-01-01 00:59:00").getTime()); 

Drukuje

60000 

60 sekund, tak jak 1 minutę. Mimo że oba te znaczniki czasu wydrukowały się tak, jak się spodziewaliśmy, nadal istnieje błąd.