我如何仅向NSDate添加工作日?

mil*_*ari 6 objective-c core-foundation

我有一个与计算Objective-C中的工作日有关的问题.

我需要为X给定的工作日添加工作日NSDate.

例如,如果我有一个日期:2010年10月22星期五,我加上2个工作日,我应该得到:2010年10月26日星期二.

提前致谢.

Ste*_*eve 20

这有两个部分:

  • 周末
  • 假期

我要从其他两个帖子中拉出来帮助我.

对于周末,我需要知道一周中某个特定日期.为此,这篇文章派上用场: 如何查看一周中的哪一天(即星期二,星期五?)并比较两个NSDates?

对于假期,@ vikingosegundo对这篇文章提出了非常好的建议: 所有美国假期列表为NSDates

首先,让我们来处理周末;

我把上面引用的帖子中的建议结合到这个漂亮的小助手函数中,该函数告诉我们日期是否是工作日:

BOOL isWeekday(NSDate * date)
{
    int day = [[[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:date] weekday];

    const int kSunday = 1;
    const int kSaturday = 7;

    BOOL isWeekdayResult = day != kSunday && day != kSaturday;

    return isWeekdayResult;
}
Run Code Online (Sandbox Code Playgroud)

我们需要一种方法来将日期递增给定的天数:

NSDate * addDaysToDate(NSDate * date, int days)
{
    NSDateComponents * components = [[NSDateComponents alloc] init];
    [components setDay:days];

    NSDate * result = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:date options:0];

    [components release];

    return result;
}
Run Code Online (Sandbox Code Playgroud)

我们需要一种方法来跳过周末:

NSDate * ensureDateIsWeekday(NSDate * date)
{
    while (!isWeekday(date))
    {
        // Add one day to the date:
        date = addDaysToDate(date, 1);
    }

    return date;
}
Run Code Online (Sandbox Code Playgroud)

我们需要一种方法来为日期添加任意天数:

NSDate * addBusinessDaysToDate(NSDate * start, int daysToAdvance)
{
    NSDate * end = start;

    for (int i = 0; i < daysToAdvance; i++)
    {
        // If the current date is a weekend, advance:
        end = ensureDateIsWeekday(end);

        // And move the date forward by one day:
        end = addDaysToDate(end, 1);
    }

    // Finally, make sure we didn't end on a weekend:
    end = ensureDateIsWeekday(end);

    return end;
}
Run Code Online (Sandbox Code Playgroud)
  • 注意; 我跳过了一个明显的优化 - 您可以轻松地在当前日期添加超过一天 - 但我的帖子的目的是向您展示如何自己完成此操作 - 而不一定要提出最好的可能性解.

现在让我们把它绑起来看看到目前为止我们有什么:

int main() {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSDate * start = [NSDate date];
    int daysToAdvance = 10;

    NSDate * end = addBusinessDaysToDate(start, daysToAdvance);

    NSLog(@"Result: %@", [end descriptionWithCalendarFormat:@"%Y-%m-%d"
                                    timeZone:nil
                                      locale:nil]);

    [pool drain];

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

所以,我们有周末,现在我们需要拉假期.

拉入一些RSS提要或来自其他来源的数据肯定超出了我的帖子的范围......所以,我们假设您有一些您知道的假期日期,或者根据您的工作日历,这些日期是休假.

现在,我将使用NSArray来做这件事......但是,这仍然有很大的改进空间 - 至少它应该被排序.更好的是,某种哈希集用于快速查找日期.但是,这个例子应该足以解释这个概念.(这里我们构造一个数组,表明从现在起两到三天都有假期)

NSMutableArray * holidays = [[NSMutableArray alloc] init];
[holidays addObject:addDaysToDate(start, 2)];
[holidays addObject:addDaysToDate(start, 3)];
Run Code Online (Sandbox Code Playgroud)

并且,此实施将与周末非常相似.我们将确保这一天不是假期.如果是,我们将提前到第二天.所以,一组方法来帮助:

BOOL isHoliday(NSDate * date, 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;
}
Run Code Online (Sandbox Code Playgroud)

和:

NSDate * ensureDateIsntHoliday(NSDate * date, NSArray * holidays)
{
    while (isHoliday(date, holidays))
    {
        // Add one day to the date:
        date = addDaysToDate(date, 1);
    }

    return date;
}
Run Code Online (Sandbox Code Playgroud)

最后,对我们的添加功能进行一些修改以考虑假期:

NSDate * addBusinessDaysToDate(NSDate * start, int daysToAdvance, NSArray * holidays)
{
    NSDate * end = start;

    for (int i = 0; i < daysToAdvance; i++)
    {
        // If the current date is a weekend, advance:
        end = ensureDateIsWeekday(end);

        // If the current date is a holiday, advance: 
        end = ensureDateIsntHoliday(end, holidays);

        // And move the date forward by one day:
        end = addDaysToDate(end, 1);
    }

    // Finally, make sure we didn't end on a weekend or a holiday:
    end = ensureDateIsWeekday(end);
    end = ensureDateIsntHoliday(end, holidays);

    return end;
}
Run Code Online (Sandbox Code Playgroud)

继续尝试:

int main() {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSDate * start = [NSDate date];
    int daysToAdvance = 10;

    NSMutableArray * holidays = [[NSMutableArray alloc] init];
    [holidays addObject:addDaysToDate(start, 2)];
    [holidays addObject:addDaysToDate(start, 3)];

    NSDate * end = addBusinessDaysToDate(start, daysToAdvance, holidays);

    [holidays release];

    NSLog(@"Result: %@", [end descriptionWithCalendarFormat:@"%Y-%m-%d"
                                    timeZone:nil
                                      locale:nil]);

    [pool drain];

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果您想要整个项目,请访问:http://snipt.org/xolnl