2017-11-15 16 views
2

指定された2つの日付の間の営業日数を計算する必要があります
私は休暇のリストをユーザーから提供された配列リストとして持っています。
は、だから私は日付の間のそれぞれと毎日を調査し、その曜日及びません(正常に動作している)私は、以下の提供されたコードのような連邦休日かどうかを確認2つの日付間の営業日数を計算します

しかし、これは非常に高価であることができ、12回の連邦休日を言うことができますし、毎週私は週末でないことを確認する必要があります
もし私が5年の間に数える必要があれば、365 * 5 * 12の21,000回の反復が必要です!そのクレイジー(営業日の計算も含まれません)
良い方法はありますか?

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)); 
    } 

} 
+1

これは何のループを使用していないため、指数関数的にランタイムで高い取得していないとして、私は考えていない、あなたに役立つかもしれない:https://stackoverflow.com/a/4600534/1932789 – zack6849

+1

同様質問が何度か尋ねられています。あなたは見ましたか?私はこれが正確な複製であると確信していると言っているわけではありませんが、検索するとインスピレーションを得ることができます。 –

+1

[Javaで2つの異なる日付の間の作業(週末を除く)の日数を計算する方法]をご覧ください(https://stackoverflow.com/questions/32758569/how-to-calculate-weeks-execluding-weekends- 2日間の差異 - d) [週末のJavaを除く2つの日付間の日数を計算する方法](https://stackoverflow.com/questions/18354727/how-to-calculate-number-of-days-between-two-dates-excluding-weekend-java ); [Javaの2つの日付の間の平日の数を計算する](https://stackoverflow.com/questions/4600034/calculate-number-of-weekdays-between-two-dates-in-java) –

答えて

1

ここには、Java 8で実装されたjava.time.*の回答があります。

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; 
    } 
} 
+0

ありがとう、あなたはHOLIDAYS.containsの複雑さは何ですか? – user648026

+1

'HashSet#contains'はここではO(1)です。なぜなら、検索は' LocalDate'のハッシュコードに基づいており、反復に基づいているわけではないからです。詳細については、この記事を参照してください:https://stackoverflow.com/questions/25247854 –

1

2つの日付の間に何平日があるかを計算するためのコメントには、すでに多くの例があります。

連邦の休暇を引くまでは、元の日付の範囲内のすべての日をループするのではなく、あなたのfromDate-toDateの範囲で1年に1回、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--; 
    } 
} 
  • getWeekdayCountは:範囲内の平日のあなたのすべてを取得します。
  • getIndexFirstHoliday:あなたのfederalHolidays配列をループし、日付がgetIndexLastHoliday
  • fromDateからより大きい最初のインデックスを返します(後方)あなたのfederalHolidays配列をループし、日付がtoDateまでよりも小さくなっている最後のインデックスを返します。
  • isWeekday:日付はあなたがをループしている年で平日であれば、この方法で

(!それがあるならば、まだ私たちが減算する必要はありませんgetWeekdayCountで廃棄されています)を決定します最初のインデックスと最後のインデックスを取得するために、毎年最大12回ループしています。

+0

このAPIはどこにありますか? getIndexFirstHoliday etc – user648026

関連する問題