Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 计算两个日期之间的工作日数_Java_Date - Fatal编程技术网

Java 计算两个日期之间的工作日数

Java 计算两个日期之间的工作日数,java,date,Java,Date,我需要计算两个给定日期之间的工作日数 我将假期列表作为用户提供的数组列表。 因此,我可以调查日期之间的每一天,并检查其是否为工作日,而不是像我下面提供的代码那样的联邦假日(工作正常) 但这是非常昂贵的,比如说12个联邦假日,每天我都要检查,而不是周末, 因此,如果我需要计算5年,它将需要365*5*12及其21000次迭代!这太疯狂了(甚至不包括工作日的计算) 有更好的办法吗 package test; import java.text.DateFormat; import java.text

我需要计算两个给定日期之间的工作日数
我将假期列表作为用户提供的数组列表。
因此,我可以调查日期之间的每一天,并检查其是否为工作日,而不是像我下面提供的代码那样的联邦假日(工作正常)

但这是非常昂贵的,比如说12个联邦假日,每天我都要检查,而不是周末,
因此,如果我需要计算5年,它将需要365*5*12及其21000次迭代!这太疯狂了(甚至不包括工作日的计算)
有更好的办法吗

package test;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.time.DateUtils;

public class TestDiff {

    public static void main(String[] args) throws ParseException {
        DateFormat formatter = new SimpleDateFormat("MM/dd/yy");
        // add 4 years as an example
        Date fromDate = formatter.parse("11/06/2017"),toDate = formatter.parse("11/29/2017");// DateUtils.addDays(fromDate,365 * 4);
        int numberOfDaysCount=0;
        int daysBetween  = daysBetween(fromDate,toDate);
        Date caurDate = fromDate;

        for(int i=0;i<=daysBetween ; i++ ) {
            if(isWeekDay(caurDate) && !isFederalHoliday(caurDate) )
                numberOfDaysCount++;
            caurDate = DateUtils.addDays(caurDate,1); // add one day
        }
        System.out.println("number of business days between "+fromDate+" and "+toDate+" is: "+numberOfDaysCount);
    }

   private static boolean isWeekDay(Date caurDate) {
             Calendar c = Calendar.getInstance();
             c.setTime(caurDate);
              int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
              return dayOfWeek!= Calendar.SATURDAY && dayOfWeek!= Calendar.SUNDAY ;
    }

        private static boolean isFederalHoliday(Date caurDate) throws ParseException {
            DateFormat formatter = new SimpleDateFormat("MM/dd/yy");    //list will come from dao.getFederalHoliday();
                List<Date> federalHolidays =  Arrays.asList(formatter.parse("01/02/2017"),formatter.parse("01/16/2017"),formatter.parse("02/20/2017"),formatter.parse("05/29/2017"),formatter.parse("07/04/2017"),formatter.parse("09/04/2017"),formatter.parse("10/09/2017"),formatter.parse("07/04/2017"),formatter.parse("11/10/2017"),formatter.parse("11/23/2017"),formatter.parse("12/25/2017"));
                for (Date holiday : federalHolidays) {
                    if(DateUtils.isSameDay(caurDate,holiday)) //using Apache commons-lang 
                        return true;
                }
                return false;
    }

