Java Date cut off ข้อมูลเวลา


121

ฉันมีวัตถุ Java Date ที่มีข้อมูลวันที่และเวลา ฉันต้องการเขียนวิธีการที่จะตัดข้อมูลเวลาตัดทอนชั่วโมงนาที - วินาทีดังนั้นฉันจึงเหลือวันที่เท่านั้น

ตัวอย่างการป้อนข้อมูล:

2008-01-01 13:15:00

ผลลัพธ์ที่คาดหวัง:

2008-01-01 00:00:00

คุณมีเคล็ดลับหรือไม่? ฉันลองทำสิ่งนี้:

(timestamp / (24 * 60 * 60 * 1000)) * (24 * 60 * 60 * 1000)

แต่ฉันพบปัญหาเกี่ยวกับเขตเวลา

คำตอบ:


178

แนะนำวิธีการทำการจัดการวันที่ / เวลาคือการใช้Calendarวัตถุ:

Calendar cal = Calendar.getInstance(); // locale-specific
cal.setTime(dateObject);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
long time = cal.getTimeInMillis();

2
@cletus เป็นไปได้ไหมที่จะลบเวลาออกจากวัตถุ Date ฉันต้องการวันที่บริสุทธิ์เช่น 2008-01-01 ไม่มีส่วนเวลา
เปรม

2
ฉันจะไม่พูดว่า java.util.Calendar แนะนำ Sun / Oracle แทนที่คลาสนั้นใน Java 8 ด้วยแพ็คเกจ java.time ใหม่ ใช้อย่างใดอย่างหนึ่งหรือ Joda-Time
Basil Bourque

3
ไม่แนะนำให้ใช้ปฏิทินอีกต่อไป ดูstackoverflow.com/a/28868089/40064หากคุณใช้ Java 8
Wim Deblauwe

2
FYI คลาสวันที่และเวลาเก่าที่มีปัญหาเช่นjava.util.Calendarตอนนี้เป็นแบบดั้งเดิมแทนที่ด้วยคลาสjava.time ดูการสอนโดยออราเคิล
Basil Bourque

149

คุณได้ดูวิธีการตัดทอนDateUtilsใน Apache Commons Lang หรือไม่?

Date truncatedDate = DateUtils.truncate(new Date(), Calendar.DATE);

จะลบองค์ประกอบเวลา


9
อัปเดตลิงค์อีกครั้ง (มาที่ Apache! ออกจาก movin your docs around!)
Ogre Psalm33

6
ข้อลบของแนวทางนี้ที่เขตเวลาในการดำเนินการตัดทอนจะเป็นเขตเวลาของพีซีในพื้นที่เสมอ ดังนั้นหากคุณทำงานกับปฏิทินและวันที่ในเขตเวลา UTC หรือในเขตเวลาอื่นที่ไม่ใช่เขตเวลาท้องถิ่นก็อาจตัดทอนวันที่ไม่ได้ตามที่ตั้งใจไว้
Cloud

ตามที่ @Cloud ชี้ให้เห็นความจริงที่ว่าฉันไม่เห็นอินสแตนซ์ปฏิทินที่นี่ (ไม่สามารถควบคุมได้) ทำให้ฉันกังวลเล็กน้อย :)
Jaroslav Záruba

วิธีนี้ใช้เวลานานอย่างน่าประหลาดใจและมีการแก้ไขข้อบกพร่องอย่างน้อยสองรายการ
Pino

42

คุณดูJodaหรือยัง? มันเป็นมากวิธีที่ง่ายและใช้งานง่ายมากขึ้นในการทำงานร่วมกับวันที่และเวลา ตัวอย่างเช่นคุณสามารถแปลงเล็กน้อยระหว่าง (พูด) LocalDateTimeและLocalDateวัตถุ

เช่น (เพื่อแสดง API)

LocalDate date = new LocalDateTime(milliseconds).toLocalDate()

