2017-12-14 163 views
5

Ai đó có thể giải thích tại sao lại như vậy? Tại sao có 24 phút bù đắp cho thời gian đó và làm thế nào để đối phó với nó?java.sql.Timestamp phân tích cú pháp sai thời gian

Scala 2.12 và 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

Ngôn ngữ của bạn là gì? Đi qua Java 8 chỉ, không có Scala, tôi không thể tái tạo điều này bằng ngôn ngữ của tôi (en_US). – rgettman

+1

@rgettman 'ZoneId.systemDefault' trả lại' Châu Âu/Warsaw ' –

+0

Tôi đã sao chép vấn đề với 'System.setProperty (" user.timezone "," Europe/Warsaw ");' ... trông giống như một lỗi đối với tôi và đã có lỗi múi giờ trong quá khứ. Bước qua mã thư viện có vẻ như có một sự chuyển đổi không có thật trong cơ sở dữ liệu zoneinfo trong khoảng thời gian đó. Nó sẽ mất một số công việc để xác minh điều này, và tôi không có thời gian ngay bây giờ, thật không may. –

Trả lời

4

Nhìn vào định nghĩa múi giờ trong cơ sở dữ liệu múi giờ 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 

Năm 1900, Ba Lan đã có một múi giờ bù đắp một giờ và 24 phút từ UTC, tức là, họ đang sử dụng thời gian mặt trời trung bình của địa phương. Đó là trước khi các múi giờ chuẩn được giới thiệu vào ngày 5 tháng 8 năm 1915.

Nó phải là bạn cấp PostgreSQL một timestamp without time zone, được diễn giải theo múi giờ địa phương của bạn (với độ lệch là 1:24).

Ai đó (scala?) Sau đó chuyển đổi dấu thời gian này trở lại dấu thời gian trong múi giờ địa phương của bạn, nhưng sử dụng sai lệch khoảng một giờ.

Tôi không biết làm thế nào chính xác để khắc phục điều đó, nhưng một trong hai sử dụng timestamp without time zone suốt hoặc sửa chữa các thành phần đó cho rằng thời gian Ba ​​Lan đã được bù đắp 1 giờ từ UTC vào năm 1900.

+0

Đúng: Java 8 của tôi không biết về bất kỳ chuyển đổi nào trong năm 1900. Đầu tiên nó biết là vào năm 1915: Chuyển đổi [Chồng chéo lúc 1915-08-05T00: 00 + 01: 24 đến +01: 00]. –

+0

Cảm ơn. Hình như Java là vấn đề rồi. Vì vậy, lựa chọn duy nhất còn lại là để tránh 'dấu thời gian với múi giờ'. –

+0

Tôi cho rằng bạn có thể sử dụng dấu thời gian với múi giờ trong cơ sở dữ liệu của mình nếu bạn chỉ có thể sử dụng 'java.time.Instant' để lưu và truy xuất (hoặc' Chuỗi' nếu mọi thứ khác không thành công, nhưng bạn muốn 'Instant'). –

2

Theo như tôi có thể nói có hai lỗi liên quan ở đây. Cả hai đều là (nếu tôi đúng) trong lớp java.util.Date, lớp cha của java.sql.Timestamp.

Đầu tiên, không có thời gian chuyển đổi bù đắp ở Warsaw vào năm 1900. Việc chuyển đổi sớm nhất mà Java 8 của tôi biết là vào năm 1915. Vì vậy, Warsaw đã được bù đắp 1:24 từ GMT trong suốt thời gian chúng tôi quan tâm với.

tôi đã cố gắng:

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)); 

này in:

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 

Phương pháp này Timestamp.valueOf phương pháp mà bạn sử dụng gián tiếp sử dụng một phản Date constructor, vì vậy rất là I (không giống constructor chính xác, tôi đang sử dụng cái không có giây, tin tưởng nó không tạo ra sự khác biệt nào). Tôi sẽ bình luận về ba trường hợp trên ngược:

  • 1:24 được xử lý một cách chính xác, chúng tôi nhận được thời gian dự kiến ​​từ cả Date.toString() và từ OffsetDateTime.
  • 1:14 được xem là 1:38, 24 phút sau đó. Điều này trông giống như một lỗi đối với tôi.
  • 0:59 được xem là 1:23, cũng sau 24 phút. Chúng ta có thể thấy điều này từ OffsetDateTime. Cùng một lỗi. Tuy nhiên, Date.toString() sản xuất 00:59 như mong đợi. Điều này dường như tôi là một lỗi thứ hai mà bằng cách nào đó bù đắp cho cái đầu tiên. Tôi chưa kiểm tra, nhưng tôi nghi ngờ rằng nguồn gốc của lỗi này cũng gây ra Timestamp.toString() để hoạt động không chính xác.

Là séc, tôi đã tính chênh lệch giữa các đối tượng Timestamp của bạn là 0:59 và 1:24. Kết quả mong muốn là 25 phút hoặc 1 500 000 mili giây.Mã này là:

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()); 

này in

60000 

60 giây, giống như 1 phút. Vì vậy, mặc dù cả hai dấu thời gian được in theo cách chúng tôi đã mong đợi, vẫn có một lỗi liên quan.

Các vấn đề liên quan