Làm cách nào để nhận ngày UTC + 0 trong Java 8?


108

Tôi gặp sự cố với lớp Ngày trong Java. Lớp ngày trả về ngày máy cục bộ nhưng tôi cần UTC-0.

Tôi đã tìm kiếm trên Google và tìm thấy giải pháp tuyệt vời cho JavaScript nhưng đối với Java thì không có gì hữu ích.

Làm cách nào để nhận ngày UTC + 0 trong Java 8?


12
java.util.Datekhông bao giờ là ngày máy cục bộ. Nó luôn được định nghĩa là mili giây trôi qua kể từ 1970-01-01 liên quan đến UTC + 00: 00. Có thể hành vi của phương thức của nó toString()làm bạn bối rối khi thực sự sử dụng một đại diện trong múi giờ địa phương.
Meno Hochschild

Một câu trả lời có thể xảy ra có thể được tìm thấy trong các câu hỏi: stackoverflow.com/questions/45350095/...
Priya Jain

Câu trả lời:


146

Với Java 8, bạn có thể viết:

OffsetDateTime utc = OffsetDateTime.now(ZoneOffset.UTC);

Để trả lời nhận xét của bạn, sau đó bạn có thể chuyển đổi nó thành Ngày (trừ khi bạn phụ thuộc vào mã kế thừa mà tôi không thấy lý do tại sao) hoặc thành mili kể từ kỷ nguyên:

Date date = Date.from(utc.toInstant());
long epochMillis = utc.toEpochSecond() * 1000;

1
cảm ơn. có thể chuyển đổi ZonedDateTime thành Date hoặc dài (mili giây) không?
Đánh dấu

7
Mặc dù mã của Câu trả lời này hoạt động về mặt kỹ thuật, sẽ không thích hợp hơn khi sử dụng OffsetDateTimethay vì ZonedDateTimechúng tôi đang làm việc với một khoảng thời gian chỉ bù trừ từ UTC thay vì một múi giờ đầy đủ?
Basil Bourque

179

tl; dr

Instant.now()

java.time

Các lớp date-time cũ rắc rối đi kèm với các phiên bản Java sớm nhất đã được thay thế bằng các lớp java.time được tích hợp trong Java 8 trở lên. Xem Hướng dẫn Oracle . Phần lớn chức năng đã được chuyển ngược sang Java 6 & 7 trong ThreeTen-Backport và được điều chỉnh thêm cho Android trong ThreeTenABP .

Instant

An Instantđại diện cho một thời điểm trên dòng thời gian theo giờ UTC với độ phân giải lên đến nano giây .

Instant instant = Instant.now();

Các toStringphương pháp tạo ra một đối tượng String bằng văn bản đại diện cho các giá trị ngày tháng thời gian bằng một trong những tiêu chuẩn ISO 8601 định dạng.

String output = instant.toString();  

2016-06-27T19: 15: 25.864Z

Các Instantlớp là một lớp xây dựng khối cơ bản trong java.time. Đây nên là bài học của bạn khi xử lý ngày-giờ vì thông thường, phương pháp hay nhất là theo dõi, lưu trữ và trao đổi các giá trị ngày-giờ trong UTC.

OffsetDateTime

Nhưng Instantcó những hạn chế như không có tùy chọn định dạng để tạo chuỗi ở các định dạng thay thế. Để linh hoạt hơn, hãy chuyển đổi từ Instantsang OffsetDateTime. Chỉ định offset-from-UTC . Trong java.time có nghĩa là một ZoneOffsetđối tượng. Ở đây chúng tôi muốn gắn bó với UTC (+00) để có thể sử dụng hằng số thuận tiện ZoneOffset.UTC.

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC );

2016-06-27T19: 15: 25.864Z

Hoặc bỏ qua Instantlớp học.

OffsetDateTime.now( ZoneOffset.UTC )

Bây giờ với một OffsetDateTimeđối tượng trong tay, bạn có thể sử dụng DateTimeFormatterđể tạo các đối tượng Chuỗi với văn bản ở các định dạng thay thế. Tìm kiếm Tràn ngăn xếp để biết nhiều ví dụ về cách sử dụng DateTimeFormatter.

ZonedDateTime

Khi bạn muốn hiển thị thời gian trên đồng hồ treo tường cho một số múi giờ cụ thể, hãy áp dụng a ZoneIdđể lấy a ZonedDateTime.

Trong ví dụ này, chúng tôi áp dụng múi giờ Montréal. Vào mùa hè, dưới thời gian vô nghĩa của Giờ tiết kiệm ánh sáng ban ngày (DST) , vùng này có giá trị bù đắp -04:00. Vì vậy, lưu ý cách thời gian trong ngày sớm hơn bốn giờ trong đầu ra, 15thay vì 19giờ. InstantZonedDateTimecả hai đều đại diện cho cùng một thời điểm đồng thời, chỉ được nhìn qua hai thấu kính khác nhau.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

