จะรับเวลาเริ่มต้นและเวลาสิ้นสุดของวันได้อย่างไร?


121

จะรับเวลาเริ่มต้นและเวลาสิ้นสุดของวันได้อย่างไร?

รหัสเช่นนี้ไม่ถูกต้อง:

 private Date getStartOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.set(year, month, day, 0, 0, 0);
    return calendar.getTime();
}

private Date getEndOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.set(year, month, day, 23, 59, 59);
    return calendar.getTime();
}

ไม่แม่นยำถึงมิลลิวินาที


8
คุณหมายความว่าอะไร "ไม่ถูกต้อง"?
Kirk Woll

รหัสผิดอะไร คุณได้อะไรที่คุณไม่คาดคิด? คุณต้องการให้วันของคุณเริ่มต้นและสิ้นสุดตามเขตเวลาใด
Mark Reed

4
โค้ดด้านบนไม่ได้ใช้วันที่ที่ส่งเข้าไปในเมธอดด้วยซ้ำ สิ่งที่ควรทำ: calendar.setTime (วันที่) หลังจากสร้างปฏิทิน
Jerry Destremps

2
คำถามนี้ถือว่าค่าวันที่และเวลามีความละเอียดเป็นมิลลิวินาที จริงสำหรับ java.util.Date และ Joda-Time แต่ False สำหรับแพ็คเกจ java.time ใน Java 8 (นาโนวินาที) ฐานข้อมูลบางอย่างเช่นPostgres (ไมโครวินาที) ไลบรารี Unix (ทั้งวินาที) และอื่น ๆ ดูคำตอบของฉันสำหรับแนวทางที่ปลอดภัยยิ่งขึ้นโดยใช้ Half-Open
Basil Bourque

2
อันที่จริงคุณควรจะได้รับการเริ่มต้นของวันถัดไปและเมื่อทำซ้ำรายการในวันนั้น (สมมติว่าคุณต้องการทำเช่นนั้น) คุณจะระบุขอบเขตบนโดยใช้ <แทน <= ซึ่งจะไม่รวมวันถัดไป แต่รวมวันก่อนหน้าทั้งหมดลงไปเป็นนาโนวินาที
Daniel F

คำตอบ:


115

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::atStartOfDayjava.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 ทั้งแบบสมัยใหม่และแบบดั้งเดิม

ขณะนี้กรอบ 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, และCalendarSimpleDateFormat

ต้องการเรียนรู้เพิ่มเติมโปรดดูที่ออราเคิลกวดวิชา และค้นหา 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 ได้ที่ไหน?

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

Joda เวลา

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

Joda เวลามีสามชั้นเรียนเพื่อเป็นตัวแทนของช่วงเวลาในรูปแบบต่างๆ: Interval, และPeriod มีระดับเริ่มต้นและสิ้นสุดในระยะเวลาของจักรวาล สิ่งนี้เหมาะกับความต้องการของเราที่จะเป็นตัวแทนของ "วัน"DurationInterval

เราเรียกวิธีนี้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();

ฉันจำเป็นต้องใช้LocalDateTime
user924

170

จาวา 8


public static Date atStartOfDay(Date date) {
    LocalDateTime localDateTime = dateToLocalDateTime(date);
    LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
    return localDateTimeToDate(startOfDay);
}

public static Date atEndOfDay(Date date) {
    LocalDateTime localDateTime = dateToLocalDateTime(date);
    LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
    return localDateTimeToDate(endOfDay);
}

private static LocalDateTime dateToLocalDateTime(Date date) {
    return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}

private static Date localDateTimeToDate(LocalDateTime localDateTime) {
    return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}

อัปเดต : ฉันได้เพิ่ม 2 วิธีการเหล่านี้ในคลาส Java Utility ของฉันที่นี่

อยู่ใน Maven Central Repository ที่:

<dependency>
  <groupId>com.github.rkumsher</groupId>
  <artifactId>utils</artifactId>
  <version>1.3</version>
</dependency>

Java 7 และรุ่นก่อนหน้า


ด้วย Apache Commons

public static Date atEndOfDay(Date date) {
    return DateUtils.addMilliseconds(DateUtils.ceiling(date, Calendar.DATE), -1);
}

public static Date atStartOfDay(Date date) {
    return DateUtils.truncate(date, Calendar.DATE);
}

ไม่มี Apache Commons

public Date atEndOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.HOUR_OF_DAY, 23);
    calendar.set(Calendar.MINUTE, 59);
    calendar.set(Calendar.SECOND, 59);
    calendar.set(Calendar.MILLISECOND, 999);
    return calendar.getTime();
}

public Date atStartOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTime();
}