        public static int daysBetween(Date d1, Date d2){
             return (int)( (d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24));
     }

}
封装测试;
导入java.text.DateFormat;
导入java.text.ParseException;
导入java.text.simpleDataFormat;
导入java.util.array;
导入java.util.Calendar;
导入java.util.Date;
导入java.util.List;
导入org.apache.commons.lang3.time.DateUtils;
公共类TestDiff{
公共静态void main(字符串[]args)引发异常{
DateFormat格式化程序=新的SimpleDateFormat(“MM/dd/yy”);
//以4年为例
日期fromDate=formatter.parse(“2017年6月11日”),toDate=formatter.parse(“2017年11月29日”);//DateUtils.addDays(fromDate,365*4);
int numberofdaysunt=0;
int daysBetween=daysBetween(从日期到日期);
日期尾日期=起始日期;

对于(int i=0;i,注释中已经给出了许多示例,用于计算两个日期之间的工作日数

就减去联邦假日而言。与其在fromdate-todate范围内的所有日期上循环,不如在fromdate-todate范围内每年循环一次federalHoliday数组中的所有条目

请原谅伪代码:

int workdays = getWeekdayCount();
for(int i = 0, count = getYearsBetween(); i < count; ++i)
{
    startIndex = (i==0?getIndexFirstHoliday():0);
    endIndex   = (i==(count-1)?getIndexLastHoliday():11);
    for(; startIndex <= endIndex; ++startIndex)
    {
        if(!federalHolidays[startIndex].IsWeekday(count))
            workdays--;
    }
}
int workdays=getWeekdayCount();
for(int i=0,count=getYearsBetween();i对于(;startIndex,这里有一个答案是使用
Java.time.*
在Java8中实现的

public class TestSo47314277 {

  /**
   * A set of federal holidays. Compared to iteration, using a
   * hash-based container provides a faster access for reading
   * element via hash code. Using {@link Set} avoids duplicates.
   * <p>
   * Add more dates if needed.
   */
  private static final Set<LocalDate> HOLIDAYS;

  static {
    List<LocalDate> dates = Arrays.asList(
        LocalDate.of(2017, 1, 2),
        LocalDate.of(2017, 1, 16),
        LocalDate.of(2017, 2, 20),
        LocalDate.of(2017, 5, 29),
        LocalDate.of(2017, 7, 4),
        LocalDate.of(2017, 9, 4),
        LocalDate.of(2017, 10, 9),
        LocalDate.of(2017, 11, 10),
        LocalDate.of(2017, 11, 23),
        LocalDate.of(2017, 12, 25)
    );
    HOLIDAYS = Collections.unmodifiableSet(new HashSet<>(dates));
  }

  public int getBusinessDays(LocalDate startInclusive, LocalDate endExclusive) {
    if (startInclusive.isAfter(endExclusive)) {
      String msg = "Start date " + startInclusive
          + " must be earlier than end date " + endExclusive;
      throw new IllegalArgumentException(msg);
    }
    int businessDays = 0;
    LocalDate d = startInclusive;
    while (d.isBefore(endExclusive)) {
      DayOfWeek dw = d.getDayOfWeek();
      if (!HOLIDAYS.contains(d)
          && dw != DayOfWeek.SATURDAY
          && dw != DayOfWeek.SUNDAY) {
        businessDays++;
      }
      d = d.plusDays(1);
    }
    return businessDays;
  }
}
公共类测试SO47314277{
/**
*一组联邦假日。与迭代相比,使用
*基于散列的容器提供了更快的读取访问
*元素。使用{@link Set}可避免重复。
*
*如果需要,添加更多日期。
*/
私人假期;
静止的{
列表日期=Arrays.asList(
本地日期(2017年1月2日),
本地日期(2017年1月16日),
本地日期(2017年2月20日),
本地日期(2017年5月29日),
本地日期(2017年7月4日),
本地日期(2017年9月4日),
本地日期(2017年10月9日),
本地日期(2017年11月10日),
本地日期(2017年11月23日),
本地日期(2017年12月25日)
);
假日=集合。不可修改集(新哈希集(日期));
}
public int getBusinessDays(LocalDate startInclusive,LocalDate endExclusive){
if(起始结论性。isAfter(endExclusive)){
字符串msg=“开始日期”+开始结论
+“必须早于结束日期”+endExclusive;
抛出新的IllegalArgumentException(msg);
}
int businessDays=0;
LocalDate d=startInclusive;
while(d.isBefore(endExclusive)){
DayOfWeek dw=d.getDayOfWeek();
如果(!HOLIDAYS.contains(d)
&&dw!=星期六
&&dw!=星期天(星期日){
商业日报++;
}
d=d.plusDays(1);
}
返回工作日;
}
}

blow代码是我用java 8编写的完整项目,将解决您的问题

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class App {

    public static void main(String[] args) {

        System.out.println("Hello World!");
        LocalDate today = LocalDate.of(2020, 5, 5);

        // Add one holiday for testing
        List<LocalDate> holidays = new ArrayList<>();
        holidays.add(LocalDate.of(2020, 5, 11));
        holidays.add(LocalDate.of(2020, 5, 1));
        for (LocalDate x : BusinessDaysBetween(today, today.plusDays(20), Optional.empty()))
        {
            System.out.println(x.toString());
        }
    }
    private static List<LocalDate> BusinessDaysBetween(LocalDate startDate, LocalDate endDate,
                                            Optional<List<LocalDate>> holidays)
    {
        if (startDate == null || endDate == null || !holidays.isPresent()) {
            throw new IllegalArgumentException("Invalid method argument(s) to countBusinessDaysBetween(" + startDate
                    + "," + endDate + "," + holidays + ")");
        }

        Predicate<LocalDate> isHoliday = date -> holidays.map(localDates -> localDates.contains(date)).orElse(false);

        Predicate<LocalDate> isWeekend = date -> date.getDayOfWeek() == DayOfWeek.SATURDAY
                || date.getDayOfWeek() == DayOfWeek.SUNDAY;

        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);

        return Stream.iterate(startDate, date -> date.plusDays(1)).limit(daysBetween)
                .filter(isHoliday.or(isWeekend).negate()).collect(Collectors.toList());
    }
}
import java.time.DayOfWeek;
导入java.time.LocalDate;
导入java.time.temporal.ChronoUnit;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.Optional;
导入java.util.function.Predicate;
导入java.util.stream.collector;
导入java.util.stream.stream;
公共类应用程序{
公共静态void main(字符串[]args){
System.out.println(“你好,世界!”);
LocalDate today=LocalDate.of(2020,5,5);
//添加一个假期进行测试
列表假日=新建ArrayList();
添加(LocalDate.of(2020,5,11));
添加(LocalDate.of(2020,5,1));
for(LocalDate x:BusinessDaysBetween(今天,今天.plusDays(20),可选.empty())
{
System.out.println(x.toString());
}
}
私有静态列表BusinessDaysBetween(LocalDate startDate、LocalDate endDate、,
(可选假日)
{
if(startDate==null | | endDate==null | |!holidays.isPresent()){
向countBusinessDaysBetween(“+startDate”)抛出新的IllegalArgumentException(“无效的方法参数
+“,“+截止日期+”,“+节假日+”);
}
谓词isHoliday=date->holidays.map(localDates->localDates.contains(date)).orElse(false);
谓词为weekend=date->date.getDayOfWeek()==DayOfWeek.SATURDAY
||date.getDayOfWeek()=DayOfWeek.SUNDAY;
long daysBetween=计时单位天数介于(开始日期、结束日期)之间;
返回流.iterate(startDate,date->date.plusDays(1)).limit(daysBetween)
.filter(isHoliday.or(isWeekend.negate()).collect(Collectors.toList());
}
}

您可以执行以下操作,而不是反复检查每一天,检查它是否是一周而不是假日:

  • 获取两次约会之间的天数
  • 计算完整周数,计算潜在工作日数(乘以5)或要减去的周末数(乘以2)
  • 计算为部分周调整的周天数
  • 获取所需范围内的非周末假期数,然后减去这些假期数(对于
    n
    假期,每年最多只能进行
    n
    检查,甚至可以进行优化)
    //start is inclusive, end is exclusive
    public long getBusinessDays(LocalDate start, LocalDate end) {
      long days = ChronoUnit.DAYS.between(start, end);
    
      long fullWeeks = days/7;
    
      //day of week value ranges from 1 (Monday) to 7 (Sunday)
      //clamp Sunday to Saturday (so treat them as one day) - range is now 1 to 6
      //business days is the difference in days if dow(start) < dow(end)
      //if start and end are on a weekend we'll get 6-6 = 0
      long partialWeekAdjustment = Math.min(6, end.getDayOfWeek().getValue()) -  Math.min(6, start.getDayOfWeek().getValue() );
    
      //if the result is negative, we have dow(start) > dow(end) so add 5 business days
      //ex.: thu (4) to wed (3) will be 3-4 = -1, so adding 5 will result in 4 (thu, fri, mon, tue)
      if( partialWeekAdjustment < 0 ) {
        partialWeekAdjustment += 5;         
      }
    
      //get the number of non-weekend holidays between the 2 dates       
      long numNonWeekendHolidays = getNonWeekendHolidays(start, end);
    
      long businessDays = fullWeeks * 5 + partialWeekAdjustment - numNonWeekendHolidays;
      return businessDays;
    }
    
    private long getNonWeekendHolidays(LocalDate start, LocalDate end) {
       //get this from somewhere, could also be something else
       SortedSet<LocalDate> holidays = ...;
    
       //get holidays between the 2 dates, filter for non-weekend and count
       return holidays.subSet(start, end).stream()
                      .filter(d -> d.getDayOfWeek().compareTo(DayOfWeek.SATURDAY) < 0)
                      .count();
    
       //if weekend and non-weekend holidays are kept separate this could be:
       // SortedSet<LocalDate> nonWeekendHolidays = ...;
       // return nonWeekendHolidays.subSet(start, end).size();
    }