2016-06-27T15: 15: 25.864-04: 00 [Mỹ / Montreal]

Chuyển đổi

Mặc dù bạn nên tránh các lớp ngày-giờ cũ, nhưng nếu cần, bạn có thể chuyển đổi bằng cách sử dụng các phương thức mới được thêm vào các lớp cũ. Ở đây chúng tôi sử dụng java.util.Date.from( Instant )java.util.Date::toInstant.

java.util.Date utilDate = java.util.Date.from( instant );

Và đi theo hướng khác.

Instant instant= utilDate.toInstant();

Tương tự, hãy tìm kiếm các phương thức mới được thêm vào GregorianCalendar(lớp con của Calendar) để chuyển đổi sang và từ java.time.ZonedDateTime.

Bảng các loại lớp ngày-giờ trong java.time hiện đại so với kế thừa.

Giới thiệu về java.time

Các java.time khung được xây dựng vào Java 8 và sau đó. Những lớp học thay thế cái cũ phiền hà di sản lớp học ngày thời gian như java.util.Date, Calendar, & SimpleDateFormat.

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

Các Joda thời gian dự án, bây giờ trong chế độ bảo trì , khuyên chuyển đổi sang các java.time lớp.

Bạn có thể trao đổi các đối tượng java.time trực tiếp với cơ sở dữ liệu của mình. Sử dụng trình điều khiển JDBC tương thích với JDBC 4.2 trở lên. Không cần chuỗi, không cần java.sql.*lớp. Hibernate 5 & JPA 2.2 hỗ trợ java.time .

Lấy các lớp java.time ở đâu?


3
Đánh giá cao vì đã nói DST là một điều vô nghĩa :-)
prash 21/02

vì vậy nếu DST không tồn tại ZonedDateTimethì sẽ không cần thiết vì tất cả ZoneIdsẽ ánh xạ tới một cái ZoneOffsetmà chúng ta có thể sử dụng OffsetDateTime?
wilmol

1
@wilmol Không. Giờ tiết kiệm ánh sáng ban ngày (DST) chỉ là một trong nhiều lý do tại sao các chính trị gia chọn xác định lại ranh giới múi giờ và khoảng cách giữa các múi giờ đó. Gần đây, Triều Tiên đã đổi đồng hồ nửa giờ để đồng bộ với Hàn Quốc vì lý do ngoại giao. Trong chiến tranh, những kẻ xâm lược / chiếm đóng có thể thay đổi mức bù đắp để phù hợp với mức chênh lệch của nước nhà. Hiện tại, có một mốt mới trong đó các chính phủ đang chọn ngừng thay đổi DST nhưng vẫn duy trì lâu dài trên DST thay vì quay trở lại thời gian chuẩn trước đó của họ. Luôn lập kế hoạch bù đắp cho mọi thay đổi vùng, nếu không ứng dụng của bạn cuối cùng sẽ bị hỏng.
Basil Bourque

1
Câu trả lời tuyệt vời! Tôi thực sự đánh giá cao thời gian bạn dành cho việc này. :)
drognisep

ZoneId.of ("Mỹ / Montreal"); tại sao ai đó lại phát minh ra thứ như vậy trong jdk? nó xấu xí, ghê tởm, không nói có sai sót gì cho đến thời gian chạy, ai có thể nhớ hết những đoạn mã khó? tại sao không cấy nó vào lớp ENUM?
workplaylifecycle

4

Trong java8, tôi sẽ sử dụng Instantlớp đã có trong UTC và thuận tiện để làm việc với.

import java.time.Instant;

Instant ins = Instant.now();
long ts = ins.toEpochMilli();

Instant ins2 = Instant.ofEpochMilli(ts)

Ngoài ra, bạn có thể sử dụng như sau:

import java.time.*;

Instant ins = Instant.now(); 

OffsetDateTime odt = ins.atOffset(ZoneOffset.UTC);
ZonedDateTime zdt = ins.atZone(ZoneId.of("UTC"));

Quay lại Instant

Instant ins4 = Instant.from(odt);

3
Không, một Instantkhông tại giờ địa phương. An Instanttheo định nghĩa là UTC. Vì vậy, không cần các mưu đồ được thấy trong Câu trả lời này cố gắng vào UTC; các Instantđã trong giờ UTC. Xem Câu trả lời của tôi để biết thêm thông tin và mã đơn giản hơn nhiều.
Basil Bourque

Cảm ơn đã nhận xét.
Abel Terefe


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.