5
ฉันไม่แนะนำให้ใช้วิธีนี้เนื่องจากปัญหากรณีขอบที่คุณจะพบกับเขตเวลาการออมแสง ฯลฯ ที่ห้องสมุดเวลาเช่น Joda จะดูแลคุณ
Edward Anderson

7
ฉันคิดว่าgetStartOfDayควรเป็น: LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);เช่น LocalTime ไม่ใช่ LocalDateTime
Konstantin Kulagin

getEndOfDay(Date date)อย่าคิดว่าคนเหล่านั้น getStartOfDay(Date date)วิธีการในส่วน Java 8 นั้นถูกต้องกล่าวคือ LocalDateTime.MAX และ. MIN ทำให้คุณทราบวันที่เร็วที่สุดในอดีตและในอนาคตไม่ใช่จุดเริ่มต้นและจุดสิ้นสุดของวัน แต่ฉันขอแนะนำ. atStartOfDay () สำหรับ start และ. plusDays (1) .atStartOfDay (). minusNanos (1) สำหรับจุดสิ้นสุด
Glen Mazza

เมธอดlocalDateTimeToDate(LocalDateTime startOfDay)พ่นข้อยกเว้น - java.lang.IllegalArgumentException: java.lang.ArithmeticException: long overflow
sanluck

1
@GlenMazza ทางออก Java 8 ใช้localtime .MAXไม่LocalDateTime.MAX การแก้ปัญหานั้นถูกต้อง
Frederico Pantuzza

28

ใน getEndOfDay คุณสามารถเพิ่ม:

calendar.set(Calendar.MILLISECOND, 999);

แม้ว่าจะพูดในเชิงคณิตศาสตร์ แต่คุณไม่สามารถระบุจุดสิ้นสุดของวันอื่นได้นอกจากพูดว่าเป็น "ก่อนเริ่มวันถัดไป"

ดังนั้นแทนที่จะพูดif(date >= getStartOfDay(today) && date <= getEndOfDay(today))คุณควรพูดว่า: if(date >= getStartOfDay(today) && date < getStartOfDay(tomorrow)). นั่นเป็นคำจำกัดความที่มั่นคงกว่ามาก (และคุณไม่ต้องกังวลกับความแม่นยำระดับมิลลิวินาที)


1
ครึ่งหลังของคำตอบนี้เป็นวิธีที่ดีที่สุด วิธีนี้เรียกว่า "Half-Open" ฉันจะอธิบายต่อไปในคำตอบของฉัน
Basil Bourque

14

java.time

ใช้java.timeเฟรมเวิร์กที่สร้างขึ้นใน Java 8

import java.time.LocalTime;
import java.time.LocalDateTime;

LocalDateTime now = LocalDateTime.now(); // 2015-11-19T19:42:19.224
// start of a day
now.with(LocalTime.MIN); // 2015-11-19T00:00
now.with(LocalTime.MIDNIGHT); // 2015-11-19T00:00
// end of a day
now.with(LocalTime.MAX); // 2015-11-19T23:59:59.999999999

3
คำตอบนี้ไม่สนใจความผิดปกติเช่น Daylight Saving Time (DST) Local…เรียนมีแนวคิดของโซนเวลาและไม่มีการปรับสำหรับความผิดปกติ ตัวอย่างเช่นบางเขตเวลามีการเปลี่ยนแปลง DST ในเวลาเที่ยงคืนดังนั้นช่วงเวลาแรกของวันจึงอยู่ที่เวลา01:00:00.0(1 น.) แทนที่จะเป็น00:00:00.0ค่าที่รหัสนี้สร้างขึ้น ใช้ZonedDateTimeแทน
Basil Bourque

4

วิธีเพิ่มเติมในการค้นหาจุดเริ่มต้นของวันด้วย java8 java.time.ZonedDateTime แทนที่จะทำผ่านLocalDateTimeเพียงแค่ตัดทอนอินพุต ZonedDateTime เป็น DAYS:

zonedDateTimeInstance.truncatedTo( ChronoUnit.DAYS );

2

สำหรับ java 8 คำสั่งบรรทัดเดียวต่อไปนี้กำลังทำงาน ในตัวอย่างนี้ฉันใช้เขตเวลา UTC โปรดพิจารณาเปลี่ยน TimeZone ที่คุณใช้ในปัจจุบัน

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

final LocalDateTime endOfDay       = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
final Date          endOfDayAsDate = Date.from(endOfDay.toInstant(ZoneOffset.UTC));

System.out.println(endOfDayAsDate);

final LocalDateTime startOfDay       = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
final Date          startOfDayAsDate = Date.from(startOfDay.toInstant(ZoneOffset.UTC));

System.out.println(startOfDayAsDate);

หากเวลาไม่แตกต่างกับเอาต์พุต ลอง:ZoneOffset.ofHours(0)


