2016-07-31 30 views
6

Trước Java-8, tôi đã quen với việc luôn giữ bất kỳ ngày/thời gian nào liên quan như mili giây kể từ Epoch và chỉ xử lý ngày/giờ có thể đọc được trên con đường, tức là trong giao diện người dùng hoặc tệp nhật ký hoặc khi phân tích cú pháp người dùng được tạo đầu vào.Java 8 epoch-millis tem thời gian để định dạng ngày, làm thế nào?

Tôi nghĩ rằng điều này vẫn an toàn với Java-8, và bây giờ tôi đang tìm cách ngắn gọn nhất để có được một ngày được định dạng từ một dấu thời gian mili giây. Tôi cố gắng

df = Dateformatter.ofPattern("...pattern..."); 
df.format(Instant.ofEpochMilli(timestamp)) 

nhưng nó bom ra với Unsupported field: YearOfEra trong Instant.getLong(...) mà tôi nửa hiểu. Bây giờ những gì để sử dụng thay vì Instant?

LocalDateTime.ofEpoch(Instant, ZoneId) có vẻ sai, vì tôi không quan tâm đến thời gian địa phương. Tôi chỉ muốn xem múi giờ địa phương khi áp dụng trình định dạng. Bên trong nó chỉ là Instant.

Tương tự với ZonedDateTime.ofInstant(Instant, ZoneId), tôi đã nghĩ chỉ áp dụng ZoneId chỉ khi định dạng. Nhưng tôi nhận thấy rằng DateTimeFormatter không tự giải quyết thêm với múi giờ, có vẻ như vậy, vì vậy tôi nghĩ tôi cần phải sử dụng một trong những điều trên.

Điều nào được ưu tiên và tại sao? Hoặc tôi có nên sử dụng cách khác để định dạng dấu thời gian epoch-millis làm ngày/giờ với múi giờ không?

Trả lời

8

An Instant không chứa bất kỳ thông tin nào về múi giờ và không giống như ở những nơi khác, múi giờ mặc định không được sử dụng tự động. Như vậy, trình định dạng không thể tìm ra năm là gì, do đó thông báo lỗi.

Do đó, để định dạng ngay lập tức, bạn phải thêm múi giờ. Điều này có thể được bổ sung trực tiếp đến định dạng sử dụng withZone(ZoneId) - không có cần phải tự chuyển đổi sang ZonedDateTime *:

zone = ZoneId.systemDefault(); 
df = DateTimeformatter.ofPattern("...pattern...").withZone(zone); 
df.format(Instant.ofEpochMilli(timestamp)) 

* đáng tiếc, vào đầu năm 8 phiên bản Java, phương pháp DateTimeformatter.withZone(ZoneId) không hiệu quả, tuy nhiên điều này hiện đã được cố định, vì vậy nếu mã ở trên không hoạt động, hãy nâng cấp lên bản phát hành bản vá Java 8 mới nhất.

Chỉnh sửa: Chỉ cần thêm rằng Instant là lớp phù hợp để sử dụng khi bạn muốn lưu trữ ngay lập tức mà không có bất kỳ ngữ cảnh nào khác.

1

Tôi đồng ý rằng điều này hơi khó hiểu, đặc biệt khi so sánh với người tiền nhiệm là Joda DateTime.

Điều khó hiểu nhất là tài liệu cho LocalDateTime nói rằng đó là "Ngày giờ không có múi giờ" và phương thức LocalDateTime.ofInstant lấy cả múi giờ và múi giờ làm tham số.

Điều đó nói rằng, tôi nghĩ rằng bạn có thể đạt được những gì bạn muốn bằng cách sử dụng Instant và LocalDateTime.ofInstant bằng cách sử dụng múi giờ UTC.

public LocalDateTime millisToDateTime(long millis) { 
    return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of("Z"); 
} 
7

Lỗi bạn có khi định dạng Instant sử dụng trình định dạng được xây dựng với năm hoặc các trường khác dự kiến; an Instant không biết năm nào hay tháng hay ngày nào, nó chỉ biết có bao nhiêu mili giây đã trôi qua kể từ thời Đại Kỷ Nguyên. Trong cùng một khoảnh khắc, có thể là 2 ngày khác nhau trên 2 địa điểm khác nhau của Trái Đất.

Vì vậy, bạn cần phải thêm thông tin múi giờ nếu bạn muốn in trong ngày. Với số Instant, bạn có thể gọi atZone(zone) để kết hợp với ZoneId để tạo thành một ZonedDateTime. Điều này rất giống một khoảnh khắc, chỉ có nó có thông tin múi giờ. Nếu bạn muốn sử dụng múi giờ của hệ thống (một trong các máy ảo đang chạy), bạn có thể sử dụng nó với ZoneId.systemDefault().

Để in, bạn có thể sử dụng hai trình định dạng dựng sẵn ISO_OFFSET_DATE_TIME hoặc ISO_ZONED_DATE_TIME. Sự khác biệt giữa hai là định dạng ngày tháng được phân vùng sẽ thêm id vùng vào đầu ra.

Instant instant = Instant.now(); 
DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; 
System.out.println(formatter.format(instant.atZone(ZoneId.systemDefault()))); 
System.out.println(formatter.format(instant.atZone(ZoneId.of("America/Los_Angeles")))); 

khi chạy trên máy tính của tôi, trong đó có một múi giờ hệ thống của "Europe/Paris", bạn sẽ nhận được:

2016-07-31T18:58:54.108+02:00 
2016-07-31T09:58:54.108-07:00 

Bạn có thể dĩ nhiên xây dựng định dạng của riêng bạn nếu những ai không phù hợp với bạn, sử dụng ofPattern hoặc người xây dựng DateTimeFormatterBuilder.

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