2016-09-12 47 views
5

Tôi nhầm lẫn với thời gian xử lý trong thời gian java. Tôi đã làm việc lâu dài dưới giả định rằng nếu một dấu thời gian được chỉ định là thời gian zulu, java sẽ chăm sóc bù đắp liên quan đến giờ địa phương.Lẫn lộn với Java Phân tích cú pháp thời gian UTC

Để minh họa. Tôi hiện đang ở BST có khoản chênh lệch là UTC +1. Với ý nghĩ đó, tôi mong chờ thời gian zulu này:

2016-09-12T13:15:17.309Z 

2016-09-12T14:15:17.309 

LocalDateTime sau khi phân tích nó. Điều này là do thời gian hệ thống mặc định của tôi được đặt thành BST và dấu thời gian trên (thời gian zulu) chỉ định rằng đó là thời gian UTC.

Thay vào đó tuy nhiên xem xét mẫu này:

 String ts = "2016-09-12T13:15:17.309Z"; 
     LocalDateTime parse = LocalDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME); 
     System.out.println(parse); 

này sẽ in:

2016-09-12T13:15:17.309 

Vì vậy, các dấu thời gian, phân tích như một LocalDateTime, không được công nhận như thời gian UTC và thay vào đó coi như localtime trực tiếp. Vì vậy, tôi nghĩ, có lẽ tôi cần phải phân tích nó như là một ZonedDateTime và chuyển đổi nó để LocalDateTime cụ thể để có được thời gian địa phương chính xác. Với xét nghiệm này:

 String ts = "2016-09-12T13:15:17.309Z"; 
     ZonedDateTime parse = ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME); 
     System.out.println(parse); 
     System.out.println(parse.toLocalDateTime()); 

tôi nhận được kết quả đầu ra:

2016-09-12T13:15:17.309Z 
2016-09-12T13:15:17.309 

Cùng sản lượng cho cả ngày.

Cách duy nhất để phân tích một cách chính xác này mà tôi có thể tìm thấy, là:

String ts = "2016-09-12T13:15:17.309Z"; 
    Instant instant = Instant.parse(ts); // parses UTC 
    LocalDateTime ofInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); 
    System.out.println(instant); 
    System.out.println(ofInstant); 

in này:

2016-09-12T13:15:17.309Z 
2016-09-12T14:15:17.309 

Đó là chính xác.

Vậy câu hỏi (s) là:

  • nên không có thời gian java nhận ra một UTC dấu thời gian và phân tích nó để mặc định hệ thống có đúng không?
  • Làm cách nào để sử dụng phương thức LocalDateTime#parse để nhận kết quả chính xác?
  • Tôi có nên sử dụng Instant cho mọi thứ ngay bây giờ và hủy phân tích cú pháp không?

Vấn đề là các mô-đun thời gian java của phân tích cú pháp dấu thời gian bằng định dạng ISO và phương pháp LocalDateTime#parse thông thường. Tôi nhận ra rằng thời gian của tôi là không tắt vì họ đang được coi là LocalTime trong khi trên thực tế họ đang trong thời gian Zulu.

Trả lời

5

Bạn hiểu sai mục đích của LocalDateTime.

Để trích dẫn tài liệu hướng dẫn lớp:

Một ngày thời gian mà không có một múi giờ trong hệ thống lịch tiêu chuẩn ISO-8601, chẳng hạn như {@code 2007-12-03T10: 15: 30}.

Lớp này không lưu trữ hoặc đại diện cho múi giờ. Thay vào đó, nó là một mô tả về ngày tháng, như được sử dụng cho ngày sinh nhật, kết hợp với thời gian địa phương như được thấy trên đồng hồ treo tường. Nó không thể biểu diễn tức thì trên dòng thời gian mà không có thông tin bổ sung, chẳng hạn như vùng bù hoặc múi giờ.

Vì vậy, nó là mục đích rõ ràng là chỉ để đại diện cho một ngày và thời gian mà không một múi giờ. Đó là porpose là không để trình bày ngày và giờ theo múi giờ địa phương.

Do đó, mỗi chuyển đổi chỉ tách múi giờ.

Vì vậy, cho mục đích của bạn, bạn cần ZonedDateTime với ZoneId.systemDefault() như bạn đã sử dụng trong ví dụ thứ ba của mình.

Ví dụ thứ hai của bạn này có thể là:

