objective-c中两个日期之间的工作日?

时间:2014-02-21 19:28:22

标签: objective-c weekday

我全神贯注地找不到一个函数,它给出了两个日期之间的工作日数。

我该怎么做?

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

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

1 个答案:

答案 0 :(得分:3)

因此,您对工作日的定义似乎是星期一到星期五。我们称之为“工作日”,而不是“周末”(周六和周日)。

如何计算从startDateendDate的工作日数量并不明显,所以让我们从一个更简单的计算开始:从startDate到{{的周数1}}。 “周”是指从星期日开始的七天。

如果endDatestartDate属于同一周,我们会计算一周。如果它们在不同的星期内出现,我们会计算包含endDate的周,包含startDate的一周,以及介于两者之间的任何周。所以这是一个“包容性”的数周。

考虑到这个周数,我们显然可以乘以5来获得本周的工作日数。但这不一定是从endDatestartDate的工作日数。如果endDate是星期日或星期一,而startDate是星期六或星期日,那么它是正确的,但除非它计算应排除的几天。

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

鉴于这一切,endDatestartDate的工作日数公式为

endDate

例如,如果 5 * inclusive count of weeks from startDate to endDate - count of workdays preceding startDate - count of workdays following and including endDate 是星期一,而startDate是同一周的星期二,则会给出1。如果您希望在这种情况下获得2(换句话说,如果不是周末,您希望将endDate计为工作日之一),则公式为

endDate

现在让我们使用Cocoa的优秀日历计算支持在Objective-C中编写它。我们将在 5 * inclusive count of weeks from startDate to endDate - count of workdays preceding startDate - count of workdays following (but not including) endDate 上实施此类别:

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直到它是星期天。然后我们计算从endDatestartDate并除以7的天数:

endDate

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

/** 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];
}

以下是我们如何计算某个日期的工作日(从1 =星期日到7 =星期六):

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

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

- (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

计算日期之后的工作日数量是类似的,但我们需要两个版本,具体取决于我们是否包含或排除给定日期:

- (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);
}