I do not exhaustively test this, but it is based on some category methods that I use regularly. To determine how many weekdays are between date1 and date2 (takes date1 and lt2), divide the return value of this function by 24 * 60 * 60 (number of seconds per day).
This breaks down the calculation by the number of days before the first weekend, the number of days after the last weekend, and the number of days in the intervening weeks. Weekends begin on Saturday at 00:00:00 and end on Sunday at 23:59:59. As a rule, you want to avoid the assumption that he has 24 hours during the day, because there may be special cases associated with daylight saving time. Therefore, I recommend using NSCalendar to calculate time intervals when it matters. But this happens on weekends, so for this case it is not important.
There are two methods here. The first returns the end date of NSDate if you specify a start date and the number of working days (weekdays) that you want to extend. (An earlier date is returned if the number of working days is negative.) The second returns the number of seconds corresponding to the number of working days (including fractional days) between the two NSDate dates.
I tried to do the calculations in the time zone, but the system time zone was set by default. (By the way, if you want to calculate with fractional days, change the weekdays parameter to float. Or you can calculate using the parameter in seconds. If so, also change the calculation of totalInterval in the first way: you do not have to convert to seconds. All subsequent calculations this method executes in seconds.)
- (NSDate*) calculateWeekDaysEndDateFrom:(NSDate*)_date1 and:(int)weekdays { NSTimeInterval dayInterval = 24*60*60; NSTimeInterval totalInterval = dayInterval * (float) weekdays; NSTimeInterval secondsBeforeWeekend; NSTimeInterval secondsAfterWeekend; NSTimeInterval secondsInInterveningWeeks; int numberOfWeeks; NSDate *dateOfFirstSaturdayMorning; NSDate *dateOfLastSundayNight; NSDate *finalDate; if (weekdays >0) { dateOfFirstSaturdayMorning = [_date1 theFollowingWeekend]; secondsBeforeWeekend = [dateOfFirstSaturdayMorning timeIntervalSinceDate:_date1]; numberOfWeeks = (int)((totalInterval - secondsBeforeWeekend)/(5.0 * dayInterval)); secondsInInterveningWeeks = 5 * (float)(numberOfWeeks * dayInterval); secondsAfterWeekend = totalInterval - secondsBeforeWeekend - secondsInInterveningWeeks; dateOfLastSundayNight = [[dateOfFirstSaturdayMorning dateByAddingDays:7*numberOfWeeks+2] dateByAddingTimeInterval:-1];
Files for category methods in NSDate are NSDate + help.h
@interface NSDate (help) + (NSDate *) LSExtendedDateWithNaturalLanguageString:(NSString *)dateString WithFormatter:(NSDateFormatter*)dateFormatter; - (NSUInteger)ordinality; - (NSDate*) theFollowingWeekend; - (NSDate *) thePreviousWeekend; - (NSDate *) dateByAddingDays:(NSInteger) numberOfDays; - (NSDate *) dateByMovingToBeginningOfDayInTimeZone:(NSTimeZone*)tz; - (NSDate *) dateByMovingToEndOfDayInTimeZone:(NSTimeZone*)tz; @end
and NSDate + help.m
#import "NSDate+help.h" @implementation NSDate (help) // thrown in for testing + (NSDate *) LSExtendedDateWithNaturalLanguageString:(NSString *)dateString WithFormatter:(NSDateFormatter*)dateFormatter{ [dateFormatter setDateFormat:@"yyyy-MM-dd HHmm"]; [dateFormatter setLocale:[NSLocale currentLocale]]; //NSDate *formattedDate = [dateFormatter dateFromString:@"2008-12-3T22-11-30-123"]; return [dateFormatter dateFromString:dateString]; } - (NSUInteger)ordinality { NSCalendar *calendar = [NSCalendar currentCalendar]; [calendar setTimeZone:[NSTimeZone systemTimeZone]]; return [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSWeekCalendarUnit forDate:self]; } - (NSDate*) theFollowingWeekend { NSUInteger myOrdinality = [self ordinality]; NSDate *dateOfFollowingWeekend = [self dateByAddingDays:(7-myOrdinality)%7]; return [dateOfFollowingWeekend dateByMovingToBeginningOfDayInTimeZone:(NSTimeZone*)nil]; } - (NSDate *) thePreviousWeekend { NSUInteger myOrdinality = [self ordinality]; NSDate *dateOfPreviousWeekend = [self dateByAddingDays:(1-myOrdinality)]; return [dateOfPreviousWeekend dateByMovingToEndOfDayInTimeZone:(NSTimeZone*)nil]; } - (NSDate *) dateByAddingDays:(NSInteger) numberOfDays { NSDateComponents *dayComponent = [[NSDateComponents alloc] init]; dayComponent.day = numberOfDays; NSCalendar *theCalendar = [NSCalendar currentCalendar]; return [theCalendar dateByAddingComponents:dayComponent toDate:self options:0]; } - (NSDate *) dateByMovingToBeginningOfDayInTimeZone:(NSTimeZone*)tz { NSTimeZone *timezone; if (tz) timezone = tz; else timezone = [NSTimeZone systemTimeZone]; unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit; NSDateComponents* parts = [[NSCalendar currentCalendar] components:flags fromDate:self]; [parts setHour:0]; [parts setMinute:0]; [parts setSecond:0]; NSCalendar *calendar = [NSCalendar currentCalendar]; [calendar setTimeZone:timezone]; return [calendar dateFromComponents:parts]; } - (NSDate *)dateByMovingToEndOfDayInTimeZone:(NSTimeZone*)tz { NSTimeZone *timezone; if (tz) timezone = tz; else timezone = [NSTimeZone systemTimeZone]; unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit; NSDateComponents* parts = [[NSCalendar currentCalendar] components:flags fromDate:self]; [parts setHour:23]; [parts setMinute:59]; [parts setSecond:59]; NSCalendar *calendar = [NSCalendar currentCalendar]; [calendar setTimeZone:timezone]; return [calendar dateFromComponents:parts]; } @end
The ordinality category ordinality returns the ordinality number of the recipient. Sunday = 1, Saturday = 7. This is used to find out how many days are left until the end of the first week and how many days are left after the beginning of last week. (Calculations are done in seconds.)
The methods of theFollowingWeekend and thePreviousWeekend return the NSDate at midnight Saturday morning, which follows the date of the receiver and the NSDate one second before midnight on Sunday, which follows the date of the receiver. These methods assume that you have already confirmed that the recipient’s date is not on weekends. I processed this in basic methods. Look for ordinality checks == 1 or 7.
dateByMovingToBeginningOfDayInTimeZone: and dateByMovingToEndOfDayInTimeZone: set the hours, minutes and seconds of the receiver date at 00:00:00 and 23:59:59 respectively. This is to distinguish between days off from midnight Saturday morning to midnight Sunday evening in the time zone.
Hope this helps. It was an exercise for me to better understand the functionality of time and date.
I will be lending to Keith Lazuka and its iPhone calendar component for the germination of this code.
Here is a snapshot of the user interface of the test program that uses these features: 
Here is your example, skip the first method. Items of interest are highlighted.
. To do this, I made a simple modification to accept fractional days (which I mentioned above, but did not include in the code shown above)