นอกจากนี้ยังช่วยแก้ปัญหาความปลอดภัยของเธรดด้วยรูปแบบวันที่ / เวลาและขอแนะนำอย่างยิ่งสำหรับการทำงานกับปัญหาวันที่ / เวลาใน Java


12
ฉันเชื่อว่ามันทำได้ ขอแนะนำให้ใช้ไลบรารีที่ดีกว่าการต่อสู้กับคลาส java.util ที่เสีย (ตามหลักฐานจากคำถาม)
Brian Agnew

10
แน่นอนว่ามันเกี่ยวข้องกัน Joda เป็นไลบรารีสำหรับการจัดการวันที่เวลาและปฏิทินใน Java จะเป็นการละทิ้งหน้าที่ที่จะไม่แนะนำ
Joel

1
ปัญหาความปลอดภัยของเธรดนั้นน่าสนใจมากฉันพบว่าโพสต์นี้กำลังค้นคว้าข้อผิดพลาด Oracle / Hibernate "IllegalArgumentException, sun.util.calendar.ZoneInfo.getOffset (ZoneInfo), oracle.jdbc.driver.DateCommonBinder.zoneOffset (OraclePreparedStatement)" สิ่งนี้พูดถึงปัญหาอื่น ๆ ของ Oracle ที่ปรากฏเฉพาะในฟอรัมที่มีภาระงานมากoracle.com/forums/thread.jspa?threadID=325576มันยากมากที่จะสร้างวัตถุที่มีมิลลิวินาทีไม่ถูกต้องในรหัสปกติ สำหรับฉันฉันคิดว่าฉันจะดาวน์คาสต์ในเธรดของฉันโดยใช้ Joda แทนที่จะปล่อยให้ Oracle ใช้สิ่งที่ไม่ใช่ joda ที่น่าสงสัย
Mark Bennett

4
ฉันหวังว่าฉันจะสามารถลดคะแนนทุกคนที่โหวตเรื่องนี้ได้ ใครคือคนเหล่านี้ที่ +1 คำตอบที่ไม่ได้พยายามตอบคำถาม คำตอบโดยใช้ Joda น่าจะดีกว่า แต่นี่ไม่ใช่ ...
Ryan

1
@Ryan ยังไงคำตอบนี้ไม่เกี่ยว? คำถามถูกถามสำหรับวันที่โดยไม่มีเวลาของวัน คำตอบนี้นำเสนอชั้นเรียนที่มีจุดประสงค์เพียงอย่างเดียวคือการแสดงวันที่โดยไม่มีเวลาของวัน
Basil Bourque

35

เพียงแค่อัปเดตอย่างรวดเร็วในแง่ของคลาสjava.time ในตอนนี้ใน Java 8 และใหม่กว่า

LocalDateTimeมีtruncatedToวิธีการที่กล่าวถึงสิ่งที่คุณกำลังพูดถึงได้อย่างมีประสิทธิภาพที่นี่:

LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES)

สิ่งนี้จะแสดงเวลาปัจจุบันลงเป็นนาทีเท่านั้น:

2015-03-05T11:47

คุณอาจใช้ChronoUnit(หรือ a TemporalUnit) ที่เล็กกว่า DAYS เพื่อดำเนินการตัดทอน (เนื่องจากการตัดทอนจะใช้กับส่วนเวลาของ LocalDateTime เท่านั้นไม่ใช่กับส่วนวันที่)


3
คุณสามารถใช้ ChronoUnits ได้ไม่เกิน DAYS หน่วยที่สูงกว่าจะทำให้เกิดข้อยกเว้น
assylias


22

ด้วย Joda คุณสามารถหาวันที่คาดหวังได้อย่างง่ายดาย

ในเวอร์ชัน 2.7 (อาจเป็นเพราะเวอร์ชันก่อนหน้าบางเวอร์ชันที่มากกว่า 2.2) ในฐานะบันทึกของผู้แสดงความคิดเห็นtoDateMidnightได้รับการเลิกใช้งานในความโปรดปรานหรือชื่อที่เหมาะสมwithTimeAtStartOfDay()ทำให้สะดวก