1
สิ่งนี้เพิ่มมูลค่านอกเหนือจากคำตอบที่มีอยู่ได้อย่างไร นอกจากนี้คุณไม่สนใจประเด็นสำคัญของเขตเวลา และการส่งผ่านค่าคงที่ UTC ไปtoInstantเป็นไวยากรณ์ที่ผิดกฎหมายและซ้ำซ้อนในเชิงแนวคิด
Basil Bourque

@BasilBourque "สิ่งนี้จะเพิ่มมูลค่านอกเหนือจากคำตอบที่มีอยู่ได้อย่างไร" นี่คือวิธีการทำงานของ stackoverflow BTW นี่เป็นเพียงเทมเพลต ผู้คนสามารถเปลี่ยนวิธีที่พวกเขาต้องการได้ การส่ง UTC ไปยัง Instant นั้นถูกต้องตามกฎหมายโดยสิ้นเชิงคุณสามารถตรวจสอบผลลัพธ์ได้
FıratKÜÇÜK

2

Java 8 หรือ ThreeTenABP

ZonedDateTime

ZonedDateTime curDate = ZonedDateTime.now();

public ZonedDateTime startOfDay() {
    return curDate
    .toLocalDate()
    .atStartOfDay()
    .atZone(curDate.getZone())
    .withEarlierOffsetAtOverlap();
}

public ZonedDateTime endOfDay() {

    ZonedDateTime startOfTomorrow =
        curDate
        .toLocalDate()
        .plusDays(1)
        .atStartOfDay()
        .atZone(curDate.getZone())
        .withEarlierOffsetAtOverlap();

    return startOfTomorrow.minusSeconds(1);
}

// based on https://stackoverflow.com/a/29145886/1658268

LocalDateTime

LocalDateTime curDate = LocalDateTime.now();

public LocalDateTime startOfDay() {
    return curDate.atStartOfDay();
}

public LocalDateTime endOfDay() {
    return startOfTomorrow.atTime(LocalTime.MAX);  //23:59:59.999999999;
}

// based on https://stackoverflow.com/a/36408726/1658268

ฉันหวังว่าจะช่วยใครบางคน


เมธอด "atTime" เป็นแนวทางที่ดีมากโดยมีค่าคงที่ "LocalTime.MAX" สำหรับการสิ้นสุดวัน ดี!
Mr. Anderson

2

ฉันลองใช้รหัสนี้และใช้งานได้ดี!

final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
final ZonedDateTime startofDay =
    now.toLocalDate().atStartOfDay(ZoneOffset.UTC);
final ZonedDateTime endOfDay =
    now.toLocalDate().atTime(LocalTime.MAX).atZone(ZoneOffset.UTC);

ถ้าคุณมีZonedDateTimeและที่จำหน่ายของคุณมีความจำเป็นต้องใช้ที่เคยไม่มีInstant java.sql.Timestampคลาสนั้นเป็นหนึ่งในคลาสเก่าที่น่ากลัวซึ่งตอนนี้ถูกแทนที่ด้วยคลาสjava.time ใน JDBC 4.2 เราสามารถแลกเปลี่ยนวัตถุjava.timeกับฐานข้อมูลได้โดยตรง การผสมผสานระหว่างคลาสดั้งเดิมและคลาสสมัยใหม่ของคุณไม่สมเหตุสมผลสำหรับฉัน
Basil Bourque

1

อีกวิธีหนึ่งที่ไม่ขึ้นอยู่กับกรอบงานใด ๆ คือ:

static public Date getStartOfADay(Date day) {
    final long oneDayInMillis = 24 * 60 * 60 * 1000;
    return new Date(day.getTime() / oneDayInMillis * oneDayInMillis);
}

static public Date getEndOfADay(Date day) {
    final long oneDayInMillis = 24 * 60 * 60 * 1000;
    return new Date((day.getTime() / oneDayInMillis + 1) * oneDayInMillis - 1);
}

โปรดทราบว่าจะส่งคืนเวลาตาม UTC


1
private Date getStartOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.setTimeInMillis(0);
    calendar.set(year, month, day, 0, 0, 0);
    return calendar.getTime();
    }

private Date getEndOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.setTimeInMillis(0);
    calendar.set(year, month, day, 23, 59, 59);
    return calendar.getTime();
    }

calendar.setTimeInMillis (0); ให้ความแม่นยำไม่เกินมิลลิวินาที


1
ชั้นเรียนวันที่ - เวลาที่น่ากลัวเหล่านี้ถูกแทนที่ด้วยคลาสjava.timeสมัยใหม่ที่กำหนดไว้ใน JSR 310
Basil Bourque

