คำตอบอื่น ๆ ที่ถูกต้องโดยเฉพาะอย่างยิ่งคำตอบ java.time โดย arganzheng ดังที่บางคนกล่าวถึงคุณควรหลีกเลี่ยงคลาส java.util.Date/.Calendar เก่าเนื่องจากคลาสเหล่านี้ได้รับการออกแบบไม่ดีสับสนและลำบาก พวกเขาถูกแทนที่ด้วยคลาส java.time
ผมขอเพิ่มบันทึกเกี่ยวกับกลยุทธ์ทั่วจัดการเที่ยงคืนและช่วงเวลา
ครึ่งเปิด
ในงานวันเวลาช่วงเวลามักถูกกำหนดโดยใช้วิธีการ "เปิดครึ่ง" ในวิธีการนี้การเริ่มต้นรวมในขณะที่การสิ้นสุดนั้นไม่เหมือนกัน วิธีนี้จะช่วยแก้ปัญหาและหากใช้อย่างสม่ำเสมอจะทำให้การจัดการวันที่และเวลาของคุณง่ายขึ้น
การแก้ไขปัญหาหนึ่งคือการกำหนดจุดสิ้นสุดของวัน เป็นนาทีสุดท้ายของวัน23:59:59.999
( มิลลิวินาที ) หรือไม่ บางทีในคลาส java.util.Date (จาก Java ตัวเก่าที่สุด, ลำบาก - หลีกเลี่ยงคลาสนี้!) และในไลบรารีJoda-Time ที่ประสบความสำเร็จอย่างสูง แต่ในซอฟต์แวร์อื่น ๆ เช่นฐานข้อมูลเช่น Postgres ช่วงเวลาสุดท้ายจะเป็น23:59:59.999999
( ไมโครวินาที ) แต่ในซอฟต์แวร์อื่นเช่นjava.time framework (สร้างขึ้นใน Java 8 และใหม่กว่า, สืบทอดมาจาก Joda-Time) และในฐานข้อมูลบางอย่างเช่นฐานข้อมูลH2 , วินาทีสุดท้ายอาจเป็น23:59.59.999999999
( นาโนวินาที ) แทนที่จะแยกผมคิดในแง่ของช่วงเวลาแรกเท่านั้นไม่ใช่ช่วงเวลาสุดท้าย
ใน Half-Open วันทำงานตั้งแต่วินาทีแรกของหนึ่งวันและขึ้นไป แต่ไม่รวมช่วงเวลาแรกของวันถัดไป ดังนั้นแทนที่จะคิดแบบนี้
…จากวันนี้เวลา 00:00 น. (เที่ยงคืนของเช้านี้) ถึง 12:00 น. (เที่ยงคืนคืนนี้)
…คิดแบบนี้…
ตั้งแต่วินาทีแรกของวันนี้จนถึง แต่ไม่รวมช่วงเวลาแรกของวันพรุ่งนี้:
(> = 00:00:00.0
วันนี้และ < 00:00:00.0
วันพรุ่งนี้)
ในการทำงานของฐานข้อมูลวิธีนี้หมายถึงการไม่ใช้ตัวBETWEEN
ดำเนินการใน SQL
เริ่มวันใหม่
นอกจากนี้ช่วงเวลาแรกของวันนั้นไม่ใช่เวลาของวัน00:00:00.0
เสมอไป เวลาออมแสง (DST)ในบางโซนเวลาและความผิดปกติอื่น ๆ อาจหมายถึงการเริ่มต้นวันใหม่
ดังนั้นให้java.timeLocalDate::atStartOfDay( ZoneId )
เรียนทำผลงานของการกำหนดจุดเริ่มต้นของวันที่มีการเรียกร้องให้ ดังนั้นเราต้องอ้อมผ่านLocalDate
และกลับไปZonedDateTime
อย่างที่คุณเห็นในโค้ดตัวอย่างนี้
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now( zoneId );
ZonedDateTime todayStart = now.toLocalDate().atStartOfDay( zoneId );
ZonedDateTime tomorrowStart = todayStart.plusDays( 1 );
ZoneId
หมายเหตุการผ่านไปของจำเป็น หากละเว้นเขตเวลาเริ่มต้นปัจจุบันของ JVM ของคุณจะถูกนำไปใช้โดยปริยาย ดีกว่าที่จะชัดเจน
เขตเวลาเป็นสิ่งสำคัญสำหรับการทำงานตามวันเวลา คำถามและคำตอบอื่น ๆ อาจมีข้อบกพร่องเนื่องจากไม่มีการจัดการกับโซนเวลา
แปลง
หากคุณต้องใช้ java.util.Date หรือ .Calendar ให้ค้นหาวิธีการแปลงใหม่ที่เพิ่มในคลาสเก่าเหล่านั้น
java.util.Date utilDate = java.util.Date.from( todayStart.toInstant() );
java.util.GregorianCalendar gregCal = java.util.GregorianCalendar.from( todayStart );
ช่วงเวลา
โดยวิธีการถ้าคุณทำงานมากกับช่วงเวลาลองดูที่:
Duration
Period
Interval
พบInterval
คลาสในโครงการThreeTen-Extraซึ่งเป็นส่วนขยายของเฟรมเวิร์ก java.time โครงการนี้เป็นพื้นฐานที่พิสูจน์ได้สำหรับการเพิ่มเติมในอนาคตไปยัง java.time
Interval todayMontreal = Interval.of( todayStart.toInstant() , tomorrowStart.toInstant() );
เกี่ยวกับjava.time
java.timeกรอบถูกสร้างขึ้นใน Java 8 และต่อมา ชั้นเรียนเหล่านี้แย่งลำบากเก่ามรดกเรียนวันที่เวลาเช่นjava.util.Date
, และCalendar
SimpleDateFormat
Joda เวลาโครงการขณะนี้อยู่ในโหมดการบำรุงรักษาให้คำแนะนำแก่การโยกย้ายไปยังjava.timeชั้นเรียน
ต้องการเรียนรู้เพิ่มเติมโปรดดูที่ออราเคิลกวดวิชา และค้นหา Stack Overflow สำหรับตัวอย่างและคำอธิบายมากมาย สเปกJSR 310
คุณสามารถแลกเปลี่ยนวัตถุjava.timeโดยตรงกับฐานข้อมูลของคุณ ใช้ไดรเวอร์ JDBC ที่สอดคล้องกับJDBC 4.2หรือใหม่กว่า ไม่จำเป็นต้องใช้สตริงไม่จำเป็นต้องมีjava.sql.*
คลาส
จะรับคลาส java.time ได้ที่ไหน?
โครงการThreeTen-Extraขยาย java.time ด้วยคลาสเพิ่มเติม โครงการนี้เป็นพื้นฐานที่พิสูจน์ได้สำหรับการเพิ่มเติมในอนาคตไปยัง java.time คุณอาจพบว่าการเรียนที่มีประโยชน์บางอย่างที่นี่เช่นInterval
, YearWeek
, YearQuarter
และอื่น ๆ อีกมากมาย