DateTime.now().withTimeAtStartOfDay()

เป็นไปได้

เพิ่มประโยชน์ของวิธีที่ดีกว่า API

ด้วยเวอร์ชันเก่าคุณสามารถทำได้

new DateTime(new Date()).toDateMidnight().toDate()

6
เมธอดและคลาสที่เกี่ยวข้องกับเที่ยงคืนใน Joda-Time เลิกใช้งานแล้ว นักพัฒนาไม่แนะนำให้ใช้ ใช้วิธีwithTimeAtStartOfDayนี้แทน
Basil Bourque

ขอบคุณที่ชี้แจ้ง อัปเดตคำตอบเพื่อพิจารณาสิ่งนี้
h7r

คุณยังสามารถใช้toLocalDateเพื่อรับวัตถุที่ไม่มีส่วนประกอบของเวลาได้อีกด้วย
Charles Wood

FYI ตอนนี้โปรเจ็กต์Joda-Timeอยู่ในโหมดการบำรุงรักษาโดยทีมงานจะแนะนำการย้ายข้อมูลไปยังคลาสjava.time ดูการสอนโดยออราเคิล
Basil Bourque

8

ฉันทำการตัดทอนด้วย java8 API ใหม่ ฉันเผชิญหน้ากับสิ่งแปลก ๆ อย่างหนึ่ง แต่โดยทั่วไปแล้วมันถูกตัดทอน ...

Instant instant = date.toInstant();
instant = instant.truncatedTo(ChronoUnit.DAYS);
date = Date.from(instant);

คีย์เวิร์ด: java.time, Java 8, LocalDateTime.truncatedTo ()
Alexander Taylor

1
คำตอบนี้สร้างเฉพาะวันที่สำหรับบริบทของเขตเวลา UTC
Basil Bourque

6

ใช้ DateUtils จาก Apache โดยมีการตัดทอนดังนี้:

DateUtils.truncate(Calendar.getInstance().getTime(), Calendar.DATE);

สิ่งนี้จะตัดทอนใน TimeZone ท้องถิ่นไม่ใช่ใน UTC ที่ Date (getTime) แสดง
epox

6

สำหรับการประทับเวลา:

timestamp -= timestamp % (24 * 60 * 60 * 1000)

3
มีข้อผิดพลาดเล็กน้อยในรหัสนี้ - วงเล็บด้านซ้ายวางไม่ถูกต้องต้องประทับเวลา - = เวลาประทับ% (24 * 60 * 60 * 1000) วิธีนี้จะตัดส่วนเวลาออก และฉันแน่ใจว่าวิธีนี้เพียงพอกว่าการสร้างวัตถุ Caledar และเล่นด้วยวิธีการของมันหรือแม้กระทั่งใช้ไลบรารีของบุคคลที่สามอื่น ๆ
สแตน

2
ไม่นี่ไม่ใช่วิธีแก้ปัญหาที่ถูกต้องระวัง นี่เหมือนกับการปัดเศษค่าวันที่เป็นพื้นนั่นคือคุณอาจได้รับ 28 มีนาคมสำหรับการประทับเวลาของวันที่ 29 มีนาคม (ในภาษาของคุณ) ดังนั้นโซลูชันที่ใช้ปฏิทิน (DateUtils ของ Apache ใช้ปฏิทินด้วย) จึงเป็นวิธีเดียว
Drew

นอกจากนี้ยังจะไม่ทำงานเมื่อเวลาเปลี่ยนไปเนื่องจากเวลาออมแสง
Alexandru Severin

5

จาก java.util.Date JavaDocs:

คลาสวันที่แสดงถึงช่วงเวลาที่เฉพาะเจาะจงโดยมีความแม่นยำระดับมิลลิวินาที

และจาก java.sql.Date JavaDocs:

