如何获得一天的开始时间和结束时间?

如何获得一天的开始时间和结束时间?

这样的代码是不准确的:

 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();
}

它不精确到毫秒。

272564 次浏览

在 getEndOfDay 中,可以添加:

calendar.set(Calendar.MILLISECOND, 999);

虽然从数学上讲,你不能确定一天的结束时间,除非你说它是“第二天开始之前”。

因此,与其说,if(date >= getStartOfDay(today) && date <= getEndOfDay(today)),你应该说: if(date >= getStartOfDay(today) && date < getStartOfDay(tomorrow))。这是一个更加可靠的定义(而且您不必担心毫秒精度)。

爪哇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());
}

更新 : 我已经将这两个方法添加到我的 Java 实用程序类 < a href = “ https://github.com/RKumsher/utils”rel = “ noReferrer”> 这里

它位于 Maven 中央存储库:

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

Java7及其早期版本


用 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();
}

博士

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 ) ;

ToString () = 2020-01-30T00:00 + 01:00[ Africa/Tunis ]

ToString () = 2020-01-31T00:00 + 01:00[ Africa/Tunis ]

在 UTC 中可以看到相同的时刻。

Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;

ToString () = 2020-01-29T23:00:00Z

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 ) ;

ToString () = 2020-01-30T00:00 + 18:00

ToString () = 2020-01-31T00:00 + 18:00

这些 OffsetDateTime 对象将已经在 UTC 中,但是如果您需要这样的对象(根据定义总是在 UTC 中) ,则可以调用 toInstant

Instant start = odtStart.toInstant() ;
Instant stop = odtStop.toInstant() ;

ToString () = 2020-01-29T06:00:00Z

ToString () = 2020-01-30T06:00:00Z

提示: 您可能有兴趣将 < em > ThreeTen-Extra 库添加到您的项目中,以使用其 Interval类来表示这对 Instant对象。这个类提供了有用的比较方法,比如 abutsoverlapscontains等等。

Interval interval = Interval.of( start , stop ) ;

ToString () = 2020-01-29T06:00:00Z/2020-01-30T06:00:00Z

半开

由 mpriat 回答是正确的。他的观点是,不要试图获得一天的结束,而是要与“第二天开始之前”相比较。他的想法被称为“半开放”的方法,其中一个时间跨度有一个 开始是包容性的结局是独一无二的

  • Java 当前的日期时间框架(Java.util。日期/日历和 Joda 时间)都使用相对于 新纪元的毫秒。但是在 Java8中,新的 JSR310java.time。* 类使用纳秒分辨率。如果切换到新类,那么基于强制执行每天最后一刻的毫秒计数而编写的任何代码都是不正确的。
  • 如果使用其他分辨率,比较来自其他来源的数据就会出错。例如,Unix 库通常使用整秒,而 邮差等数据库将日期时间解析为微秒。
  • 一些夏时制变化发生在午夜,这可能会进一步混淆事物。

enter image description here

Joda-Time 2.3为此提供了一种方法,用于获取一天中的第一个时刻: withTimeAtStartOfDay()。类似地,在 java.time 中,LocalDate::atStartOfDay

在 StackOverflow 中搜索“ joda half-open” ,查看更多讨论和示例。

看看 Bill Schneider 的这篇文章 时间间隔和其他范围应该是半开放的

避免遗留的日期时间类

众所周知,java.util.Date 和.Calendar 类很麻烦。避免使用它们。

使用 < em > java.time 类。 爪哇时间框架是非常成功的 尤达时间库的正式继承者。

爪哇时间

Time 框架是内置在 Java8及更高版本中的。在 310-后端口项目中向后移植到 Java6和7,在 三个十分项目中进一步适应 Android。

Instant协调世界时时间线上的一个时刻,分辨率为 纳秒

Instant instant = Instant.now();

应用一个时区来获取某些地区的 挂钟时间

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

要获得一天中的第一个时刻,请查看 LocalDate类及其 atStartOfDay方法。

ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );

使用半开放的方法,获得第二天的第一个时刻。

ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );

Table of all date-time types in Java, both modern and legacy

