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.
เริ่มต้นวันใหม่
รับความยาวเต็มของวันนี้ตามที่เห็นในเขตเวลา
โดยใช้วิธีการครึ่งเปิดที่จุดเริ่มต้นคือรวมในขณะที่ตอนจบเป็นพิเศษ วิธีนี้ช่วยแก้ข้อบกพร่องในรหัสของคุณที่ไม่สามารถอธิบายได้ในวินาทีสุดท้ายของวัน
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 [แอฟริกา / ตูนิส]
zdtStop.toString () = 2020-01-31T00: 00 + 01: 00 [แอฟริกา / ตูนิส]
ดูช่วงเวลาเดียวกันใน UTC
Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;
start.toString () = 2020-01-29T23: 00: 00Z
stop.toString () = 2020-01-30T23: 00: 00Z
หากคุณต้องการตลอดทั้งวันของวันที่เท่าที่เห็นใน UTC 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 น
อOffsetDateTime
อบเจ็กต์เหล่านี้จะอยู่ใน UTC อยู่แล้ว แต่คุณสามารถโทรได้toInstant
หากคุณต้องการอ็อบเจกต์ดังกล่าวซึ่งจะอยู่ใน UTC เสมอตามคำจำกัดความ
Instant start = odtStart.toInstant() ;
Instant stop = odtStop.toInstant() ;
start.toString () = 2020-01-29T06: 00: 00Z
stop.toString () = 2020-01-30T06: 00: 00Z
เคล็ดลับ: คุณอาจสนใจที่จะเพิ่มไลบรารี ThreeTen-Extraลงในโปรเจ็กต์ของคุณเพื่อใช้Interval
คลาสแทนInstant
อ็อบเจ็กต์คู่นี้ ชั้นนี้จะเสนอวิธีการที่เป็นประโยชน์สำหรับการเปรียบเทียบเช่นabuts
, overlaps
, contains
และอื่น ๆ
Interval interval = Interval.of( start , stop ) ;
interval.toString () = 2020-01-29T06: 00: 00Z / 2020-01-30T06: 00: 00Z
ครึ่งเปิด
คำตอบโดย mprivatถูกต้อง ประเด็นของเขาคืออย่าพยายามที่จะบรรลุจุดจบของวัน แต่ให้เปรียบเทียบกับ "ก่อนเริ่มวันถัดไป" ความคิดของเขาเป็นที่รู้จักกันว่า "ครึ่งเปิด" วิธีการที่ช่วงเวลาที่มีจุดเริ่มต้นที่ได้รวมในขณะที่ตอนจบเป็นพิเศษ
- ปัจจุบันกรอบวันเวลาของ Java (java.util.Date/Calendar และJoda-Time ) การใช้งานทั้งมิลลิวินาทีจากยุค แต่ใน Java 8 คลาส JSR 310 java.time. * ใหม่ใช้ความละเอียดระดับนาโนวินาที รหัสใด ๆ ที่คุณเขียนโดยอาศัยการบังคับให้นับมิลลิวินาทีของช่วงเวลาสุดท้ายของวันจะไม่ถูกต้องหากเปลี่ยนไปใช้คลาสใหม่
- การเปรียบเทียบข้อมูลจากแหล่งอื่นจะผิดพลาดหากใช้ความละเอียดอื่น ตัวอย่างเช่นโดยทั่วไปไลบรารี Unix จะใช้เวลาทั้งวินาทีและฐานข้อมูลเช่นPostgres จะแก้ไขวันที่ - เวลาเป็นไมโครวินาที
- การเปลี่ยนแปลงเวลาออมแสงบางอย่างเกิดขึ้นในช่วงเที่ยงคืนซึ่งอาจทำให้สิ่งต่างๆสับสน
Joda เวลา 2.3 withTimeAtStartOfDay()
ข้อเสนอวิธีการเพื่อวัตถุประสงค์อย่างนี้เพื่อให้ได้ช่วงแรกของวันที่: ในทำนองเดียวกันใน LocalDate::atStartOfDay
java.time,
ค้นหา StackOverflow สำหรับ "joda half-open"เพื่อดูการสนทนาและตัวอย่างเพิ่มเติม
ดูโพสต์นี้ช่วงเวลาและช่วงอื่น ๆ ควรเปิดครึ่งหนึ่งโดย Bill Schneider
หลีกเลี่ยงคลาสวันเวลาเดิม
คลาส java.util.Date และ. ปฏิทินเป็นปัญหาที่น่าอับอาย หลีกเลี่ยงพวกเขา
ใช้คลาสjava.time java.timeกรอบเป็นผู้สืบทอดอย่างเป็นทางการของความสำเร็จอย่างสูงJoda เวลาห้องสมุด
java.time
กรอบ java.time ถูกสร้างขึ้นใน Java 8 และใหม่กว่า แบ็คพอร์ตเป็น Java 6 & 7 ในโครงการThreeTen-Backportซึ่งปรับให้เข้ากับ Android ในโครงการThreeTenABP
Instant
เป็นช่วงเวลาบนไทม์ไลน์ในส่วนUTCมีความละเอียดของนาโนวินาที
Instant instant = Instant.now();
ใช้เขตเวลาเพื่อรับเวลานาฬิกาแขวนสำหรับบางท้องที่
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
เพื่อให้ได้ช่วงเวลาแรกของวันให้ผ่านLocalDate
ชั้นเรียนและatStartOfDay
วิธีการของมัน
ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
ใช้วิธี Half-Open รับช่วงเวลาแรกของวันถัดไป
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );
ขณะนี้กรอบ java.time ไม่มีInterval
คลาสดังที่อธิบายไว้ด้านล่างสำหรับ Joda-Time อย่างไรก็ตามโครงการThreeTen-Extraขยาย java.time ด้วยคลาสเพิ่มเติม โปรเจ็กต์นี้เป็นจุดพิสูจน์สำหรับการเพิ่ม java.time ในอนาคต Interval
ในบรรดาชั้นเรียนของมันคือ สร้างInterval
โดยผ่านคู่ของInstant
วัตถุ เราสามารถดึง an Instant
จากZonedDateTime
วัตถุของเรา
Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );
เกี่ยวกับjava.time
java.timeกรอบถูกสร้างขึ้นใน Java 8 และต่อมา ชั้นเรียนเหล่านี้แย่งลำบากเก่ามรดกเรียนวันที่เวลาเช่นjava.util.Date
, และCalendar
SimpleDateFormat
ต้องการเรียนรู้เพิ่มเติมโปรดดูที่ออราเคิลกวดวิชา และค้นหา Stack Overflow สำหรับตัวอย่างและคำอธิบายมากมาย สเปกJSR 310
โครงการJoda-Timeขณะนี้อยู่ในโหมดการบำรุงรักษาแนะนำการโยกย้ายไปยังคลาสjava.time
คุณสามารถแลกเปลี่ยนวัตถุjava.timeโดยตรงกับฐานข้อมูลของคุณ ใช้ไดรเวอร์ JDBC ที่สอดคล้องกับJDBC 4.2หรือใหม่กว่า ไม่จำเป็นต้องมีสตริงไม่จำเป็นต้องมีjava.sql.*
คลาส Hibernate 5 & JPA 2.2 สนับสนุนjava.time
จะหาคลาส java.time ได้ที่ไหน?
Joda เวลา
อัปเดต: ขณะนี้โปรเจ็กต์ Joda-Time อยู่ในโหมดการบำรุงรักษาและแนะนำการย้ายข้อมูลไปยังคลาสjava.time ฉันจะปล่อยให้ส่วนนี้เหมือนเดิมสำหรับประวัติศาสตร์
Joda เวลามีสามชั้นเรียนเพื่อเป็นตัวแทนของช่วงเวลาในรูปแบบต่างๆ: Interval
, และPeriod
มีระดับเริ่มต้นและสิ้นสุดในระยะเวลาของจักรวาล สิ่งนี้เหมาะกับความต้องการของเราที่จะเป็นตัวแทนของ "วัน"Duration
Interval
เราเรียกวิธีนี้withTimeAtStartOfDay
แทนที่จะตั้งเวลาของวันเป็นศูนย์ เนื่องจากเวลาออมแสงและความผิดปกติอื่น ๆ ในช่วงแรกของวันอาจไม่เป็น00:00:00
เช่นนั้น
ตัวอย่างรหัสโดยใช้ 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 );
หากคุณต้องการคุณสามารถแปลงเป็น java.util.Date
java.util.Date date = todayStart.toDate();