เพื่อให้สอดคล้องกับนิยามของ SQL DATE ค่ามิลลิวินาทีที่ห่อด้วยอินสแตนซ์ java.sql.Date จะต้อง 'ทำให้เป็นมาตรฐาน' โดยการตั้งค่าชั่วโมงนาทีวินาทีและมิลลิวินาทีเป็นศูนย์ในเขตเวลาเฉพาะที่เกี่ยวข้องกับอินสแตนซ์ .

ดังนั้นแนวทางที่ดีที่สุดคือการใช้ java.sql.Date หากคุณไม่ต้องการช่วงเวลา

java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis());

และผลลัพธ์คือ:

java.util.Date : Thu Apr 26 16:22:53 PST 2012
java.sql.Date  : 2012-04-26

4

TL; DR

LocalDateTime.parse(                            // Lacking an offset or time zone, parse as a `LocalDateTime`. *Not* a specific moment in time.
    "2008-01-01 13:15:00".replace( " " , "T" )  // Alter input string to comply with ISO 8601 standard format.
)
.toLocalDate()                                  // Extract a date-only value.
.atStartOfDay(                                  // Do not assume the day starts at 00:00:00. Let class determine start-of-day.
    ZoneId.of( "Europe/Paris" )                 // Determining a specific start-of-day requires a time zone.
)                                               // Result is a `ZonedDateTime` object. At this point we have a specific moment in time, a point on the timeline.
.toString()                                     // Generate a String in standard ISO 8601 format, wisely extended to append the name of the time zone in square brackets.

2008-01-01T00: 00 + 01: 00 [ยุโรป / ปารีส]

ในการสร้าง String ในรูปแบบที่คุณต้องการให้ส่งไฟล์DateTimeFormatter.

LocalDateTime.parse(                            // Lacking an offset or time zone, parse as a `LocalDateTime`. *Not* a specific moment in time.
    "2008-01-01 13:15:00".replace( " " , "T" )  // Alter input string to comply with ISO 8601 standard format.
)
.toLocalDate()                                  // Extract a date-only value.
.atStartOfDay(                                  // Do not assume the day starts at 00:00:00. Let class determine start-of-day.
    ZoneId.of( "Europe/Paris" )                 // Determining a specific start-of-day requires a time zone.
)                                               // Result is a `ZonedDateTime` object. At this point we have a specific moment in time, a point on the timeline.
.format(                                        // Generate a String representing the object’s value.
    DateTimeFormatter.ISO_LOCAL_DATE_TIME       // Built-in predefined formatter close to what you want. 
)
.replace( "T" , " " )                           // Replace the standard’s use of a 'T' in the middle with your desired SPACE character.

2008-01-01 00:00:00 น

รายละเอียด

คำตอบอื่น ๆ ถูกต้อง แต่ใช้คลาสวันที่และเวลาแบบเก่าซึ่งตอนนี้เฟรมเวิร์ก java.time ล้าสมัย

java.time

กรอบ java.time ถูกสร้างขึ้นใน Java 8 และใหม่กว่า ฟังก์ชัน java.time ส่วนใหญ่แบ็คพอร์ตเป็น Java 6 & 7 ( ThreeTen-Backport ) และปรับให้เข้ากับ Android ( ThreeTenABP ) เพิ่มเติม

ขั้นแรกให้แก้ไขสตริงอินพุตเพื่อให้สอดคล้องกับรูปแบบ ISO 8601 เวอร์ชัน Canonical มาตรฐานISO 8601รูปแบบถูกนำมาใช้โดยเริ่มต้นในการเรียน java.time สำหรับการแยก / สร้างสตริงที่เป็นตัวแทนของค่าวันเวลา เราจำเป็นต้องแทนที่ SPACE ตรงกลางด้วยไฟล์T.

String input = "2008-01-01 13:15:00".replace( " " , "T" );  // → 2008-01-01T13:15:00

ตอนนี้เราสามารถแยกวิเคราะห์เป็น a LocalDateTimeโดยที่“ Local” หมายถึงไม่มีเฉพาะท้องที่ ข้อมูลที่ป้อนไม่มีข้อมูลoffset-from-UTCหรือเขตเวลา

