Sự khác biệt giữa Instant và LocalDateTime là gì?


256

Tôi biết điều đó:

  • Tức thì là một biểu diễn dấu thời gian "kỹ thuật" (nano giây) cho điện toán.
  • LocalDateTime là đại diện ngày / đồng hồ bao gồm cả múi giờ cho con người.

Cuối cùng, IMO cả hai có thể được coi là loại cho hầu hết các trường hợp sử dụng ứng dụng. Ví dụ: Hiện tại tôi đang chạy một công việc hàng loạt trong đó tôi cần tính toán lần chạy tiếp theo dựa trên ngày và tôi đang vật lộn để tìm ra ưu / nhược điểm giữa hai loại này (ngoài lợi thế chính xác nano giây của phần tức thời và phần múi giờ của LocalDateTime).

Bạn có thể đặt tên cho một số ví dụ ứng dụng, trong đó chỉ nên sử dụng Instant hoặc LocalDateTime không?

Chỉnh sửa: Coi chừng tài liệu đọc sai cho LocalDateTime về độ chính xác và múi giờ


Instant là cơ bản hơn, gói tiêu chuẩn dài cho UTC. Đối với một cron như đợt không phải là một sự lựa chọn hợp lý.
Eggen

37
Định nghĩa không chính xác . LocalDateTimekhông không có một múi giờ!
Basil Bourque

Câu trả lời:


831

Bảng của tất cả các loại thời gian trong Java, cả hiện đại và di sản

tl; dr

InstantLocalDateTime 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 LocalDateTimekhô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

nhập mô tả hình ảnh ở đây

Một Instantlà 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

nhập mô tả hình ảnh ở đây

Lớp OffsetDateTimehọ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

nhập mô tả hình ảnh ở đây

Các ZoneOffsetlớ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 ZoneOffsetchỉ 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

nhập mô tả hình ảnh ở đây

Một múi giờ được đại diện bởi các ZoneIdlớ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/Casablancahoặc Pacific/Auckland. Không bao giờ sử dụng chữ viết tắt 2-4 chữ cái như ESThoặc ISTchú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

nhập mô tả hình ảnh ở đây

Hãy nghĩ về ZonedDateTimekhái niệm như một Instantvớ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 ZonedDateTimelớ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

Sơ đồ chỉ hiển thị lịch cho <code> LocalDate </ code>.

Sơ đồ chỉ hiển thị đồng hồ cho <code> LocalTime </ code>.

Sơ đồ hiển thị lịch cộng với đồng hồ cho <code> LocalDateTime </ code>.

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 InstantZonedDateTime 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 ở SeattleAuckland .

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 LocalDateTimevà 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 Instanttừ 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 LocalDateTimetrong 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& LocalDateTimecác lớp trong bối cảnh lớn hơn.

Bảng của tất cả các loại thời gian ngày trong Java (cả hiện đại & di sản) cũng như tiêu chuẩn SQL.

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?

  • Java SE 8 , Java SE 9 , Java SE 10 và mới hơn
    • Được xây dựng trong.
    • Một phần của API Java tiêu chuẩn với việc triển khai đi kèm.
    • Java 9 thêm một số tính năng nhỏ và sửa lỗi.
  • Java SE 6 Java SE 7
    • Phần lớn chức năng java.time được chuyển ngược lại sang Java 6 & 7 trong ThreeTen-Backport .
  • Android
    • Các phiên bản sau của triển khai gói Android của các lớp java.time.
    • Đối với Android trước đó (<26), các ThreeTenABP dự án thích nghi ThreeTen-backport (nêu trên). Xem Cách sử dụng ThreeTenABP .

Bảng mà thư viện java.time sẽ sử dụng với phiên bản Java hoặc Android nào

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 .


40
Câu trả lời chính xác. Tôi nghĩ rằng một số nhầm lẫn (ít nhất là của tôi) đến từ việc Localđặt tên. Trực giác của tôi về các Localphương tiện liên quan đến nơi tôi VÀ khi tôi (?!), Điều đó khiến tôi tin rằng nó thực sự sẽ là những gì a ZonedDateTime.
mkobit

4
Có nó là khó hiểu. Đó là lý do tại sao java.time đã khéo léo thêm từ 'Được khoanh vùng' vào DateTimetên lớp được sử dụng bởi người tiền nhiệm Joda-Time (sản xuất ZonedDateTime), để nhấn mạnh sự khác biệt từ các lớp "Địa phương". Hãy nghĩ về cái tên "Địa phương" là viết tắt của "cần phải được áp dụng cho một số địa phương cụ thể".
Basil Bourque

2
Tiền tố với từ Localnày cũng có thể là một cách để phân biệt với gói java.util, mặc dù bằng cách nào đó tôi cảm thấy có thể có một lựa chọn từ tốt hơn.
vphilipnyc

2
@simonh Ngược lại khi nhân viên mới ký giấy thuê mướn xác định quyền lợi của họ bao gồm bảo hiểm nhân thọ và sau đó thuê mới bước ra ngoài để uống cà phê chỉ để bị xe tải đâm và giết, sẽ có nhiều người như vậy là người quản lý nhân sự, đại lý bảo hiểm và luật sư, những người sẽ muốn biết thời điểm chính xác khi việc làm mới đó có hiệu lực.
Basil Bourque

2
@simonh Có, có những trường hợp thời gian ngày "cục bộ" là phù hợp. Bên cạnh những điều được đề cập trong Câu trả lời của tôi, một trường hợp phổ biến khác trong kinh doanh là các cuộc hẹn sẽ được thực hiện hơn một vài tháng trong tương lai, đủ xa để các chính trị gia có thể thay đổi quy tắc múi giờ, thường là ít báo trước. Các chính trị gia thường xuyên thực hiện những thay đổi này như thay đổi ngày khi bật / tắt Giờ tiết kiệm ánh sáng ban ngày (DST) hoặc duy trì bật / tắt DST vĩnh viễn.
Basil Bourque

