2009-08-06 37 views
18

Đoạn mã sau xuất hiện để chứng minh một lỗi trong java.util.Date theo đó một giờ được thêm vào nếu đồng hồ cục bộ được đặt thành GMT với điều chỉnh DST và thời gian trước ngày 1 tháng 11 năm 1971. Giả định đầu tiên của tôi luôn là tôi đã sai rồi. Bất cứ ai có thể nhìn thấy những gì sai (hoặc đây thực sự là một lỗi Java)? Điều gì quan trọng vào ngày 1 tháng 11 năm 1971?Tại sao một giờ được thêm vào java.util.Date cho các ngày trước ngày 1 tháng 11 năm 1971?

import java.text.SimpleDateFormat; 
import java.util.Locale; 
import java.util.TimeZone; 

class JavaUtilDateBug 
{ 
    private static void demo() throws Exception 
    { 
     // UK developers usually have the clock on their development machines set 
     // to "Europe/London" (i.e. GMT with daylight saving). Set it explicitly 
     // here so readers in other countries can see the problem too. 
     TimeZone.setDefault(TimeZone.getTimeZone("Europe/London")); 
     Locale.setDefault(Locale.ENGLISH); 

     SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy"); 
     String strJan1st1970Expected = "Thu Jan 01 00:00:00 GMT 1970"; 
     String strJan1st1970Actual = dateFormat.parse(strJan1st1970Expected).toString(); 
     System.out.println("strJan1st1970Actual: " + strJan1st1970Actual); // -> "Thu Jan 01 01:00:00 GMT 1970" 
     boolean jvmHasDateBug = !strJan1st1970Expected.equals(strJan1st1970Actual); 
     System.out.println("jvmHasDateBug: " + jvmHasDateBug); // -> true 

     // The anomaly only seems to affect times before 1 Nov 1971. 
     final String strNov1st1971 = "Mon Nov 01 00:00:00 GMT 1971"; 
     assert strNov1st1971.equals(dateFormat.parse(strNov1st1971).toString()); 
    } 

    public static void main(String[] args) 
    { 
     try 
     { 
      demo(); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

My Java môi trường:

java version "1.6.0_13" 
    Java(TM) SE Runtime Environment (build 1.6.0_13-b03) 
    Java HotSpot(TM) Client VM (build 11.3-b02, mixed mode, sharing) 
+1

Chương trình demo của bạn chỉ hoạt động trên các máy không phải tiếng Anh nếu bạn cũng đặt ngôn ngữ địa phương (phân tích ngày không thành công). –

+0

Cảm ơn, Michael. Đã cập nhật mã demo. –

Trả lời

5

Tôi đã tìm thấy matching bug trong cơ sở dữ liệu lỗi của Sun. Dường như họ coi đó là "sự thiếu chính xác lịch sử" (định dạng rõ ràng sẽ tạo ra "BST" là múi giờ chứ không phải GMT - giờ sẽ chính xác) và sẽ không sửa chữa nó, bởi vì sâu bên dưới, việc triển khai TimeZone không thể xử lý các địa điểm chuyển đổi tên múi giờ của họ.

Giải pháp thay thế, bạn có thể đặt múi giờ của mình thành GMT thay vì "Châu Âu/Luân Đôn". Vấn đề sau đó biến mất.

+0

Lỗi này dường như không còn trong cơ sở dữ liệu lỗi. –

13

Đó là miền địa phương. Từ http://en.wikipedia.org/wiki/British_Summer_Time

Đề án Thời gian chuẩn của Anh được thử nghiệm từ ngày 27 tháng 10 năm 1968 đến ngày 31 tháng 10 năm 1971, khi nước Anh duy trì trên GMT + 1 cả năm.

+0

Wow, nghĩ rằng đã quá mơ hồ để được trả lời hai lần ... –

+0

Bah. Tôi đã trả lời một nửa số ma khi tôi được thông báo về hai người của bạn. –

21

Đã có bản dùng thử Thời gian chuẩn của Anh từ ngày 27 tháng 10 năm 1968 đến ngày 31 tháng 10 năm 1971, điều tôi nghi ngờ là nguyên nhân gây ra sự cố này.

Có một số chi tiết của cuộc thử nghiệm ở đây:

http://en.wikipedia.org/wiki/British_Summer_Time#Single.2FDouble_Summer_Time

Các múi giờ cho Châu Âu/London ngày 01 Tháng 1 1970 là Giờ chuẩn Anh (GMT + 1) vì vậy khi bạn sử dụng một java.text.SimpleDateFormat để phân tích 01 Tháng 1 00:00:00 GMT 1970 nó tạo ra giá trị epoch chính xác bằng Jan 01 01:00:00 1970 trong BST.

Sau đó, do sự crappiness của java.util.Date, khi bạn gọi java.util.Date.toString() nó sử dụng múi giờ mặc định cho các địa phương hiện nay như của tại, mà đã thay đổi đến giờ và bạn sẽ có được 1 tháng 1 01:00:00 GMT 1970.

+0

Thú vị. Tuy nhiên, vẫn chưa rõ lý do tại sao nó không đối xứng, nếu bạn ăn trong "Thu Jan 01 00:00:00 GMT 1970" bạn sẽ nhận được cùng một trở lại. –

+0

Đây không phải là vấn đề với java.util.Date toString(), hành vi không khác khi bạn định dạng nó bằng cách sử dụng cùng SimpleDateFormat mà bạn đã sử dụng để phân tích cú pháp. Xem câu trả lời của tôi cho Sun đưa về điều này. –

+0

Hey Michael - hãy xem phương thức normalize() java.util.Date. Nó được gọi từ phương thức toString() và thực hiện cuộc gọi TimeZone.getDefaultRef() để lấy múi giờ. Điều đó có vẻ giống như nguyên nhân phải không? –

0

Đây không phải là lỗi.

Bạn đã thiết lập múi giờ mặc định của bạn để BST đó là (GMT + 1), ngày GMT của Jan 1 1970 00:00:00, khi bạn phân tích ngày nay sử dụng BST múi giờ như mặc định của bạn, nó luôn luôn hiển thị thời gian dựa trên múi giờ hiện tại của bạn (tự động gây hiệu ứng bù đắp từ GMT) .

Trong trường hợp này là GMT + 1 đó là lý do tại sao kết quả của bạn là một giờ nghỉ.

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