LocalDateTime ldt = LocalDateTime.parse( input );

ldt.toString () … 2008-01-01T13: 15: 00 น

หากคุณไม่สนใจเรื่องเวลาของวันหรือเขตเวลาให้แปลงเป็นLocalDateไฟล์.

LocalDate ld = ldt.toLocalDate();

ld.toString () … 2008-01-01

ช่วงเวลาแรกของวัน

หากคุณต้องการให้เวลาของวันตั้งเป็นช่วงเวลาแรกของวันให้ใช้ZonedDateTimeคลาสจากนั้นแปลงเป็นLocalDateวัตถุเพื่อเรียกatStartOfDayใช้เมธอด โปรดทราบว่าช่วงเวลาแรกอาจไม่ใช่เวลา00:00:00เนื่องจากเวลาออมแสงหรือความผิดปกติอื่น ๆ

เขตเวลามีความสำคัญเนื่องจากในช่วงเวลาใด ๆ วันที่จะแตกต่างกันไปทั่วโลกตามโซน ตัวอย่างเช่นช่วงเวลาหลังเที่ยงคืนในปารีสเป็นวันใหม่สำหรับชาวปารีส แต่ยังคงเป็น "เมื่อวาน" ในมอนทรีออลสำหรับชาวแคนาดา

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone( zoneId );
LocalDate ldFromZdt = zdt.toLocalDate();
ZonedDateTime zdtStartOfDay = ldFromZdt.atStartOfDay( zoneId );

zdtStartOfDay.toString () … 2008-01-01T00: 00: 00-05: 00 [อเมริกา / มอนทรีออล]

UTC

หากต้องการดูช่วงเวลานั้นผ่านเลนส์ของเขตเวลาUTCให้แยกInstantวัตถุ ทั้งสองZonedDateTimeและInstantจะแสดงช่วงเวลาเดียวกันบนไทม์ไลน์ แต่ปรากฏเป็นเวลานาฬิกาแขวนที่ต่างกันสองเวลาครั้งผนังนาฬิกา

An Instantเป็นคลาส building-block พื้นฐานใน java.time เสมอใน UTC ตามความหมาย ใช้คลาสนี้บ่อยๆเนื่องจากโดยทั่วไปคุณควรใช้ตรรกะทางธุรกิจการจัดเก็บข้อมูลและการแลกเปลี่ยนข้อมูลใน UTC

Instant instant = zdtStartOfDay.toInstant();

instant.toString () … 2008-01-01T05: 00: 00Z

เราเห็นเวลา 5.00 น. แทนที่จะเป็นจังหวะของเที่ยงคืน ในรูปแบบมาตรฐานZส่วนท้ายสั้นZuluและหมายถึง "UTC"


เกี่ยวกับjava.time

java.timeกรอบถูกสร้างขึ้นใน Java 8 และต่อมา ชั้นเรียนเหล่านี้แย่งลำบากเก่ามรดกเรียนวันที่เวลาเช่นjava.util.Date, และCalendarSimpleDateFormat

โครงการJoda-Timeขณะนี้อยู่ในโหมดการบำรุงรักษาแนะนำให้ย้ายไปที่java.timeคลาส

ต้องการเรียนรู้เพิ่มเติมโปรดดูที่ออราเคิลกวดวิชา และค้นหา Stack Overflow สำหรับตัวอย่างและคำอธิบายมากมาย ข้อมูลจำเพาะคือJSR 310310

คุณสามารถแลกเปลี่ยนวัตถุjava.timeโดยตรงกับฐานข้อมูลของคุณ ใช้ไดรเวอร์ JDBC ที่สอดคล้องกับJDBC 4.2หรือใหม่กว่า ไม่ต้องใช้สายไม่จำเป็นต้องมีjava.sql.*คลาส

