我试图通过忽略周末来获得两个特定时间实例之间的分钟数。这就是我所做的。
public static final List<Integer> NON_WORKING_DAYS;
static {
List<Integer> nonWorkingDays = new ArrayList<Integer>();
nonWorkingDays.add(Calendar.SATURDAY);
nonWorkingDays.add(Calendar.SUNDAY);
NON_WORKING_DAYS = Collections.unmodifiableList(nonWorkingDays);
}
public static int getMinsBetween(Date d1, Date d2, boolean onlyBusinessDays)
{
int minsBetween = (int)((d2.getTime() - d1.getTime()) / (1000 * 60));
int minsToSubtract = 0;
if(onlyBusinessDays){
Calendar dateToCheck = Calendar.getInstance();
dateToCheck.setTime(d1);
Calendar dateToCompare = Calendar.getInstance();
dateToCompare.setTime(d2);
//moving the first day of the week to Tues so that a Sat, sun and mon fall in the same week, easy to adjust dates
dateToCheck.setFirstDayOfWeek(Calendar.TUESDAY);
dateToCompare.setFirstDayOfWeek(Calendar.TUESDAY);
//moving the dates out of weekends
if(!isBusinessDay(dateToCheck, NON_WORKING_DAYS)){
dateToCheck.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
dateToCheck.set(Calendar.HOUR, 0);
dateToCheck.set(Calendar.MINUTE, 0);
dateToCheck.set(Calendar.SECOND, 0);
dateToCheck.set(Calendar.MILLISECOND, 0);
}
if(!isBusinessDay(dateToCompare, NON_WORKING_DAYS)){
dateToCompare.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
dateToCompare.set(Calendar.HOUR, 0);
dateToCompare.set(Calendar.MINUTE, 0);
dateToCompare.set(Calendar.SECOND, 0);
dateToCompare.set(Calendar.MILLISECOND, 0);
}
for(; dateToCheck.getTimeInMillis() < dateToCompare.getTimeInMillis() ; dateToCheck.add(Calendar.DAY_OF_MONTH, 1)){
if(isBusinessDay(dateToCheck, NON_WORKING_DAYS)){
minsToSubtract = minsToSubtract + 1440;
}
}
minsBetween = minsBetween - minsToSubtract;
}
return minsBetween;
}
private static boolean isBusinessDay(Calendar dateToCheck, List<Integer> daysToExclude){
for(Integer dayToExclude : daysToExclude){
if(dayToExclude != null && dayToExclude == dateToCheck.get(Calendar.DAY_OF_WEEK)) {
return true;
}
else continue;
}
return false;
}
有人可以告诉我,如果我的逻辑是正确的,如果不是,如何做到这一点?我不太确定这个代码在月末周末变化时的行为方式。
某些测试用例的预期输出:
答案 0 :(得分:2)
我强烈建议使用Joda-Time来处理有关Java中日期操作的任何事情,因为它提供了许多有用的函数来使代码更简单。
此代码使用JodaTime:
public static final List<Integer> NON_WORKING_DAYS;
static {
List<Integer> nonWorkingDays = new ArrayList<Integer>();
nonWorkingDays.add(DateTimeConstants.SATURDAY);
nonWorkingDays.add(DateTimeConstants.SUNDAY);
NON_WORKING_DAYS = Collections.unmodifiableList(nonWorkingDays);
}
public static Minutes getMinsBetween(DateTime d1, DateTime d2,
boolean onlyBusinessDays) {
BaseDateTime startDate = onlyBusinessDays && !isBusinessDay(d1) ?
new DateMidnight(d1) : d1;
BaseDateTime endDate = onlyBusinessDays && !isBusinessDay(d2) ?
new DateMidnight(d2) : d2;
Minutes minutes = Minutes.minutesBetween(startDate, endDate);
if (onlyBusinessDays) {
DateTime d = new DateTime(startDate);
while (d.isBefore(endDate)) {
if (!isBusinessDay(d)) {
Duration dayDuration = new Duration(d, d.plusDays(1));
minutes = minutes.minus(int) dayDuration.getStandardMinutes());
}
d = d.plusDays(1);
}
}
return minutes;
}
private static boolean isBusinessDay(DateTime dateToCheck) {
return !NON_WORKING_DAYS.contains(dateToCheck.dayOfWeek().get());
}
测试此代码时,会产生以下结果:
DateTime d1 = new DateTime(2013, 1, 4, 18, 0); // a Friday, 6 pm
DateTime d2 = new DateTime(2013, 1, 7, 6, 0); // the following Monday, 6 am
Minutes minutes = getMinsBetween(d1, d2, true);
System.out.println(minutes.toStandardHours().getHours()); // outputs "12" (in hours)
d1 = new DateTime(2013, 1, 5, 12, 0); // a Saturday, 12 pm
d2 = new DateTime(2013, 1, 6, 12, 0); // the following Sunday, 12 pm
minutes = getMinsBetween(d1, d2, true);
System.out.println(minutes.toStandardHours().getHours()); // outputs "0" (in hours)
d1 = new DateTime(2013, 1, 5, 12, 0); // a Saturday, 12 pm
d2 = new DateTime(2013, 1, 7, 6, 0); // the following Monday, 6 am
minutes = getMinsBetween(d1, d2, true);
System.out.println(minutes.toStandardHours().getHours()); // outputs "6" (in hours)
我刚刚测试了一个月份周末变化的案例:从3月29日星期五(下午6点)到4月1日星期一(早上6点):
d1 = new DateTime(2013, 3, 29, 18, 0);
d2 = new DateTime(2013, 4, 1, 6, 0);
minutes = getMinsBetween(d1, d2, true);
System.out.println(minutes.toStandardHours().getHours());
结果是12小时,因此适用于月份更改。
我的第一个解决方案是没有正确处理夏令时。我们必须在减去分钟数时确定每个实际日期的持续时间,因为夏令时变化的天数不会是24小时:
if (!isBusinessDay(d)) {
Duration dayDuration = new Duration(d, d.plusDays(1));
minutes = minutes.minus(int) dayDuration.getStandardMinutes());
}
答案 1 :(得分:1)
JodaTime是要走的路,所以@KatjaChristiansen走在正确的轨道上。 如果您需要使用Java日历,我的解决方案将如下所示:
private static final long MILLIS_OF_WEEK = TimeUnit.DAYS.toMillis(7);
private static final long MILLIS_OF_WORKWEEK = TimeUnit.DAYS.toMillis(5);
public static int getMinsBetween(Date d1, Date d2, boolean onlyBusinessDays) {
long duration = d2.getTime() - d1.getTime();
if (onlyBusinessDays) {
Date sat = toSaturdayMidnight(d1);
long timeBeforeWeekend = Math.max(sat.getTime() - d1.getTime(), 0);
if (duration > timeBeforeWeekend) {
Date mon = toMondayMidnight(d2);
long timeAfterWeekend = Math.max(d2.getTime() - mon.getTime(), 0);
long numberOfWeekends = Math.max((duration / MILLIS_OF_WEEK) - 1, 0);
duration = numberOfWeekends * MILLIS_OF_WORKWEEK + timeBeforeWeekend + timeAfterWeekend;
}
}
return (int) TimeUnit.MILLISECONDS.toMinutes(duration);
}
private static Date toMondayMidnight(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
switch (cal.get(Calendar.DAY_OF_WEEK)) {
case Calendar.SATURDAY:
case Calendar.SUNDAY:
cal.add(Calendar.DAY_OF_MONTH, 7);
}
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
toMidnight(cal);
return cal.getTime();
}
private static Date toSaturdayMidnight(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
toMidnight(cal);
return cal.getTime();
}
private static void toMidnight(Calendar cal) {
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
}
这些测试通过:
@Test
public void testWithinSameDay() {
assertMinsBetween(30, "2013-01-03 9:00", "2013-01-03 9:30");
}
@Test
public void testOverWeekend() {
assertMinsBetween(60, "2013-01-04 23:30", "2013-01-07 0:30");
}
@Test
public void testWeekendStart() {
assertMinsBetween(30, "2013-01-05 23:30", "2013-01-07 0:30");
}
@Test
public void testTwoWeeks() {
assertMinsBetween((int) TimeUnit.DAYS.toMinutes(10), "2013-01-08 23:30", "2013-01-22 23:30");
}
@Test
public void testTwoWeeksAndOneDay() {
assertMinsBetween((int) TimeUnit.DAYS.toMinutes(11), "2013-01-08 23:30", "2013-01-23 23:30");
}
@Test
public void testOneWeekMinusOneDay() {
assertMinsBetween((int) TimeUnit.DAYS.toMinutes(4), "2013-01-09 23:30", "2013-01-15 23:30");
}
private void assertMinsBetween(int expected, String start, String end) {
try {
assertEquals(expected, getMinsBetween(FORMAT.parse(start), FORMAT.parse(end), true));
}
catch (ParseException e) {
throw new IllegalStateException(e);
}
}