How would I add only business days to an NSDate?

前端 未结 4 1379
难免孤独
难免孤独 2021-02-04 18:55

I have an issue related to calculating business days in Objective-C.

I need to add X business days to a given NSDate.

For example, if

4条回答
  •  伪装坚强ぢ
    2021-02-04 19:54

    I took @steve's answer and added a method to calculate the days of all the federal holidays in USA and put it all in a Category. I've tested it and it works nicely. Check it out.

    #import "NSDate+BussinessDay.h"
    
    @implementation NSDate (BussinessDay)
    
    -(NSDate *)addBusinessDays:(int)daysToAdvance{
        NSDate * end = self;
        NSArray *holidays = [self getUSHolidyas];
        for (int i = 0; i < daysToAdvance; i++)
        {
            // Move the date forward by one day:
            end = [self addDays:1 toDate:end];
    
            // If the current date is a weekday, advance:
            end = [self ensureDateIsWeekday:end];
    
            // If the current date is a holiday, advance:
            end = [self ensureDateIsntHoliday:end forHolidays:holidays];
        }
    
        return end;
    }
    
    #pragma mark - Bussiness Days Calculations
    
    -(BOOL)isWeekday:(NSDate *) date{
        int day = (int)[[[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:date] weekday];
    
        const int kSunday = 1;
        const int kSaturday = 7;
    
        BOOL isWeekdayResult = day != kSunday && day != kSaturday;
        return isWeekdayResult;
    }
    
    -(NSDate *)addDays:(int)days toDate:(NSDate *)date{
        NSDateComponents * components = [[NSDateComponents alloc] init];
        [components setDay:days];
    
        NSDate * result = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:date options:0];
        return result;
    }
    
    -(NSDate *)ensureDateIsWeekday:(NSDate *)date{
        while (![self isWeekday:date])
        {
            // Add one day to the date:
            date = [self addDays:1 toDate:date];
        }
    
        return date;
    }
    
    -(BOOL)isHoliday:(NSDate *)date forHolidays:(NSArray *)holidays{
        BOOL isHolidayResult = NO;
    
        const unsigned kUnits = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
        NSDateComponents * components = [[NSCalendar currentCalendar] components:kUnits fromDate:date];
    
        for (int i = 0; i < [holidays count]; i++)
        {
            NSDate * holiday = [holidays objectAtIndex:i];
            NSDateComponents * holidayDateComponents = [[NSCalendar currentCalendar] components:kUnits fromDate:holiday];
    
            if ([components year] == [holidayDateComponents year]
                && [components month] == [holidayDateComponents month]
                && [components day] == [holidayDateComponents day])
            {
                isHolidayResult = YES;
                break;
            }
        }
    
        return isHolidayResult;
    }
    
    -(NSDate *)ensureDateIsntHoliday:(NSDate *)date forHolidays:(NSArray *)holidays{
        while ([self isHoliday:date forHolidays:holidays])
        {
            // Add one day to the date:
            date = [self addDays:1 toDate:date];
        }
    
        return date;
    }
    
    -(NSArray *)getUSHolidyas{
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        formatter.dateFormat = @"yyyy";
    
        NSString *year = [formatter stringFromDate:[NSDate date]];
        NSString *nextYear = [formatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow:(60*60*24*365)]];
        formatter.dateFormat = @"M/d/yyyy";
    
        //Constant Holidays
        NSDate *newYearsDay = [formatter dateFromString:[NSString stringWithFormat:@"1/1/%@",nextYear]]; //Use next year for the case where we are adding days near end of december.
        NSDate *indDay = [formatter dateFromString:[NSString stringWithFormat:@"7/4/%@",year]];
        NSDate *vetDay = [formatter dateFromString:[NSString stringWithFormat:@"11/11/%@",year]];
        NSDate *xmasDay = [formatter dateFromString:[NSString stringWithFormat:@"12/25/%@",year]];
    
    
        //Variable Holidays
        NSInteger currentYearInt = [[[NSCalendar currentCalendar]
                                     components:NSYearCalendarUnit fromDate:[NSDate date]] year];
    
        NSDate *mlkDay = [self getTheNth:3 occurrenceOfDay:2 inMonth:1 forYear:currentYearInt];
        NSDate *presDay = [self getTheNth:3 occurrenceOfDay:2 inMonth:2 forYear:currentYearInt];
        NSDate *memDay = [self getTheNth:5 occurrenceOfDay:2 inMonth:5 forYear:currentYearInt]; // Let's see if there are 5 Mondays in May
        NSInteger month = [[[NSCalendar currentCalendar] components:NSYearCalendarUnit fromDate:memDay] month];
        if (month > 5) { //Check that we are still in May
            memDay = [self getTheNth:4 occurrenceOfDay:2 inMonth:5 forYear:currentYearInt];
        }
        NSDate *labDay = [self getTheNth:1 occurrenceOfDay:2 inMonth:9 forYear:currentYearInt];
        NSDate *colDay = [self getTheNth:2 occurrenceOfDay:2 inMonth:10 forYear:currentYearInt];
        NSDate *thanksDay = [self getTheNth:4 occurrenceOfDay:5 inMonth:11 forYear:currentYearInt];
    
        return @[newYearsDay,mlkDay,presDay,memDay,indDay,labDay,colDay,vetDay,thanksDay,xmasDay];
    }
    
    -(NSDate *)getTheNth:(NSInteger)n occurrenceOfDay:(NSInteger)day inMonth:(NSInteger)month forYear:(NSInteger)year{
    
        NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
    
        dateComponents.year = year;
        dateComponents.month = month;
        dateComponents.weekday = day; // sunday is 1, monday is 2, ...
        dateComponents.weekdayOrdinal = n; // this means, the first of whatever weekday you specified
        return [[NSCalendar currentCalendar] dateFromComponents:dateComponents];
    }
    
    @end
    

提交回复
热议问题