จะหาคลาส java.time ได้ที่ไหน?

  • Java SE 8 , Java SE 9และใหม่กว่า
    • Built-in
    • ส่วนหนึ่งของ Java API มาตรฐานพร้อมการใช้งานแบบรวม
    • Java 9 เพิ่มคุณสมบัติและการแก้ไขเล็กน้อย
  • Java SE 6และ Java SE 7
    • มากของการทำงาน java.time จะกลับรังเพลิง Java 6 และ 7 ในThreeTen-ย้ายกลับ
  • Android
    • การใช้งานกลุ่ม Android เวอร์ชันที่ใหม่กว่าของคลาส java.time
    • สำหรับก่อนหน้านี้ Android (<26) ที่ThreeTenABPโครงการปรับThreeTen-ย้ายกลับ (ดังกล่าวข้างต้น) ดูวิธีใช้ ThreeTenABP … .

โครงการThreeTen-Extraขยาย java.time ด้วยคลาสเพิ่มเติม โปรเจ็กต์นี้เป็นพื้นที่พิสูจน์สำหรับการเพิ่ม java.time ในอนาคต คุณอาจพบว่าการเรียนที่มีประโยชน์บางอย่างที่นี่เช่นInterval, YearWeek, YearQuarterและอื่น ๆ อีกมากมาย



2

คำถามขัดแย้งกัน 00:00:00มันจะถามสำหรับวันที่โดยไม่ต้องเวลาของวันยังแสดงตัวอย่างด้วยเวลาของ

Joda เวลา

UPDATE: Joda เวลาโครงการขณะนี้อยู่ในโหมดการบำรุงรักษาด้วยทีมงานให้คำปรึกษาการโยกย้ายไปยังjava.timeชั้นเรียน ดูคำตอบอื่น ๆ ของฉันสำหรับโซลูชัน java.time

หากคุณต้องการให้ตั้งค่าเวลาเป็นช่วงเวลาแรกของวันแทนให้ใช้DateTimeวัตถุในไลบรารี Joda-Time และเรียกwithTimeAtStartOfDayใช้เมธอด โปรดทราบว่าช่วงเวลาแรกอาจไม่ใช่เวลา00:00:00เนื่องจากเวลาออมแสงหรือความผิดปกติอื่น ๆ


นี่คือคำตอบที่ชัดเจน (สมมติว่ามีใครสามารถและต้องการใช้เวลา Joda)
Clint Eastwood

2

เพียงแค่clear()เขตข้อมูลซ้ำซ้อน

Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.clear(Calendar.MINUTE);
calendar.clear(Calendar.SECOND);
calendar.clear(Calendar.MILLISECOND);
Date truncatedDate = calendar.getTime();

จาก Java 8 ตัวเลือกที่ดีกว่าคือใช้truncatedTomethod LocalDateTimeเช่น:

LocalDateTime.now().truncatedTo(ChronoUnit.DAYS)

วิธีนี้ใช้ไม่ได้เพราะcalendar.clear(Calendar.HOUR_OF_DAY);ไม่ได้ล้างเวลาทำการ วิธีแก้ปัญหาจาก @cletus ใช้งานได้ดี
Arcao

ขออภัยคุณพูดถูกฉันแก้ไขแล้วคุณควรตั้งค่าเป็นเวลาหลายชั่วโมง โดยทั่วไปแล้วการตัดทอนวันที่ ...
m190

1

มันทำให้ฉันรำคาญจริงๆที่ตัวสร้างปฏิทินที่ "ปรับปรุง" ใหม่ไม่ใช้ int เป็นมิลลิวินาทีเหมือน Date one แบบเก่าที่ "แย่มาก" จากนั้นฉันก็ข้ามจริงๆและเขียนสิ่งนี้:

long stuffYou = startTime.getTimeInMillis() % 1000;
startTime.setTimeInMillis(startTime.getTimeInMillis() - stuffYou);

ตอนนั้นฉันไม่ได้ใช้คำว่า "สิ่งของ" แต่แล้วฉันก็ค้นพบความสุขของสิ่งนี้:

startTime.set(Calendar.MILLISECOND, 0);

แต่ฉันยังค่อนข้างข้ามเรื่องนี้


1