20

Một sự khác biệt chính là Localmột phần của LocalDateTime. Nếu bạn sống ở Đức và tạo một LocalDateTimecá thể và một người khác sống ở Hoa Kỳ và tạo một cá thể khác vào cùng một thời điểm (miễn là đồng hồ được đặt đúng cách) - giá trị của các đối tượng đó sẽ thực sự khác nhau. Điều này không áp dụng cho Instant, được tính độc lập với múi giờ.

LocalDateTimelưu trữ ngày và giờ không có múi giờ, nhưng giá trị ban đầu của nó phụ thuộc vào múi giờ. InstantKhông phải.

Hơn nữa, LocalDateTimecung cấp các phương thức để thao tác các thành phần ngày như ngày, giờ, tháng. An Instantkhông có.

ngoài lợi thế chính xác về nano giây của Instant và phần múi giờ của LocalDateTime

Cả hai lớp có độ chính xác như nhau. LocalDateTimekhông lưu trữ múi giờ. Đọc kỹ javadocs, bởi vì bạn có thể phạm sai lầm lớn với các giả định không hợp lệ như vậy: InstantLocalDateTime .


xin lỗi vì đã đọc sai một phần về vùng + độ chính xác. Xin lỗi vì đã lặp lại từ bài đăng trên: Xem xét một ứng dụng múi giờ duy nhất, trong đó các trường hợp sử dụng bạn sẽ ưu tiên LocalDateTime hoặc ngược lại?
manuel aldana

1
Tôi sẽ dùng LocalDateTime bất cứ khi nào tôi cần ngày và / hoặc lần. Trong giờ, phút, hoặc như vậy. Tôi sẽ sử dụng Instant để đo thời gian thực hiện, ví dụ, hoặc lưu trữ một trường nội bộ của sth xảy ra sau đó. Tính toán lần chạy tiếp theo, như trong trường hợp của bạn? LocalDateTime có vẻ phù hợp, nhưng đó là một ý kiến. Như bạn đã nêu, cả hai có thể được sử dụng.
Dariusz

Bạn có thể giải thích nhiều hơn về LocalDateTime stores date and time without timezone, but it's initial value is timezone dependent? giá trị ban đầu là gì và nó phụ thuộc múi giờ như thế nào? Cảm ơn.
Tối đa

12

Bạn đã sai về LocalDateTime: nó không lưu trữ bất kỳ thông tin múi giờ nào và nó có độ chính xác nano giây. Trích dẫn Javadoc (nhấn mạnh của tôi):

Thời gian không có múi giờ trong hệ thống lịch ISO-8601 , chẳng hạn như 2007-12-03T10: 15: 30.

LocalDateTime là một đối tượng ngày giờ bất biến đại diện cho thời gian ngày, thường được xem là năm-tháng-ngày-giờ-giây-giây. Các trường ngày và thời gian khác, chẳng hạn như ngày trong năm, ngày trong tuần và tuần, cũng có thể được truy cập. Thời gian được biểu diễn cho độ chính xác nano giây . Ví dụ: giá trị "ngày 2 tháng 10 năm 2007 lúc 13: 45.30.123456789" có thể được lưu trữ trong LocalDateTime.

Sự khác biệt giữa hai là Instantđại diện cho một phần bù từ Kỷ nguyên (01-01-1970) và, như vậy, đại diện cho một tức thời cụ thể trên dòng thời gian. Hai Instantvật thể được tạo ra tại cùng một thời điểm ở hai nơi khác nhau trên Trái đất sẽ có cùng một giá trị.


Xem xét một ứng dụng múi giờ duy nhất, trong đó các trường hợp sử dụng bạn sẽ ưu tiên LocalDateTime hoặc ngược lại?
manuel aldana

3
@manuelaldana Đó là vấn đề của hương vị. Tôi thích LocalDateTime cho mọi thứ liên quan đến người dùng (sinh nhật ...) và Instant cho mọi thứ liên quan đến máy (thời gian thực hiện ...).
Tunaki

2
@manuelaldana Một ứng dụng múi giờ duy nhất rất hiếm nếu không tồn tại. Bạn có thể thoát khỏi việc bỏ qua các múi giờ cho một ứng dụng nhỏ mà bạn đã đánh cắp cho câu lạc bộ âm nhạc Baroque địa phương của bạn. Nhưng ngay khi bạn cần đăng một sự kiện cho những người đi du lịch (và xuyên thời gian), họ sẽ muốn dữ liệu đó được gắn với múi giờ để ứng dụng lịch của họ có thể điều chỉnh khi cần. Tôi khuyên bạn nên học cách làm việc với các múi giờ chính xác trong tất cả các ứng dụng của mình.
Basil Bourque

@Tunaki Việc bạn sử dụng từ 'offset' trong đoạn cuối gây mất tập trung. Từ đó có một ý nghĩa nhất định trong công việc thời gian, vì vậy nó được sử dụng ở đây trong bối cảnh này có thể không có ích.
Basil Bourque

0

Instant tương ứng với thời gian trên kinh tuyến gốc (Greenwich).

Trong khi đó LocalDateTimeliên quan đến cài đặt múi giờ của hệ điều hành và

không thể biểu thị tức thời mà không có thông tin bổ sung như phần bù hoặc múi giờ.


2
Instant được dựa trên UTC chứ không phải GMT.
Torsten Ojaperv
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.