计算两个日期之间的小时数,不包括周末

你好我试图计算在24小时内发生在java中两个不同时间戳之间的小时数而不包括周末的问题。

String timestamp = rs.getString("timestamp"); String timeStamp = new SimpleDateFormat("yyyyMMddHH").format(new Date()); int currentTimeStamp = Integer.parseInt(timeStamp); String orderTime = timestamp.replace("-", ""); String[] splitTimestamp = orderTime.split(" "); String finalTimestamp = splitTimestamp[0] + splitTimestamp[1].substring(0,2); int orderTimeStamp = Integer.parseInt(finalTimestamp); 

这目前确实有效但包括周末。

如果有人能帮助我,我会非常感激。

这都是在东部时区完成的。 周末不需要或不需要假期。

我发现java.util.Calendar更干净,这是一个从3月1日(早上8点)到当前时间的小时数:

 final Calendar first = new Calendar.Builder() .setDate(2016, 2, 1).set(Calendar.AM_PM, 0).set(Calendar.HOUR, 8).build(); final Calendar second = Calendar.getInstance(); int numberOfDays = 0; long numberOfHours = 0; //Get number of full days while(first.get(Calendar.DATE) != second.get(Calendar.DATE)){ if(Calendar.SATURDAY != first.get(Calendar.DAY_OF_WEEK) && Calendar.SUNDAY != first.get(Calendar.DAY_OF_WEEK)){ numberOfDays++; } first.roll(Calendar.DATE, true); } //Get number of hours in the remaining day numberOfHours = TimeUnit.MILLISECONDS .toHours(second.getTimeInMillis() - first.getTimeInMillis()); System.out.println("Difference = " + ( numberOfDays * 24 + numberOfHours ) + " hour(s)"); 

避免旧的日期时间类

与最早版本的Java捆绑在一起的旧日期时间类设计糟糕,令人困惑且麻烦。 避免使用java.util.Date/.Calendar等。

java.time

使用Java 8及更高版本中内置的java.time框架。 或者它的Java 7和6的后端 。请参阅Oracle教程 。

我还没有尝试过运行此代码; 就在我的头顶。 从不运行,从未测试过。 可能会给你一个开始。

该问题似乎表明,我们希望假定通用的24小时工作日而不是实际工作日(由于诸如夏令时之类的exception,其长度会有所不同)。 在通用日的情况下,我们不关心时区。 我们可以使用LocalDateTime类。

如果开始恰好是周末,请将其移至下周​​一的第一个时刻。

 DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyyMMddHH" ); LocalDateTime start = LocalDateTime.parse( "2016010123" , formatter ); // If on a weekend, move to first moment of Monday. if( start.getDayOfWeek().equals( DayOfWeek.SATURDAY ) { start = start.plusDays( 2 ).toLocalDate().atStartOfDay(); } if( start.getDayOfWeek().equals( DayOfWeek.SUNDAY ) { start = start.plusDays( 1 ).toLocalDate().atStartOfDay(); } 

同样停止。 如果在周末,请转到下周一的第一时刻。

 LocalDateTime stop = LocalDateTime.parse( "2016010723" , formatter ); // If on a weekend, move to first moment of Monday. if( stop.getDayOfWeek().equals( DayOfWeek.SATURDAY ) { stop = stop.plusDays( 2 ).toLocalDate().atStartOfDay(); } if( stop.getDayOfWeek().equals( DayOfWeek.SUNDAY ) { stop = stop.plusDays( 1 ).toLocalDate().atStartOfDay(); } 

如果开始与停止相同,我们就完成了:报告零。

 if( start.isEqual( stop ) ) { return 0; } 