ฉันแก้ไขปัญหาเช่นนี้แล้ว (ในโซนแปดตะวันออก (เวลาปักกิ่ง)):

private Date getTruncatedDate(Date d) {
    if (d == null) {
        return null;
    }
    long h = 60 * 60 * 1000L;
    long dateStamp = d.getTime() - (d.getTime() + 8 * h) % (24 * h);
    return new Date(dateStamp);
}

ก่อนอื่นคุณควรระบุให้ชัดเจนว่าการประทับเวลาคืออะไร การประทับเวลาคือมิลลิวินาทีทั้งหมดตั้งแต่ 01 ม.ค. 00:00:00 น. 1970 ของ GMT (เช่นเดียวกับ UTC) หรือพฤ. 01 ม.ค. 08:00:00 CST 1970 ถึงตอนนี้

ข้อควรจำ: การประทับเวลาไม่ขึ้นกับเขตเวลา

ดังนั้นคุณจะได้ผลลัพธ์เดียวกันกับคำสั่งต่อไปนี้ในเขตเวลาที่ต่างกัน:

System.out.println(new Date().getTime());

และ

System.out.println(new Date(0));

พิมพ์ข้อมูลเวลาที่แตกต่างกันในเขตเวลาที่แตกต่างกัน: หากคุณตั้งค่าโซนเวลาพีซีเป็น UTC คุณจะได้รับ

Thu Jan 01 00:00:00 UTC 1970

แต่ถ้าคุณตั้งเขตเวลาเป็น (UTC +8: 00) ปักกิ่งฉงชิ่งฮ่องกงอุรุมกคุณจะได้รับ:

Thu Jan 01 08:00:00 CST 1970

Java ได้รับการประทับเวลาจากนั้นจะแสดงข้อมูลวันที่และเวลาตามเขตเวลา

สำหรับการแนะนำวิธีที่ Java แสดงข้อมูลวันที่และเวลาในเขตเวลาต่างๆวิธีการแปลข้อมูลเวลาทำได้ง่าย คุณควรได้รับการประทับเวลาและคำนึงถึงเขตเวลาเมื่อตัดข้อมูลเวลาออก จากนั้นคุณสามารถสร้างออบเจ็กต์ Date ใหม่ด้วยการประทับเวลาตัด (เราเรียกมันว่าการประทับวันที่) java จะชดเชยเขตเวลาเมื่อแสดงข้อมูลวันที่

เช่นเดียวกับในโซนแปดตะวันออก (เวลาปักกิ่ง) เวลาปักกิ่งเร็วกว่า GMT 8 ชั่วโมงดังนั้นคุณควรลบออกมากกว่า 8 ชั่วโมงเมื่อคุณดำเนินการโมดูโล กล่าวคือคุณควรได้รับเวลา GMT ก่อนจากนั้น Java จะเพิ่มเวลา 8 ชั่วโมงเมื่อแสดงเวลาตามการตั้งค่าโซนเวลาของพีซีของคุณ


ปัญหาเรื่องเขตเวลาคลุมเครือและยังทำให้ฉันสงสัยมานาน ตอนนี้ฉันทำให้มันชัดเจน หวังว่าจะช่วยได้


2018-01-04 วิธีการด้านล่างก็ใช้ได้เช่นกัน

private Date getTruncatedDate2(Date d) {
    Calendar cal = Calendar.getInstance(); // locale-specific
    cal.setTime(d);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);


return cal.getTime();

}


FYI คำตอบนี้ใช้คลาสวันเวลาเก่าที่ยุ่งยากซึ่งถูกแทนที่ด้วยคลาสjava.time เมื่อหลายปีก่อน
Basil Bourque

1

คุณสามารถทำได้เพื่อหลีกเลี่ยงปัญหาเขตเวลา:

public static Date truncDate(Date date) {
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    cal.setTime(date);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    return cal.getTime();
}