String ts = "2016-09-12T13:15:17.309Z"; 
ZonedDateTime parse = 
    ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME) 
     .withZoneSameInstant(ZoneId.systemDefault()); 
System.out.println(parse); 
System.out.println(parse.toLocalDateTime()); 
+0

Ví dụ của bạn có vẻ như sẽ thực hiện cuộc trò chuyện tức thì trong ví dụ của tôi 3. Bạn nói đúng, tôi hiểu nhầm những gì LocalDateTime là viết tắt của. ughh .. timezones :) Cảm ơn – pandaadb

+0

Ah, vì vậy ZonedDateTime nhận ra múi giờ là "Z" mà nó diễn giải là UTC tự động (chỉ là những gì tôi muốn) - có đúng không? – pandaadb

+0

@pandaadb Vâng, nó có lẽ chỉ là một cách khác để viết này. –

3

tl; dr

Ví dụ:

Instant.parse("2016-09-12T13:15:17.309Z") 
     .atZone(ZoneId.of("Europe/London")) 
     .toString(); 

2016-09-12T14: 15: 17,309 + 01: 00 [Châu Âu/London]

Run in IdeOne.com.

Chi tiết

Answer by Krüske là chính xác. Bạn hiểu nhầm ý nghĩa của lớp LocalDateTime. Nó không đại diện cho ngày giờ của một địa phương cụ thể. Ngược lại, nó không không là thời điểm thực tế.

Tôi khuyên bạn nên nghĩ đến Instant làm lớp xây dựng cơ bản trong java.time. Lớp Instant đại diện cho một thời điểm trên dòng thời gian trong UTC với độ phân giải nanoseconds (tối đa chín (9) chữ số của một phần thập phân).

Chuỗi đầu vào của bạn tuân theo định dạng ISO 8601 được sử dụng theo mặc định trong lớp Instant cho cả phân tích cú pháp và tạo biểu diễn chuỗi. Các Z cuối cùng là viết tắt của Zulu và có nghĩa là UTC. Không cần chỉ định mẫu định dạng.

Instant instant = Instant.parse("2016-09-12T13:15:17.309Z"); 

Là một lập trình viên, bạn nên học cách suy nghĩ và làm việc trong UTC. Hãy quên đi múi giờ của riêng bạn. Hãy nghĩ về UTC là Thời gian thực. Áp dụng múi giờ làm biến thể và chỉ khi cần.

Chỉ định proper time zone name ở định dạng continent/region, chẳng hạn như America/Montreal, Africa/Casablanca hoặc Pacific/Auckland. Không bao giờ sử dụng từ viết tắt 3-4 ký tự như BST hoặc EST hoặc IST vì chúng không phải là múi giờ thực, không được chuẩn hóa và không phải là duy nhất (!). Nếu theo số BST, bạn có nghĩa là Giờ mùa hè của Anh, thì tên múi giờ thực tế sẽ là Europe/London. Các lớp java.time sẽ xác định cách điều chỉnh cho bất kỳ sự bất thường nào bao gồm Daylight Saving Time (DST).

ZoneId z = ZoneId.of("Europe/London"); 
ZonedDateTime zdt = instant.atZone(z); 

Về java.time

Khung java.time được xây dựng vào Java 8 và sau đó. Các lớp này thay thế các lớp học ngày giờ legacy phiền hà cũ như java.util.Date, Calendar, & SimpleDateFormat.

Dự án Joda-Time, hiện đang ở maintenance mode, khuyên di chuyển sang java.time.

Để tìm hiểu thêm, hãy xem Oracle Tutorial. Và tìm kiếm Stack Overflow cho nhiều ví dụ và giải thích. Đặc điểm kỹ thuật là JSR 310.

Nơi lấy các lớp java.time?

  • Java SE 8SE 9 và sau
    • Built-in.
    • Một phần của API Java chuẩn với gói được triển khai.
    • Java 9 thêm một số tính năng và bản sửa lỗi nhỏ.
  • Java SE 6SE 7
    • Hầu hết các chức năng java.time được back-chuyển đến Java 6 & 7 trong ThreeTen-Backport.
  • Android

Dự án mở rộng ThreeTen-Extra java.time với các lớp bổ sung. Dự án này là một nền tảng chứng minh cho những bổ sung có thể có trong tương lai vào java.time.Bạn có thể tìm thấy một số lớp học hữu ích tại đây như Interval, YearWeek, YearQuartermore.

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