0

我看了一遍,没有找到一个函数可以给出两个日期之间的工作日数。

我该怎么做?

当然它不会计算假期,因为每个国家都有自己的假期,但我可以为我的国家做一些特定的功能。

编辑:我没有问如何获得两个日期之间的天数。

4

1 回答 1

3

所以你对工作日的定义似乎是周一到周五。我们称这些为“工作日”,而不是“周末”(即周六和周日)。

如何计算从 astartDate到a 的工作日数并不明显endDate,所以让我们从一个更简单的计算开始:从startDate到的周数endDate。“周”是指从星期日开始的 7 天时间段。

如果startDateendDate落在同一周,我们将计算该周一次。如果它们落在不同的周内,我们将计算包含startDate的周、包含 的endDate周以及其间的任何周。所以这是一个“包含”的周数。

给定这个周数,我们显然可以乘以 5 来得到一周中的工作日数。但这不一定是从startDate到的工作日数endDate。如果startDate是星期日或星期一,并且endDate是星期六或星期日,那么它是正确的,否则它会计算一些应该排除的天数。

应该排除多少天?首先,考虑startDate. 我们需要排除startDate一周之前的工作日数(0 表示周日和周一,1 表示周二,2 表示周三,3 表示周四,4 表示周五,5 表示周六)。然后考虑endDate。我们需要排除endDate一周中接下来的工作日数,如果是工作日,我们需要排除endDate自身(周日和周一为 5,周二为 4,周三为 3,周四为 2,周五为 1,0星期六)。

考虑到这一切,从startDate到的工作日数的公式endDate

 5 * inclusive count of weeks from startDate to endDate
   - count of workdays preceding startDate
   - count of workdays following and including endDate

startDate例如,如果是星期一并且endDate是同一周的星期二,这将给出 1 。如果在这种情况下你宁愿得到 2(换句话说,endDate如果不是周末,你想算作工作日之一),那么公式是

 5 * inclusive count of weeks from startDate to endDate
   - count of workdays preceding startDate
   - count of workdays following (but not including) endDate

现在让我们使用 Cocoa 出色的日历计算支持在 Objective-C 中编写它。我们将在NSCalendar

@interface NSCalendar (Rob_Workdays)

/** I return the number of non-weekend days from startDate to endDate,
    including the day containing `startDate` and excluding the day
    containing `endDate`. */
- (NSInteger)Rob_countOfWorkdaysFromDate:(NSDate *)startDate
    toDate:(NSDate *)endDate;

/** I return the number of non-weekend days from startDate to endDate,
    including the day containing `startDate` and the day containing
    `endDate`. */
- (NSInteger)Rob_countOfWorkdaysFromDate:(NSDate *)startDate
    toAndIncludingDate:(NSDate *)endDate;

@end

为了实现这些方法,让我们将公式直接转换为代码:

@implementation NSCalendar (Rob_Workdays)

- (NSInteger)Rob_countOfWorkdaysFromDate:(NSDate *)startDate toDate:(NSDate *)endDate {
    return 5 * [self Rob_inclusiveCountOfWeeksFromDate:startDate toDate:endDate]
        - [self Rob_countOfWorkdaysPrecedingDate:startDate]
        - [self Rob_countOfWorkdaysFollowingAndIncludingDate:endDate];
}

- (NSInteger)Rob_countOfWorkdaysFromDate:(NSDate *)startDate toAndIncludingDate:(NSDate *)endDate {
    return 5 * [self Rob_inclusiveCountOfWeeksFromDate:startDate toDate:endDate]
        - [self Rob_countOfWorkdaysPrecedingDate:startDate]
        - [self Rob_countOfWorkdaysFollowingDate:endDate];
}

当然,我们需要实现辅助方法,从周数开始。为了计算周数,我们startDate向后滚动直到星期天,我们endDate向前滚动直到星期天。然后我们计算从startDateto的天数endDate并除以 7:

/** I return the number of weeks from `startDate` to `endDate`, including
    the weeks containing each date (but only counting the week once if the
    same week includes both dates). */
- (NSInteger)Rob_inclusiveCountOfWeeksFromDate:(NSDate *)startDate
    toDate:(NSDate *)endDate
{
    startDate = [self Rob_sundayOnOrBeforeDate:startDate];
    endDate = [self Rob_sundayAfterDate:endDate];
    NSDateComponents *components = [self components:NSCalendarUnitDay
        fromDate:startDate toDate:endDate options:0];
    return components.day / 7;
}

以下是我们如何回滚到周日:

- (NSDate *)Rob_sundayOnOrBeforeDate:(NSDate *)date {
    return [self Rob_dateByAddingDays:1 - [self Rob_weekdayOfDate:date]
        toDate:date];
}

以下是我们如何推进到周日:

- (NSDate *)Rob_sundayAfterDate:(NSDate *)date {
    return [self Rob_dateByAddingDays:8 - [self Rob_weekdayOfDate:date]
        toDate:date];
}

以下是我们如何计算日期的工作日(从 1=Sunday 到 7=Saturday):

- (NSInteger)Rob_weekdayOfDate:(NSDate *)date {
    return [self components:NSCalendarUnitWeekday fromDate:date].weekday;
}

以下是我们如何将一些天数添加到日期:

- (NSDate *)Rob_dateByAddingDays:(NSInteger)days toDate:(NSDate *)date {
    if (days != 0) {
        NSDateComponents *components = [[NSDateComponents alloc] init];
        components.day = days;
        date = [self dateByAddingComponents:components toDate:date
            options:0];
    }
    return date;
}

请注意,如果days为负数,该方法将及时回滚日期。

要计算某个日期之前的工作日数,我们可以使用蛮力(因为一周中只有 7 天需要考虑),这很容易理解,也可以使用公式,它更小但更难理解:

- (NSInteger)Rob_countOfWorkdaysPrecedingDate:(NSDate *)date {
    switch ([self Rob_weekdayOfDate:date]) {
        case 1: return 0;
        case 2: return 0;
        case 3: return 1;
        case 4: return 2;
        case 5: return 3;
        case 6: return 4;
        case 7: return 5;
        default: abort();
    }
    // equivalently: return MIN(MAX(0, [self Rob_weekdayOfDate:date] - 2), 5);
}

计算日期后的工作日数是类似的,但我们需要两个版本,具体取决于我们是包括还是不包括给定日期:

- (NSInteger)Rob_countOfWorkdaysFollowingAndIncludingDate:(NSDate *)date {
    switch ([self Rob_weekdayOfDate:date]) {
        case 1: return 5;
        case 2: return 5;
        case 3: return 4;
        case 4: return 3;
        case 5: return 2;
        case 6: return 1;
        case 7: return 0;
        default: abort();
    }
    // equivalently: return MIN(7 - [self Rob_weekdayOfDate:date], 5);
}

- (NSInteger)Rob_countOfWorkdaysFollowingDate:(NSDate *)date {
    switch ([self Rob_weekdayOfDate:date]) {
        case 1: return 5;
        case 2: return 4;
        case 3: return 3;
        case 4: return 2;
        case 5: return 1;
        case 6: return 0;
        case 7: return 0;
        default: abort();
    }
    // equivalently: return MAX(6 - [self Rob_weekdayOfDate:date], 0);
}

@end
于 2014-02-21T21:17:43.310 回答