แม้ว่าDateออบเจ็กต์Java จะเป็นค่าการประทับเวลา แต่ในระหว่างการตัดทอนจะถูกแปลงเป็นเขตเวลาท้องถิ่นดังนั้นคุณจะได้รับค่าที่น่าประหลาดใจหากคุณคาดหวังค่าจากเขตเวลา UTC


คลาสที่ยุ่งยากCalendarและDateกลายเป็นมรดกเมื่อหลายปีก่อนด้วยคลาสjava.time ที่ใช้ JSR 310 ใน Java 8 และใหม่กว่า การแนะนำให้ใช้ในปี 2018 เป็นคำแนะนำที่ไม่ดี
Basil Bourque

0

อาจเป็นการตอบช้า แต่นี่เป็นวิธีที่ทำได้ในบรรทัดเดียวโดยไม่ต้องใช้ไลบรารีใด ๆ :

new SimpleDateFormat("yyyy-MM-dd").parse(new SimpleDateFormat("yyyy-MM-dd").format(YOUR_TIMESTAMP))

0

ด้วยJoda-Timeตั้งแต่เวอร์ชัน 2.0 คุณสามารถLocalDate.toDate()ใช้ได้

ง่ายดาย

// someDatetime is whatever java.util.Date you have.
Date someDay = new LocalDate(someDatetime).toDate();

[A] คำตอบของคุณซ้ำซ้อน แล้วโพสต์โดยไบรอัน Agnew [B] รหัสของคุณไม่ถูกต้องเนื่องจากไม่สนใจเขตเวลาซึ่งเป็นปัญหาที่เกิดขึ้นในคำถาม
Basil Bourque

อาจจะซ้ำซ้อน แต่ฉันแค่ยกตัวอย่างที่ง่ายกว่านี้เพราะฉันรู้ว่าคำตอบไม่ควรอยู่ในความคิดเห็น ใช่ java.util.Date ละเว้นปรบ แต่คำถามเดิมกับทำให้ผมใช้a Java Date object java.util.Dateยิ่งไปกว่านั้นมันไม่ได้อธิบายว่าเขตเวลาของเขามีปัญหากับ java.util.Date (เมื่อไหร่ที่ไหน?) แม้ว่าเขาจะไม่สามารถช่วยใช้อื่นนอกจากDate.
lamusique

0

สำหรับคำตอบทั้งหมดที่ใช้ปฏิทินคุณควรใช้แบบนี้แทน

public static Date truncateDate(Date date) {
    Calendar c = Calendar.getInstance();
    c.setTime(date);
    c.set(Calendar.HOUR_OF_DAY, c.getActualMinimum(Calendar.HOUR_OF_DAY));
    c.set(Calendar.MINUTE, c.getActualMinimum(Calendar.MINUTE));
    c.set(Calendar.SECOND, c.getActualMinimum(Calendar.SECOND));
    c.set(Calendar.MILLISECOND, c.getActualMinimum(Calendar.MILLISECOND));
    return c.getTime();
}

แต่ฉันชอบสิ่งนี้:

public static Date truncateDate(Date date) {
    return new java.sql.Date(date.getTime());
}

java.sql.Dateระดับอ้างว่าเป็นตัวแทนของค่าวันเท่านั้น แต่จริง ๆ แล้วไม่มีช่วงเวลาของวันปรับโซนเวลา UTC ดังนั้นจึงไม่ใช่วิธีแก้ปัญหาที่เหมาะสมสำหรับคำถาม
Basil Bourque

0

นี่เป็นวิธีง่ายๆในการรับวันที่โดยไม่ใช้เวลาหากคุณใช้ Java 8+: ใช้ประเภทjava.time.LocalDateแทน Date

LocalDate now = LocalDate.now();
 System.out.println(now.toString());

ผลลัพธ์:

2019-05-30

https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html


1
การใช้LocalDateเป็นความคิดที่ดีสำหรับวัตถุประสงค์ส่วนใหญ่ แต่ยังไม่ชัดเจนว่าจะใช้กับข้อมูลจากคำถาม2008-01-01 13:15:00อย่างไร
Ole VV
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.