@BasilBourque แพ็คเกจjava.timeปรากฏเฉพาะใน Java 8 ซึ่งพร้อมใช้งานตั้งแต่ Android N (API 26) เท่านั้น
ivan8m8

@ ivan8m8 ส่วนใหญ่ของjava.timeการทำงานจะกลับรังเพลิง Java 6 และ 7 ในThreeTen-ย้ายกลับห้องสมุด ดัดแปลงเพิ่มเติมสำหรับ Android รุ่นแรก (<26) ในไลบรารีThreeTenABP
Basil Bourque

@BasilBourque แต่ ThreeTen ใช้กลไกที่ไม่มีประสิทธิภาพมากบน Android
ivan8m8

@ ivan8m8 คุณอาจจะคิดของบรรพบุรุษของjava.time , Joda เวลา อีกครั้งดูโครงการThreeTenABP ฉันไม่เคยได้ยินมาก่อนว่า Android ใช้ไลบรารีนั้นไม่มีประสิทธิภาพ
Basil Bourque

0

ฉันรู้ว่ามันช้าไปหน่อย แต่ในกรณีของ Java 8 หากคุณใช้ OffsetDateTime (ซึ่งมีข้อดีมากมายเช่น TimeZone นาโนวินาที ฯลฯ ) คุณสามารถใช้รหัสต่อไปนี้:

OffsetDateTime reallyEndOfDay = someDay.withHour(23).withMinute(59).withSecond(59).withNano(999999999);
// output: 2019-01-10T23:59:59.999999999Z

0

ฉันมีความไม่สะดวกหลายประการเกี่ยวกับวิธีแก้ปัญหาทั้งหมดเนื่องจากฉันต้องการประเภทของตัวแปรทันทีและโซนเวลามักจะขัดขวางการเปลี่ยนแปลงทุกอย่างจากนั้นรวมโซลูชันที่ฉันเห็นว่านี่เป็นตัวเลือกที่ดี

        LocalDate today = LocalDate.now();
        Instant startDate = Instant.parse(today.toString()+"T00:00:00Z");
        Instant endDate = Instant.parse(today.toString()+"T23:59:59Z");

และเราก็ได้ผลลัพธ์

        startDate = 2020-01-30T00:00:00Z
        endDate = 2020-01-30T23:59:59Z

ฉันหวังว่ามันจะช่วยคุณได้


วันจริงจะสิ้นสุดลงเมื่อมาถึงช่วงเวลาแรกของวันถัดไป รหัสของคุณข้ามไปในช่วงวินาทีสุดท้ายของวันซึ่งเป็นพันล้านนาโนวินาทีที่ไม่เคยรายงาน ดูคำตอบของฉันเพื่อเรียนรู้เกี่ยวกับแนวทาง Half-Open ในการกำหนดช่วงเวลา
Basil Bourque

การจัดการสตริงเป็นวิธีจัดการค่าวันที่ - เวลาโดยทั่วไปเป็นแนวทางที่ไม่ดี ใช้สมาร์ทออบเจ็กต์แทนการใช้สตริงใบ้สำหรับงานนี้ java.timeเรียนให้ฟังก์ชันการทำงานทั้งหมดที่คุณต้องการสำหรับปัญหานี้ได้โดยไม่ต้องหันไปจัดการสตริง
Basil Bourque

ตอนนี้ฉันเพิ่งเพิ่มส่วนtl; drในคำตอบของฉันซึ่งแสดงวิธีรับช่วงของวันเป็นคู่ของInstantวัตถุ เคล็ดลับ: คุณอาจสนใจที่จะเพิ่มไลบรารี ThreeTen-Extraในโปรเจ็กต์ของคุณเพื่อใช้Intervalคลาส
Basil Bourque

0

ฉันคิดว่าสิ่งที่ง่ายที่สุดคือ:

// Joda Time

DateTime dateTime=new DateTime(); 

StartOfDayMillis = dateTime.withMillis(System.currentTimeMillis()).withTimeAtStartOfDay().getMillis();
EndOfDayMillis = dateTime.withMillis(StartOfDayMillis).plusDays(1).minusSeconds(1).getMillis();

จากนั้นมิลลิวินาทีเหล่านี้สามารถแปลงเป็นปฏิทินทันทีหรือ LocalDate ได้ตามความต้องการของคุณด้วย Joda Time


-2
public static Date beginOfDay(Date date) {
    Calendar cal = Calendar.getInstance();
    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();
}

public static Date endOfDay(Date date) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    cal.set(Calendar.HOUR_OF_DAY, 23);
    cal.set(Calendar.MINUTE, 59);
    cal.set(Calendar.SECOND, 59);
    cal.set(Calendar.MILLISECOND, 999);

    return cal.getTime();
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.