如何从NSDate中减去持续时间,但不包括周末? [英] How do I subtract a duration from an NSDate, but not include the weekends?

查看:141
本文介绍了如何从NSDate中减去持续时间,但不包括周末?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以今天为例,如何确定哪个日期是230个工作日?

Using today as an example, how do I determine which date it was, 230 workdays ago?

我知道如何使用while循环检查日期

I know how to do it iteratively with a while loop checking date and subtracting 1 if it's a workday, but I'm wondering if there is a better method.

此外,让我们以星期日下午1点为例,减去3工作日和从那时起2小时。首先,从周末减去工作时间没有意义。因此,它必须将时间移动到星期五的23:59:59,然后减去这3天和2小时。

Also, let's take a Sunday 1 PM as an example, and subtract 3 work days and 2 hours from that time. First, it doesn't make sense to subtract work-time from weekends. So it would have to move the time to 23:59:59 of Friday, and then subtract those 3 days and 2 hours.

如果是星期一1:30 AM,我从那时间减去5天和3个工作小时,那么结果应该是上周的周五22:30 PM。

If it's a Monday at 1:30 AM, and I'm subtracting 5 days and 3 work-hours from that time, then the result should be Friday 22:30 PM of the previous week.

测试Kevin的方法的代码:

Code to test Kevin's method:

NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *dc = [[NSDateComponents new] autorelease];
dc.month = 12;
dc.day = 19;
dc.year = 2011;
dc.hour = 1;
dc.minute = 0;
dc.second = 0;

NSDate *date = [cal dateFromComponents:dc];

NSLog(@"%@", [date descriptionWithCalendarFormat:nil timeZone:nil locale:nil]);
date = dateBySubtractingWorkOffset(date, 0, 2);
NSLog(@"%@", [date descriptionWithCalendarFormat:nil timeZone:nil locale:nil]);

输出日志:

2011-12-02 16:33:46.878 otest[7124:707] 2011-12-19 01:00:00 -0500
2011-12-02 16:33:47.659 otest[7124:707] 2011-12-18 23:00:00 -0500

不应该是12

推荐答案

从上周末你的日期算起多长时间,从两者中减去您的日期和您的偏移量。现在,您可以将偏移量除以5,以计算您的偏移量中有多少整周,然后乘以7,并从您的日期中减去这个新的值。取你以前的偏移量(你除以5),并将其修改为5,得到剩余天数。如果大于0,从您的日期中减去偏移量+ 2(周末)。

Figure out how long from the last weekend your date is, subtract that amount from both your date and your offset. Now you can divide your offset by 5 to figure out how many full weeks are in your offset, and then multiply that by 7 and subtract this new value from your date. Take your previous offset (the one you divided by 5) and mod it by 5, to get the number of remaining days. If it's greater than 0, subtract that offset + 2 (for the weekend) from your date.

注意,假设每个工作日都是工作日。公司假期往往使该假设无效。如果你需要处理假日,你会遇到一个更加棘手的问题。

Note, this assumes every single weekday is a workday. Corporate holidays tend to make that assumption invalid. If you need to handle holidays, you're in for a much tougher problem.

更新:这里尝试修复David的代码在这里表达想法:

Update: Here's an attempt to fix David's code to actually express the idea here:

NSDate *dateBySubtractingWorkOffset(NSDate *date, NSUInteger days, NSUInteger hours) {
    const int secsInHour = 60*60;
    const int secsInDay = 24*secsInHour;
    NSTimeInterval offset = days*secsInDay + hours*secsInHour;
    NSCalendar *cal = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];

    // figure out distance from last weekend
    {
        NSUInteger units = NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekdayCalendarUnit;
        NSDateComponents *dc = [cal components:units fromDate:date];
        if (dc.weekday == 1 || dc.weekday == 7) {
            // we're in the weekend already. Let's just back up until friday
            // and then we can start our calculations there
        } else {
            // figure out our offset from sunday 23:59:59
            dc.day -= (dc.weekday - 1);
            dc.weekday = 1;
            dc.hour = 23;
            dc.minute = 23;
            dc.second = 23;
            NSDate *sunday = [cal dateFromComponents:dc];
            NSTimeInterval newOffset = [date timeIntervalSinceDate:sunday];
            if (offset < newOffset) {
                // our offset doesn't even go back to sunday, we don't need any calculations
                return [date dateByAddingTimeInterval:-offset];
            }
            offset -= [date timeIntervalSinceDate:sunday];
            // Now we can jump back to Friday with our new offset
        }
        // Calculate last friday at 23:59:59
        dc.day -= (dc.weekday % 7 + 1);
        dc.hour = 23;
        dc.minute = 59;
        dc.second = 59;
        date = [cal dateFromComponents:dc];
    }

    // We're now set to Friday 23:59:59
    // Lets figure out how many weeks we have
    int secsInWorkWeek = 5*secsInDay;
    NSInteger weeks = (NSInteger)trunc(offset / secsInWorkWeek);
    offset -= weeks*secsInWorkWeek;
    if (weeks > 0) {
        // subtract that many weeks from the date
        NSDateComponents *dc = [[NSDateComponents alloc] init];
        dc.week = -weeks;
        date = [cal dateByAddingComponents:dc toDate:date options:0];
        [dc release];
    }
    // now we can just subtract our remaining offset from the date
    return [date dateByAddingTimeInterval:-offset];
}

这篇关于如何从NSDate中减去持续时间,但不包括周末?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