如何获取一天的开始时间和结束时间?
如何获取一天的开始时间和结束时间?
这样的代码并不准确:
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();
}
毫秒不准确。
半开
mprivat的答案是正确的。 他的观点是不要试图结束一天,而是要比较“在第二天开始之前”。 他的想法被称为“半开放”的方法,其中一段时间的开始是包容性的,而结尾是排他性的 。
Joda-Time 2.3为此提供了一种方法来获取当天的第一时刻: withTimeAtStartOfDay()
。 同样在java.time中, LocalDate::atStartOfDay
。
查找StackOverflow中的“joda half-open”以查看更多讨论和示例。
看到这篇文章,比尔施耐德的时间间隔和其他范围应该是半开放的。
避免遗留的日期时间类
java.util.Date和.Calendar类是非常麻烦的。 避免它们。
使用Joda-Time或者最好是java.time。 java.time框架是非常成功的Joda-Time库的正式继承者。
java.time
java.time框架内置于Java 8及更高版本中。 在ThreeTen-Backport项目中移植到Java 6和7,在ThreeTenABP项目中进一步适用于Android。
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 );
使用半开放式方法,获得下一天的第一时刻。
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );
目前,java.time框架缺少如下所述的Joda-Time的Interval
类。 但是,ThreeTen-Extra项目使用其他类扩展了java.time。 这个项目是未来可能增加java.time的试验场。 其中有Interval
。 通过传递一对Instant
对象构造一个Interval
。 我们可以从我们的ZonedDateTime
对象中提取Instant
。
Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );
乔达时间
Joda-Time有三种类型,以各种方式表示一段时间: 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();
Java 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实用程序类中
它位于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();
}
在getEndOfDay中,您可以添加:
calendar.set(Calendar.MILLISECOND, 999);
尽管在数学上说,除了说“在第二天开始之前”之外,你不能指定一天结束。
因此,不应该说if(date >= getStartOfDay(today) && date <= getEndOfDay(today))
,你应该说: if(date >= getStartOfDay(today) && date < getStartOfDay(tomorrow))
。 这是一个更坚实的定义(并且您不必担心毫秒精度)。