目前,java.time 框架缺少下面描述的 Joda-Time 的 Interval类。但是,310-号外项目使用其他类扩展 java.time。这个项目是将来可能添加 java.time 的试验场。它的课程包括 Interval。通过传递一对 Instant对象构造一个 Interval。我们可以从我们的 ZonedDateTime对象中提取一个 Instant

Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );

关于 爪哇时间

< em > java.time 框架内置于 Java8及更高版本中。这些类取代了令人讨厌的旧的 遗产日期时间类,如 java.util.DateCalendarSimpleDateFormat

要了解更多,请参阅 < em > Oracle 教程 。并搜索堆栈溢出许多例子和解释。规范是 JSR 310

现在在 维修模式中的 尤达时间项目建议迁移到 爪哇时间类。

您可以直接与数据库交换 爪哇时间对象。使用与 JDBC 4.2或更高版本兼容的 JDBC 驱动程序。不需要字符串,不需要 java.sql.*类。Hibernate 5 & JPA 2.2支持 爪哇时间

从哪里获得 java.time 类?


Joda 时间

更新: Joda-Time 项目现在处于维护模式,建议迁移到 爪哇时间类。我要把这一部分完好无损地留给历史。

Joda-Time 有三个类以不同的方式表示时间跨度: IntervalPeriodDuration。ABc0在宇宙年表上有一个特定的开始和结束。这符合我们代表“一天”的需要。

我们调用方法 withTimeAtStartOfDay而不是将一天的时间设置为零。由于夏时制和其他异常现象,一天中的第一个时刻可能不是 ABc1。

使用 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();

爪哇时间

使用内置在 Java8中的 java.time框架。

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
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();
}

对于 java8,下面的单行语句可以工作。在这个例子中,我使用 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)

用 java8 java.time 寻找一天开始的其他方法。ZonedDateTime 不是通过 LocalDateTime,而是简单地将输入 ZonedDateTime 截断为 DAYS:

zonedDateTimeInstance.truncatedTo( ChronoUnit.DAYS );

另一个不依赖任何框架的解决办法是:

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 的时间

Java8或 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 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

我希望这对某人有帮助。

我试过这个代码,它工作得很好!

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);

我知道这有点晚了,但是对于 Java8来说,如果你正在使用 OffsetDateTime (它提供了很多优势,比如 TimeZone、 Nanoseconds 等) ,你可以使用下面的代码:

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

我有几个不便与所有的解决方案,因为我需要类型的 马上变量和时区总是干扰改变一切,然后结合解决方案,我看到这是一个很好的选择。

        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

希望能帮到你

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();
}

SetTimeInMillis (0) ; 使您的精确度达到毫秒

我认为最简单的方法是:

// Joda Time


DateTime dateTime=new DateTime();


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

然后可以根据 Joda Time 的需求将这些工厂转换为 Calendar、 Instant 或 LocalDate。

以下代码采用 OP 的原始公式,并根据 ms 不精确度进行调整:

    private static Date getStartOfDay() {
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);
long approximateTimestamp = calendar.getTime().getTime();
long extraMillis = (approximateTimestamp % 1000);
long exactTimestamp = approximateTimestamp - extraMillis;
return new Date(exactTimestamp);
}


private static Date getEndOfDay() {
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);
long approximateTimestamp = calendar.getTime().getTime();
long extraMillis = (approximateTimestamp % 1000);
long exactTimestamp = approximateTimestamp - extraMillis + 999;
return new Date(exactTimestamp);
}

与这个线程上的许多其他答案不同,它与旧版本的 Java 和 Android API 兼容。

最简短的回答,考虑到你的时区是 TZ:

LocalDateTime start = LocalDate.now(TZ).atStartOfDay()
LocalDateTime end = start.plusDays(1)

使用 isAfter()isBefore()方法进行比较,或者使用 toEpochSecond()toInstant()方法进行转换。

Date date = new Date();
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);

时间戳:

Timestamp startTs = Timestamp.valueOf(startOfDay);
Timestamp endTs = Timestamp.valueOf(endOfDay);