【问题标题】:Business days between two dates in objective-c?Objective-c中两个日期之间的工作日?
【发布时间】:2014-02-21 19:28:22
【问题描述】:

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

我该怎么做?

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

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

【问题讨论】:

  • 你看的不够仔细,因为有数百种解决方案。
  • 您是指两个日期之间的天数,不包括周末?还是什么?
  • 大力水手,我确实找到了一些解决方案,但没有一个完成......我只是想知道是否有任何完成的解决方案,但显然没有

标签: objective-c weekday


【解决方案1】:

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

如何计算从startDateendDate 的工作日数并不明显,所以让我们从更简单的计算开始:从startDateendDate 的周数。 “周”是指从星期日开始的 7 天。

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

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

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

考虑到所有这些,从startDateendDate 的工作日数的公式是

 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 直到星期天。然后我们计算从startDateendDate的天数并除以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=星期日到 7=星期六)的方法:

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

【讨论】:

  • 您还可以有一个假期日期数组,如果它们在给定的时间间隔内,则从结果中减去它们:)
  • 谢谢!这是你写的还是从其他地方得到的?我确实搜索了很多并找不到......不幸的是我无法投票,呵呵。谢谢
  • 我是根据你的问题写的。如果它解决了您的问题,请点击答案顶部的复选标记接受它。
  • @Sulthan,我已经设法通过检查日期是否在范围内来从结果中减去假期,就像你说的那样......检查的功能如下:+(BOOL) date:(NSDate*)date isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate { if ([date compare:beginDate] == NSOrderedAscending) 返回 NO; if ([date compare:endDate] == NSOrderedDescending) 返回 NO;返回是; }
猜你喜欢
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-24
  • 1970-01-01
  • 2020-05-10
  • 2021-06-02
  • 2020-11-20
相关资源
最近更新 更多