计算两个日期之间的小时数,不包括周末
你好我试图计算在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
类的nextWorkingDay
和previousWorkingDay
方法检测周末的更多信息,请参阅我对另一个问题的回答 。 这个类位于扩展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;