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

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

这样的代码并不准确:

 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的答案是正确的。 他的观点是不要试图结束一天,而是要比较“在第二天开始之前”。 他的想法被称为“半开放”的方法,其中一段时间​​的开始是包容性的,结尾是排他性的

  • 当前的日期 - 时间框架是Java(java.util.Date/Calendar和Joda-Time),均使用来自时期的毫秒。 但在Java 8中,新的JSR 310 java.time。*类使用纳秒分辨率。 如果切换到新类别,那么基于强制毫秒计数的任何代码都是不正确的。
  • 如果他们使用其他分辨率比较来自其他来源的数据则会出错。 例如,Unix库通常使用整秒,Postgres等数据库将日期时间解析为微秒。
  • 某些夏令时会在午夜时发生变化,这可能会进一步混淆事物。
  • 在这里输入图像描述

    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有三种类型,以各种方式表示一段时间: IntervalPeriodDuration 。 一个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实用程序类中

  • DateUtils.atStartOfDay
  • DateUtils.atEndOfDay
  • 它位于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)) 。 这是一个更坚实的定义(并且您不必担心毫秒精度)。

    链接地址: http://www.djcxy.com/p/18511.html

    上一篇: How to obtain the start time and end time of a day?

    下一篇: TimeSpan "pretty time" format in C#