tl; dr
Instant
và LocalDateTime
là hai động vật hoàn toàn khác nhau: Một con đại diện cho một khoảnh khắc, con kia thì không.
Instant
đại diện cho một khoảnh khắc, một điểm cụ thể trong dòng thời gian.
LocalDateTime
đại diện cho một ngày và một thời gian trong ngày. Nhưng thiếu múi giờ hoặc bù từ UTC, lớp này không thể biểu thị một khoảnh khắc . Nó đại diện cho những khoảnh khắc tiềm năng dọc theo phạm vi khoảng 26 đến 27 giờ, phạm vi của tất cả các múi giờ trên toàn cầu.
Giả định không chính xác
LocalDateTime
là đại diện ngày / đồng hồ bao gồm cả múi giờ cho con người.
Tuyên bố của bạn là không chính xác: Một LocalDateTime
có không múi giờ . Không có múi giờ là toàn bộ điểm của lớp đó.
Để trích dẫn tài liệu của lớp đó:
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, như được sử dụng cho ngày sinh nhật, kết hợp với giờ địa phương như được thấy trên đồng hồ treo tường. Nó không thể biểu thị tức thời trên dòng thời gian mà không có thông tin bổ sung như phần bù hoặc múi giờ.
Vì vậy, Local…
có nghĩa là không được khoanh vùng, không có bù bù.
Instant
Một Instant
là một khoảnh khắc trên Timeline trong UTC , một đếm nano giây kể từ khi kỷ nguyên của giây phút đầu tiên năm 1970 UTC (về cơ bản, xem lớp doc cho chi tiết thực dụng). Vì hầu hết logic kinh doanh, lưu trữ dữ liệu và trao đổi dữ liệu của bạn phải ở trong UTC, đây là một lớp tiện dụng được sử dụng thường xuyên.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
OffsetDateTime
Lớp OffsetDateTime
học đại diện cho một khoảnh khắc là một ngày và thời gian với bối cảnh của một số giờ-phút-giây trước hoặc sau, UTC. Lượng bù, số giờ-phút-giây, được biểu thị bằngZoneOffset
lớp.
Nếu số giờ-phút-giây bằng 0, một OffsetDateTime
đại diện cho một khoảnh khắc trong UTC giống như một Instant
.
ZoneOffset
Các ZoneOffset
lớp đại diện cho một bù đắp-từ-UTC , một số giờ-phút-giây trước UTC hoặc đằng sau UTC.
A ZoneOffset
chỉ là một số giờ-phút-giây, không có gì hơn. Một khu vực là nhiều hơn, có một tên và lịch sử thay đổi để bù đắp. Vì vậy, sử dụng một vùng luôn luôn thích hợp hơn là sử dụng một phần bù đơn thuần.
ZoneId
Một múi giờ được đại diện bởi các ZoneId
lớp.
Một ngày mới khởi đầu sớm hơn ở Paris so với ở Montréal chẳng hạn. Vì vậy, chúng ta cần di chuyển tay của đồng hồ để phản xạ tốt hơn vào buổi trưa (khi Mặt trời trực tiếp trên cao) cho một khu vực nhất định. Càng đi xa về phía đông / tây từ đường UTC ở tây Âu / Châu Phi thì phần bù càng lớn.
Múi giờ là một bộ quy tắc để xử lý các điều chỉnh và sự bất thường như được thực hiện bởi một cộng đồng địa phương hoặc khu vực. Sự bất thường phổ biến nhất là sự mất trí quá phổ biến được gọi là Giờ tiết kiệm ánh sáng ban ngày (DST) .
Một múi giờ có lịch sử của các quy tắc trong quá khứ, quy tắc hiện tại và quy tắc được xác nhận cho tương lai gần.
Các quy tắc này thay đổi thường xuyên hơn bạn có thể mong đợi. Hãy chắc chắn giữ các quy tắc của thư viện thời gian của bạn, thường là một bản sao của cơ sở dữ liệu 'tz' , được cập nhật. Luôn cập nhật dễ dàng hơn bao giờ hết trong Java 8 với việc Oracle phát hành Công cụ cập nhật múi giờ .
Chỉ định một tên múi giờ thích hợp trong các định dạng của Continent/Region
, chẳng hạn như America/Montreal
, Africa/Casablanca
hoặc Pacific/Auckland
. Không bao giờ sử dụng chữ viết tắt 2-4 chữ cái như EST
hoặc IST
chúng không phải là múi giờ thực, không được tiêu chuẩn hóa và thậm chí không phải là duy nhất (!).
Múi giờ = Offset + Quy tắc điều chỉnh
ZoneId z = ZoneId.of( “Africa/Tunis” ) ;
ZonedDateTime
Hãy nghĩ về ZonedDateTime
khái niệm như một Instant
với một nhiệm vụ ZoneId
.
ZiatedDateTime = (Instant + ZoneId)
Để ghi lại khoảnh khắc hiện tại như đã thấy trong thời gian đồng hồ treo tường được sử dụng bởi người dân của một khu vực cụ thể (múi giờ):
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`.
Gần như tất cả các phụ trợ, cơ sở dữ liệu, logic kinh doanh, lưu trữ dữ liệu, trao đổi dữ liệu của bạn đều phải có trong UTC. Nhưng để trình bày cho người dùng, bạn cần điều chỉnh theo múi giờ mà người dùng mong đợi. Đây là mục đích của ZonedDateTime
lớp và các lớp định dạng được sử dụng để tạo các biểu diễn Chuỗi của các giá trị thời gian đó.
ZonedDateTime zdt = instant.atZone( z ) ;
String output = zdt.toString() ; // Standard ISO 8601 format.
Bạn có thể tạo văn bản ở định dạng địa phương bằng cách sử dụng DateTimeFormatter
.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;
String outputFormatted = zdt.format( f ) ;
mardi 30 avril 2019 à 23 h 22 phút 55 s heure de l'Inde
LocalDate
, LocalTime
,LocalDateTime
Các "địa phương" lớp thời gian ngày, LocalDateTime
, LocalDate
, LocalTime
, là một loại khác nhau của critter. Không được gắn với bất kỳ một địa phương hoặc múi giờ. Họ không bị ràng buộc với dòng thời gian. Chúng không có ý nghĩa thực sự cho đến khi bạn áp dụng chúng cho một địa phương để tìm một điểm trên dòng thời gian.
Từ ngữ Local Local trong các tên lớp này có thể phản trực giác với người không quen biết. Từ này có nghĩa là bất kỳ địa phương, hoặc mọi địa phương, nhưng không phải là một địa phương cụ thể.
Vì vậy, đối với các ứng dụng kinh doanh, các loại "Địa phương" thường không được sử dụng vì chúng chỉ đại diện cho ý tưởng chung về ngày hoặc thời gian có thể không phải là một thời điểm cụ thể trên dòng thời gian. Các ứng dụng kinh doanh có xu hướng quan tâm đến thời điểm chính xác hóa đơn đến, một sản phẩm được vận chuyển, một nhân viên được thuê hoặc taxi rời khỏi nhà để xe. Vì vậy, các nhà phát triển ứng dụng kinh doanh sử dụng Instant
vàZonedDateTime
các lớp phổ biến nhất.
Vậy khi nào chúng ta sẽ sử dụng LocalDateTime
? Trong ba tình huống: nơi chúng tôi muốn áp dụng một ngày và thời gian nhất định trên nhiều địa điểm, nơi chúng tôi đang đặt các cuộc hẹn hoặc nơi chúng tôi có múi giờ dự định chưa được xác định. Lưu ý rằng không có trường hợp nào trong ba trường hợp này là một điểm cụ thể nhất định trên dòng thời gian, không có trường hợp nào trong số này là một khoảnh khắc.
Một lần trong ngày, nhiều khoảnh khắc
Đôi khi chúng tôi muốn đại diện cho một thời điểm nhất định trong một ngày nhất định, nhưng muốn áp dụng điều đó vào nhiều địa phương trên các múi giờ.
Ví dụ: "Giáng sinh bắt đầu vào nửa đêm ngày 25 tháng 12 năm 2015" là một LocalDateTime
. Nửa đêm đình công ở những thời điểm khác nhau ở Paris so với ở Montréal, và lại khác ở Seattle và Auckland .
LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ; // 00:00:00
LocalTime ldt = LocalDateTime.of( ld , lt ) ; // Xmas morning anywhere.
Một ví dụ khác, "Công ty Acme có chính sách bắt đầu lúc 12:30 PM tại mỗi nhà máy của mình trên toàn thế giới" là một LocalTime
. Để có ý nghĩa thực sự, bạn cần áp dụng nó vào dòng thời gian để tính thời điểm 12:30 tại nhà máy ở Stuttgart hoặc 12:30 tại nhà máy Rabat hoặc 12:30 tại nhà máy Sydney .
Đặt lịch hẹn
Một tình huống khác để sử dụng LocalDateTime
là để đặt các sự kiện trong tương lai (ví dụ: các cuộc hẹn với nha sĩ). Những cuộc hẹn này có thể đủ xa trong tương lai mà bạn có nguy cơ các chính trị gia xác định lại múi giờ. Các chính trị gia thường đưa ra lời cảnh báo nhỏ, hoặc thậm chí không có cảnh báo nào cả. Nếu bạn có nghĩa là "3 giờ chiều ngày 23 tháng 1" bất kể các chính trị gia có thể chơi với đồng hồ như thế nào, thì bạn không thể ghi lại một khoảnh khắc - điều đó sẽ thấy 3 giờ chiều biến thành 2 giờ chiều hoặc 4 giờ chiều nếu khu vực đó được thông qua hoặc giảm Thời gian tiết kiệm ánh sáng ban ngày, ví dụ.
Đối với các cuộc hẹn, lưu trữ a LocalDateTime
và a ZoneId
, được giữ riêng. Sau đó, khi tạo lịch biểu, nhanh chóng xác định thời điểm bằng cách gọi LocalDateTime::atZone( ZoneId )
để tạo ZonedDateTime
đối tượng.
ZonedDateTime zdt = ldt.atZone( z ) ; // Given a date, a time-of-day, and a time zone, determine a moment, a point on the timeline.
Nếu cần, bạn có thể điều chỉnh theo UTC. Trích xuất một Instant
từ ZonedDateTime
.
Instant instant = zdt.toInstant() ; // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.
Vùng không xác định
Một số người có thể sử dụng LocalDateTime
trong trường hợp không xác định được múi giờ hoặc thời gian.
Tôi coi trường hợp này không phù hợp và không khôn ngoan. Nếu một vùng hoặc phần bù được dự định nhưng không xác định, bạn có dữ liệu xấu. Điều đó sẽ giống như lưu trữ giá của một sản phẩm mà không biết loại tiền dự định. Không phải là một ý tưởng tốt.
Tất cả các loại thời gian
Để đầy đủ, đây là bảng gồm tất cả các loại thời gian ngày có thể, cả hiện đại và di sản trong Java, cũng như các loại được xác định bởi tiêu chuẩn SQL. Điều này có thể giúp đặt Instant
& LocalDateTime
các lớp trong bối cảnh lớn hơn.
Lưu ý các lựa chọn kỳ lạ do nhóm Java đưa ra khi thiết kế JDBC 4.2. Họ đã chọn hỗ trợ tất cả các thời gian java.time ngoại trừ hai lớp được sử dụng phổ biến nhất: Instant
& ZonedDateTime
.
Nhưng không phải lo lắng. Chúng ta có thể dễ dàng chuyển đổi qua lại.
Chuyển đổi Instant
.
// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;
Chuyển đổi ZonedDateTime
.
// Storing
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject( … , odt ) ;
// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZone( z ) ;
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
.
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.
Để tìm hiểu thêm, xem Hướng dẫn Oracle . 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 .
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 bạn. 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.
Nơi để có được các lớp java.time?
Các ThreeTen-Extra dự án mở rộng 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 các bổ sung có thể trong tương lai cho java.time. Bạn có thể tìm thấy một số các lớp học hữu ích ở đây chẳng hạn như Interval
, YearWeek
, YearQuarter
, và nhiều hơn nữa .