tl; dr
LocalDate // Represents an entire day, without time-of-day and without time zone.
.now( // Capture the current date.
ZoneId.of( "Asia/Tokyo" ) // Returns a `ZoneId` object.
) // Returns a `LocalDate` object.
.atStartOfDay( // Determines the first moment of the day as seen on that date in that time zone. Not all days start at 00:00!
ZoneId.of( "Asia/Tokyo" )
) // Returns a `ZonedDateTime` object.
Bắt đầu ngày mới
Nhận toàn bộ thời lượng của ngày hôm nay như đã thấy trong một múi giờ.
Sử dụng phương pháp Nửa mở, trong đó phần đầu bao gồm trong khi phần cuối là độc quyền . Cách tiếp cận này giải quyết lỗ hổng trong mã của bạn không tính đến giây cuối cùng trong ngày.
ZoneId zoneId = ZoneId.of( "Africa/Tunis" ) ;
LocalDate today = LocalDate.now( zoneId ) ;
ZonedDateTime zdtStart = today.atStartOfDay( zoneId ) ;
ZonedDateTime zdtStop = today.plusDays( 1 ).atStartOfDay( zoneId ) ;
zdtStart.toString () = 2020-01-30T00: 00 + 01: 00 [Châu Phi / Tunis]
zdtStop.toString () = 2020-01-31T00: 00 + 01: 00 [Châu Phi / Tunis]
Xem những khoảnh khắc tương tự trong UTC.
Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;
start.toString () = 2020-01-29T23: 00: 00Z
stop.toString () = 2020-01-30T23: 00: 00Z
Nếu bạn muốn cả ngày của một ngày như được thấy ở UTC thay vì theo múi giờ, hãy sử dụng OffsetDateTime
.
LocalDate today = LocalDate.now( ZoneOffset.UTC ) ;
OffsetDateTime odtStart = today.atTime( OffsetTime.MIN ) ;
OffsetDateTime odtStop = today.plusDays( 1 ).atTime( OffsetTime.MIN ) ;
odtStart.toString () = 2020-01-30T00: 00 + 18: 00
odtStop.toString () = 2020-01-31T00: 00 + 18: 00
Những OffsetDateTime
đối tượng này sẽ ở UTC, nhưng bạn có thể gọi toInstant
nếu bạn cần những đối tượng như vậy luôn ở UTC theo định nghĩa.
Instant start = odtStart.toInstant() ;
Instant stop = odtStop.toInstant() ;
start.toString () = 2020-01-29T06: 00: 00Z
stop.toString () = 2020-01-30T06: 00: 00Z
Mẹo: Bạn có thể quan tâm đến việc thêm thư viện ThreeTen-Extra vào dự án của mình để sử dụng Interval
lớp của nó để đại diện cho cặp Instant
đối tượng này. Đây lớp Mời các phương pháp hữu ích để so sánh như abuts
, overlaps
, contains
, và nhiều hơn nữa.
Interval interval = Interval.of( start , stop ) ;
khoảng thời gian.toString () = 2020-01-29T06: 00: 00Z / 2020-01-30T06: 00: 00Z
Mở một nửa
Câu trả lời của mprivat là chính xác. Quan điểm của anh ấy là đừng cố gắng đạt được kết quả của một ngày, mà hãy so sánh với "trước khi bắt đầu ngày hôm sau". Ý tưởng của ông được biết đến là cách tiếp cận "Nửa mở" trong đó một khoảng thời gian có phần đầu bao hàm trong khi phần kết là độc quyền .
- Khung ngày-giờ hiện tại của Java (java.util.Date/Calendar và Joda-Time ) đều sử dụng mili giây so với thời đại . Nhưng trong Java 8, các lớp JSR 310 java.time. * Mới sử dụng độ phân giải nano giây. Bất kỳ mã nào bạn đã viết dựa trên việc buộc đếm mili giây của khoảnh khắc cuối cùng trong ngày sẽ không chính xác nếu được chuyển sang các lớp mới.
- So sánh dữ liệu từ các nguồn khác sẽ bị lỗi nếu chúng sử dụng các độ phân giải khác. Ví dụ: thư viện Unix thường sử dụng toàn bộ giây và cơ sở dữ liệu như Postgres phân giải ngày-thời gian thành micro giây.
- Một số thay đổi về Giờ tiết kiệm ánh sáng ban ngày xảy ra vào nửa đêm, điều này có thể gây nhầm lẫn thêm cho mọi thứ.
Joda thời gian 2,3 Mời một phương pháp cho mục đích này rất, để có được khoảnh khắc đầu tiên trong ngày: withTimeAtStartOfDay()
. Tương tự trong java.time , LocalDate::atStartOfDay
.
Tìm kiếm StackOverflow cho "joda nửa mở" để xem thêm các cuộc thảo luận và ví dụ.
Hãy xem bài đăng này, Khoảng thời gian và các phạm vi khác nên để ngỏ , bởi Bill Schneider.
Tránh các lớp ngày-giờ kế thừa
Các lớp java.util.Date và .Calendar nổi tiếng là rắc rối. Tránh chúng.
Sử dụng các lớp java.time . Khung java.time là sự kế thừa chính thức của thư viện Joda-Time rất thành công .
java.time
Khuôn khổ java.time được tích hợp trong Java 8 trở lên. Được chuyển ngược sang Java 6 & 7 trong dự án ThreeTen-Backport , được điều chỉnh thêm cho Android trong dự án ThreeTenABP .
An Instant
là một thời điểm trên dòng thời gian tính theo giờ UTC với độ phân giải là nano giây .
Instant instant = Instant.now();
Áp dụng múi giờ để lấy giờ trên đồng hồ treo tường cho một số địa phương.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Để có được khoảnh khắc đầu tiên trong ngày, hãy xem qua LocalDate
lớp học và atStartOfDay
phương pháp của nó .
ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
Sử dụng phương pháp Half-Open, có được khoảnh khắc đầu tiên của ngày hôm sau.
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );
Hiện tại, khuôn khổ java.time thiếu một Interval
lớp như được mô tả bên dưới cho Joda-Time. Tuy nhiên, dự án ThreeTen-Extra mở rộng java.time với các lớp bổ sung. Dự án này là cơ sở chứng minh cho những bổ sung có thể có trong tương lai cho java.time. Trong số các lớp của nó là Interval
. Xây dựng một Interval
bằng cách truyền một cặp Instant
đối tượng. Chúng ta có thể trích xuất một Instant
từ các ZonedDateTime
đối tượng của mình.
Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );
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?
Joda-Time
CẬP NHẬT: Dự án Joda-Time hiện đang ở chế độ bảo trì và khuyên bạn nên chuyển sang các lớp java.time . Tôi để phần này nguyên vẹn cho lịch sử.
Joda thời gian có ba lớp học để đại diện cho một khoảng thời gian theo nhiều cách khác nhau: Interval
, Period
, và Duration
. An Interval
có một khởi đầu và kết thúc cụ thể trên dòng thời gian của Vũ trụ. Điều này phù hợp với nhu cầu của chúng tôi để đại diện cho "một ngày".
Chúng tôi gọi phương thức withTimeAtStartOfDay
thay vì đặt thời gian trong ngày thành số không. Do Giờ tiết kiệm ánh sáng ban ngày và những điều bất thường khác, khoảnh khắc đầu tiên trong ngày có thể không như vậy 00:00:00
.
Mã ví dụ sử dụng Joda-Time 2.3.
DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( timeZone );
DateTime todayStart = now.withTimeAtStartOfDay();
DateTime tomorrowStart = now.plusDays( 1 ).withTimeAtStartOfDay();
Interval today = new Interval( todayStart, tomorrowStart );
Nếu phải, bạn có thể chuyển đổi sang java.util.Date.
java.util.Date date = todayStart.toDate();