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

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

这样的代码是不准确的:

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

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

在这里输入图像说明

Joda-Time 2.3为这个目的提供了一种方法来获取一天中的第一个时刻: withTimeAtStartOfDay() 。 同样在java.time中, LocalDate::atStartOfDay

searchStackOverflow中的“joda half-open”来查看更多的讨论和示例。

看到这篇文章, 时间间隔和其他范围应该是由比尔·施耐德半开放 。

避免遗留的date时间类

java.util.Date和.Calendar类是非常麻烦的。 避免他们。

使用Joda-Time或者最好是java.time 。 java.time框架是非常成功的Joda-Time库的正式inheritance者。

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框架缺less如下所述的Joda-Time的Interval类。 但是, ThreeTen-Extra项目使用其他类扩展了java.time。 这个项目是未来可能增加java.time的试验场。 其中class级是Interval 。 通过传递一对Instant对象构造一个Interval 。 我们可以从ZonedDateTime对象中提取一个Instant

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

乔达时间

Joda-Time有三种types,以各种方式表示一段时间: IntervalPeriodDuration 。 一个Interval在宇宙的时间轴上有一个特定的开始和结束。 这符合我们代表“一天”的需要。

我们使用withTimeAtStartOfDay调用方法,而不是将时间设置为零。 由于夏令时和其他exception情况,一天中的第一时间可能不是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 getEndOfDay(Date date) { LocalDateTime localDateTime = dateToLocalDateTime(date); LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX); return localDateTimeToDate(endOfDay); } public static Date getStartOfDay(Date date) { LocalDateTime localDateTime = dateToLocalDateTime(date); // LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN); LocalDateTime startOfDay = localDateTime.atStartOfDay(); return localDateTimeToDate(startOfDay); } private static Date localDateTimeToDate(LocalDateTime startOfDay) { return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()); } private static LocalDateTime dateToLocalDateTime(Date date) { return LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault()); } 

Java 7和更早版本


与Apache Commons

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

没有Apache Commons

 public Date getEndOfDay(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 getStartOfDay(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); 

虽然从math上讲,除了说“在第二天开始之前”之外,你不能指定一天结束。

因此,不应该说if(date >= getStartOfDay(today) && date <= getEndOfDay(today)) ,应该说if(date >= getStartOfDay(today) && date < getStartOfDay(tomorrow)) 。 这是一个更坚实的定义(你不必担心毫秒精度)。

java.time

使用Java 8内置的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 

对于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)

补充@BasilBourque回答:

有点沉重,但安全的方法来设置一个最小的时间(只为开始):

 cal.setTime(...); cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY)); cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE)); cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND)); cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND)); 

这确保了最小值是日历的最小值。

我知道这是一个古老的问题,但这是我的主张,希望这可以帮助你:

  • 使用JodaTime,我们可以做到这一点:

      public static final Integer CURRENT_YEAR = DateTime.now()。getYear();
    
     public static final Integer CURRENT_MONTH = DateTime.now()。getMonthOfYear();
    
     public static final Integer CURRENT_DAY = DateTime.now()。getDayOfMonth();
    
     public static final Integer LAST_HOUR_OF_CURRENT_DAY = DateTime.now()。hourOfDay()。getMaximumValue();
    
     public static final Integer FIRST_HOUR_OF_CURRENT_DAY = DateTime.now()。hourOfDay()。getMinimumValue();
    
     public static final Integer LAST_MINUTE_OF_CURRENT_HOUR = DateTime.now()。minuteOfHour()。getMaximumValue();
    
     public static final Integer FIRST_MINUTE_OF_CURRENT_HOUR = DateTime.now()。minuteOfHour()。getMinimumValue();
    
     public static final Integer LAST_SECOND_OF_CURRENT_MINUTE = DateTime.now()。secondOfMinute()。getMaximumValue();
    
     public static final Integer FIRST_SECOND_OF_CURRENT_MINUTE = DateTime.now()。secondOfMinute()。getMinimumValue(); 
 public static DateTime getFirstDateOfDay(){
        返回新的DateTime(CURRENT_YEAR,CURRENT_MONTH,CURRENT_DAY,
                 FIRST_HOUR_OF_CURRENT_DAY,FIRST_MINUTE_OF_CURRENT_HOUR,
                 FIRST_SECOND_OF_CURRENT_MINUTE);
     }

     public static DateTime getLastDateOfDay(){
        返回新的DateTime(CURRENT_YEAR,CURRENT_MONTH,CURRENT_DAY,
                 LAST_HOUR_OF_CURRENT_DAY,LAST_MINUTE_OF_CURRENT_HOUR,
                 LAST_SECOND_OF_CURRENT_MINUTE);
     } 

正如我在github上的一些小技巧所描述的那样: joda时间,java8date时间(utils)

 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查找开始date的其他方法java.time.ZonedDateTime而不是通过LocalDateTime只是将inputZonedDateTime截断为DAYS:

 zonedDateTimeInstance.truncatedTo( ChronoUnit.DAYS ); 

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

 Date d= new Date(); GregorianCalendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC")); String s_d=d.getYear()+"-"+(d.getMonth()+1)+"-"+d.getDay(); DateFormat dateFormat = DateFormat.getDateInstance(); try { // for the end of day : c.setTime(dateFormat.parse(s_d+" 23:59:59")); // for the start of day: //c.setTime(dateFormat .parse(s_d+" 00:00:00")); } catch (ParseException e) { e.printStackTrace(); }