How can I add business days to the current date in Java?

后端 未结 14 1354
Happy的楠姐
Happy的楠姐 2020-12-03 02:05

How can I add business days to the current date in Java?

public Calendar addBusinessDate(Calendar cal, int days) {
//
// code goes over here
//
}


        
相关标签:
14条回答
  • 2020-12-03 02:24

    Most of the answer I've found online didn't work as expected, so I tweaked an example on this thread, How to get current date and add five working days in Java. The code below appears to work better.

    public static Date addWorkingDays(Date date, int days) {
        if (days > 0) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
    
            int daysAdded = 0;
            do {
                cal.add(Calendar.DATE, 1);
                if (isWorkingDay(cal)) {
                    daysAdded++;
                }
            } while (daysAdded < days);
    
            return cal.getTime();;
        } else {
            return date;
        }
    }
    
    
     private static boolean isWorkingDay(Calendar cal) {
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == Calendar.SUNDAY || dayOfWeek == Calendar.SATURDAY)
            return false;
        // tests for other holidays here        
        return true;
     }
    
    0 讨论(0)
  • 2020-12-03 02:27

    tl;dr

    Going forward.

    myLocalDate.with( 
        org.threeten.extra.Temporals.nextWorkingDay() 
    )
    

    Going backward.

    myLocalDate.with( 
        org.threeten.extra.Temporals.previousWorkingDay() 
    )
    

    Using java.time

    The Question and other Answers use the troublesome old date-time classes, now legacy, supplanted by the java.time classes.

    Also, see my Answer to a similar Question.

    TemporalAdjuster

    In java.time, the TemporalAdjuster interface provides for classes to manipulate date-time values. Using immutable objects, a new instance is created with values based on the original.

    nextWorkingDay

    The ThreeTen-Extra project extend java.time with additional functionality. That includes a nextWorkingDay adjuster that skips over Saturday and Sunday days. So we can loop, incrementing a date one day at a time, and skip over any weekend days.

    The LocalDate class represents a date-only value without time-of-day and without time zone.

    LocalDate start = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;
    int businessDaysToAdd = 13 ;
    // … ensure that: ( businessDaysToAdd >= 0 )
    
    int daysLeft = businessDaysToAdd ;
    LocalDate localDate = start ;
    while ( daysLeft > 0 ) {
        localDate = localDate.with( Temporals.nextWorkingDay() );
        daysLeft = ( daysLeft - 1 ) ;  // Decrement as we go.
    }
    return localDate ;
    

    Holidays

    Holidays are an entirely different matter. Obviously there is no simple solution. You must either supply a list of your honored holidays, or obtain a list with which you agree.

    Once you have such a list, I suggest writing your own implementation of TemporalAdjuster similar to nextWorkingDay.


    About java.time

    The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

    The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

    To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

    Where to obtain the java.time classes?

    • Java SE 8 and SE 9 and later
      • Built-in.
      • Part of the standard Java API with a bundled implementation.
      • Java 9 adds some minor features and fixes.
    • Java SE 6 and SE 7
      • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
    • Android
      • The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
      • See How to use ThreeTenABP….

    The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

    0 讨论(0)
  • 2020-12-03 02:28

    Will this work? Of course, this is not handling holidays.

    public static Date addBusinessDays(Date baseDate, int numberOfDays){

        if(baseDate == null){
            baseDate = new Date();
        }
    
        Calendar baseDateCal = Calendar.getInstance();
        baseDateCal.setTime(baseDate);
    
        for(int i = 0; i < numberOfDays; i++){
    
            baseDateCal.add(Calendar.DATE,1);
            if(baseDateCal.get(Calendar.DAY_OF_WEEK)
                             == Calendar.SATURDAY){
               baseDateCal.add(Calendar.DATE,2);
            }
        }
        return baseDateCal.getTime();
    }
    
    0 讨论(0)
  • 2020-12-03 02:38
    public static Date addBusinessDays(Date date, int days) {
    
        DateTime result = new DateTime(date);
        result = isWeekEnd(result)
            ? getPreviousBusinessDate(result)
            : result;
    
        for (int i = 0; i < days; i++) {
            if (isWeekEnd(result)) {
                i--;
            }
            result = result.plusDays(1);
        }
        return result.toDate();
    }
    
    private static boolean isWeekEnd(DateTime dateTime) {
        int dayOfWeek = dateTime.getDayOfWeek();
        return dayOfWeek == DateTimeConstants.SATURDAY || dayOfWeek == DateTimeConstants.SUNDAY;
    }
    
    private static DateTime getPreviousBusinessDate(DateTime result) {
        while (isWeekEnd(result)) {
            result = result.minusDays(1);
        }
    
        return result;
    }
    
    0 讨论(0)
  • 2020-12-03 02:40

    O(1) version that works and supports different weekend patterns and negative days:

    import java.util.Calendar;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    
    public class DateUtil {
    
    //Weekend patterns
    public static  final int WEEKEND_SAT_SUN = 0;
    public static  final int WEEKEND_FRI_SAT = 1;
    public static  final int WEEKEND_THU_FRI = 2;
    public static  final int WEEKEND_FRI_SUN = 3;
    public static  final int WEEKEND_FRI = 4;
    public static  final int WEEKEND_SAT = 5;
    public static  final int WEEKEND_SUN = 6;
    
    
    //Weekend pattern by country 
    //@see https://en.wikipedia.org/wiki/Workweek_and_weekend
    public static Map<String,Integer> weekendPatternByCountry = new HashMap<>();
    static {
        weekendPatternByCountry.put("CO",WEEKEND_SUN);     //Colombia
        weekendPatternByCountry.put("GQ",WEEKEND_SUN);     //Equatorial Guinea
        weekendPatternByCountry.put("IN",WEEKEND_SUN);     //India
        weekendPatternByCountry.put("MX",WEEKEND_SUN);     //Mexico
        weekendPatternByCountry.put("KP",WEEKEND_SUN);     //North Korea
        weekendPatternByCountry.put("UG",WEEKEND_SUN);     //Uganda
        weekendPatternByCountry.put("BN",WEEKEND_FRI_SUN); //Brunei Darussalam
        weekendPatternByCountry.put("DJ",WEEKEND_FRI);     //Djibouti
        weekendPatternByCountry.put("IR",WEEKEND_FRI);     //Iran
        weekendPatternByCountry.put("AF",WEEKEND_THU_FRI); //Afghanistan
        weekendPatternByCountry.put("NP",WEEKEND_SAT);     //Nepal
        weekendPatternByCountry.put("DZ",WEEKEND_FRI_SAT); //Algeria
        weekendPatternByCountry.put("BH",WEEKEND_FRI_SAT); //Bahrain
        weekendPatternByCountry.put("BD",WEEKEND_FRI_SAT); //Bangladesh
        weekendPatternByCountry.put("EG",WEEKEND_FRI_SAT); //Egypt
        weekendPatternByCountry.put("IQ",WEEKEND_FRI_SAT); //Iraq
        weekendPatternByCountry.put("IL",WEEKEND_FRI_SAT); //Israel
        weekendPatternByCountry.put("JO",WEEKEND_FRI_SAT); //Jordan
        weekendPatternByCountry.put("KW",WEEKEND_FRI_SAT); //Kuwait
        weekendPatternByCountry.put("LY",WEEKEND_FRI_SAT); //Libya
        weekendPatternByCountry.put("MV",WEEKEND_FRI_SAT); //Maldives
        weekendPatternByCountry.put("MR",WEEKEND_FRI_SAT); //Mauritania
        weekendPatternByCountry.put("MY",WEEKEND_FRI_SAT); //Malaysia
        weekendPatternByCountry.put("OM",WEEKEND_FRI_SAT); //Oman
        weekendPatternByCountry.put("PS",WEEKEND_FRI_SAT); //Palestine
        weekendPatternByCountry.put("QA",WEEKEND_FRI_SAT); //Qatar
        weekendPatternByCountry.put("SA",WEEKEND_FRI_SAT); //Saudi Arabia
        weekendPatternByCountry.put("SD",WEEKEND_FRI_SAT); //Sudan
        weekendPatternByCountry.put("SY",WEEKEND_FRI_SAT); //Syria
        weekendPatternByCountry.put("AE",WEEKEND_FRI_SAT); //United Arab Emirates
        weekendPatternByCountry.put("YE",WEEKEND_FRI_SAT); //Yemen
    }
    
    //Adjustment vectors - precomputed adjustment
    static int[][][] adjVector = new int[][][]{
        {//WEEKEND_SAT_SUN
            //Positive number of days
            {1,0,-1,-2,-3,1,1},
            {0,0},
            {0,0,0,0,0,2,1},
            //Negative number of days
            {-1,3,2,1,0,-1,-1},
            {0,0},
            {-1,1,1,1,1,1,0}
        },
        {//WEEKEND_FRI_SAT
            //Positive number of days
            {0,-1,-2,-3,1,1,1},
            {0,0},
            {0,0,0,0,2,1,0},
            //Negative number of days
            {3,2,1,0,-1,-1,-1},
            {0,0},
            {1,1,1,1,1,0,-1}
        },
        {//WEEKEND_THU_FRI
            //Positive number of days
            {-1,-2,-3,1,1,1,0},
            {0,0},
            {0,0,0,2,1,0,0},
            //Negative number of days
            {2,1,0,-1,-1,-1,3},
            {0,0},
            {1,1,1,1,0,-1,1}
        },
        {//WEEKEND_FRI_SUN
            //Positive number of days
            {0,-1,-2,-3,-4,-4,0},
            {1,0},
            {0,0,0,0,0,-1,1},
            //Negative number of days
            {4,3,2,1,0,0,4},
            {0,-1},
            {1,1,1,1,1,0,2}
        },
        {//WEEKEND_FRI
            //Positive number of days
            {-1,-2,-3,-4,1,1,0},
            {0},
            {0,0,0,0,1,0,0},
            //Negative number of days
            {3,2,1,0,-1,-1,4},
            {0},
            {1,1,1,1,1,0,1}
        },
        {//WEEKEND_SAT
            //Positive number of days
            {0,-1,-2,-3,-4,1,1},
            {0},
            {0,0,0,0,0,1,0},
            //Negative number of days
            {4,3,2,1,0,-1,-1},
            {0},
            {1,1,1,1,1,1,0}
        },
        {//WEEKEND_SUN
            //Positive number of days
            {1,0,-1,-2,-3,-4,1},
            {0},
            {0,0,0,0,0,0,1},
            //Negative number of days
            {-1,4,3,2,1,0,-1},
            {0},
            {0,1,1,1,1,1,1}
        }
    };
    
    //O(1) algorithm to add business days.
    public static Date addBusinessDays(Date day, int days,int weekendPattern){
        Calendar ret = Calendar.getInstance();
        if(day != null) {
            ret.setTime(day);
        }
        if(days != 0) {
            int startDayofWeek  = ret.get(Calendar.DAY_OF_WEEK)-1; //Zero based to use the vectors bellow.
            int idx = days > 0 ? 0 : 3;
            int howManyWeekendDays = 0;
            int[][] adjV = adjVector[weekendPattern];
            int numWeekendDaysInOneWeek = adjV[idx+1].length;
    
            for(int i  = 0; i < numWeekendDaysInOneWeek;i++){
                int adjustmentA = adjV[idx][startDayofWeek];  //pattern shift
                int adjustmentB = adjV[idx+1][i];             //day shift
    
                howManyWeekendDays += (days-adjustmentA-adjustmentB)/(7-numWeekendDaysInOneWeek); 
            }
    
            int adjustmentC = adjV[idx+2][startDayofWeek]; //f(0) adjustment
            howManyWeekendDays += adjustmentC;
    
            ret.add(Calendar.DATE,days + howManyWeekendDays);
    
            //TODO: Extend to support holidays using recursion
            // int numHolidays = getNumHolidaysInInterval(day,ret.getTime());
            // if(numHolidays > 0) return addBusinessDays(ret.getTime,numHolidays);
        }
        return ret.getTime();
    }
    
    public static Date addBusinessDays(Date day, int days,String country){
        Integer weekpat = weekendPatternByCountry.get(country);     
        return weekpat != null ? addBusinessDays(day,days,weekpat) : addBusinessDays(day,days,WEEKEND_SAT_SUN);
    }
    }
    
    0 讨论(0)
  • 2020-12-03 02:42

    Here is the modified version to find date calculation.

    public  Calendar algorithm2(int businessDays){
        Calendar cal2 = Calendar.getInstance();
        Calendar cal = Calendar.getInstance(); 
        int totalDays= businessDays/5*7;
        int remainder = businessDays % 5;
        cal2.add(cal2.DATE, totalDays); 
    
        switch(cal.get(Calendar.DAY_OF_WEEK)){
            case 1:
                    break;
            case 2: 
                    break;
            case 3: 
                    if(remainder >3)
                    cal2.add(cal2.DATE,2);
                    break;
            case 4: 
                    if(remainder >2)
                    cal2.add(cal2.DATE,2);
                    break;
            case 5: 
                    if(remainder >1)
                    cal2.add(cal2.DATE,2);
                    break;
            case 6: 
                    if(remainder >1)
                    cal2.add(cal2.DATE,2);
                    break;
            case 7: 
                    if(remainder >1)
                    cal2.add(cal2.DATE,1);
                    break;
        }
    
        cal2.add(cal2.DATE, remainder); 
        return cal2;
    
    }
    
    0 讨论(0)
提交回复
热议问题