如果开始是在停止之后,我们有一个错误条件。 抛出exception,尝试纠正问题,或报告零,无论你的应用程序有什么意义。

 if( start.isAfter( stop ) ) { return 0; // Or consider it a problem, throw exception. } 

我们将这个问题分为三个部分:

  • 第一个部分日,
  • 最后的部分日,
  • 两者之间的整天数。

为了表示部分日期,我们使用Duration类。 Duration是一个跟踪的时间跨度,以秒为单位加上纳秒。

第一部分从第二天start到第一天开始。

 LocalDateTime firstMomentOfDayAfterStart = start.toLocalDate().plusDays(1).atStartOfDay(); Duration firstDayDuration = Duration.between( start , firstMomentOfDayAfterStart ); 

最后一个部分日从stop的同一天的第一个时刻开始。

 LocalDateTime firstMomentOfDayOfStop = stop.toLocalDate().atStartOfDay(); Duration lastDayDuration = Duration.between( firstMomentOfDayOfStop , stop ); 

我们可以将每个Duration转换为数小时。

 int hoursFirstDay = firstDayDuration.toHours(); int hoursLastDay = lastDayDuration.toHours(); 

因此,我们有定义这些时间跨度的变量,如下图所示。 请记住,这些是半开放的,每个跨度的结尾是独占的

 [ start > firstMomentOfDayAfterStart ][ firstMomentOfDayAfterStart > firstMomentOfDayOfStop ][ firstMomentOfDayOfStop > stop ] 

现在,在这对偏僻的日子之间循环整整一天。 每天递增,连续一天测试工作日或周末。 记住我们遇到的工作日。 使用方便的DayOfWeek 枚举进行比较。

 int countWeekdays = 0; LocalDateTime firstMomentOfSomeDay = firstMomentOfDayAfterStart while( firstMomentOfSomeDay.isBefore( firstMomentOfDayOfStop ) ) { DayOfWeek dayOfWeek = firstMomentOfSomeDay.getDayOfWeek(); if( dayOfWeek.equals( DayOfWeek.SATURDAY ) || dayOfWeek.equals( DayOfWeek.SUNDAY ) ) { // ignore this day. } else { countWeekdays ++ ; // Tally another weekday. } // Set up the next loop. firstMomentOfSomeDay = firstMomentOfSomeDay.plusDays( 1 ); } 

我们可以使用TimeUnit枚举将整天的计数转换为小时数。 此转换假设为24小时通用日。

 int hoursOfWholeDays = TimeUnit.DAYS.toHours( countWeekDays ) ; 

全部添加。

 int totalHours = ( hoursFirstDay + hoursOfWholeDays + hoursLastDay ) ; 

完成。 返回总小时数。

 return totalHours ; 

如果您的数据通常包含很长一段时间,那么您可以考虑通过检测星期一和计算整周数来优化性能。 我假设在业务场景中跟踪订单,间隔时间很短。 所以这种优化不太可能很重要。

EnumSet

你可以替换这行:

 if( dayOfWeek.equals( DayOfWeek.SATURDAY ) || dayOfWeek.equals( DayOfWeek.SUNDAY ) )… 

…使用EnumSet

 Set weekend = EnumSet.of( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY ) ; … if( weekend.contains( dayOfWeek ) ) … 

时间调节器

有关使用Temporals类的nextWorkingDaypreviousWorkingDay方法检测周末的更多信息,请参阅我对另一个问题的回答 。 这个类位于扩展java.time框架的ThreeTen-Extra项目中。

此外,该类文档表明,编写自己的时态调整器以适合您的特定业务规则相对容易。

你可以这样做:

  Date date1 = new Date(2016, 3, 21), date2 = new Date(2016, 4, 9); int oneHour = 1000 * 60 * 60; //Note that this rounds down the number of hours/days int hours = (int)((date2.getTime() - date1.getTime()) / oneHour); int days = hours / 24; int day1, day2; //set the values of day: [Sun=0, Mon=1, Tue=2, Wed=3, Thur=4, Fri=5, Sat=6] //date.getDay() is supposed to do that, but it's deprecated int nWEdays = days/7*2; if(day2-day1 < 0) nWEdays += 2; else { if(day1 == 0 || day1 == 6) nWEdays++; else if(day2 == 0 || day2 == 6) nWEdays++; } int weekendHours = hours - nWEdays*24;