Dav*_*vid 6 cocoa objective-c nsdate nsdatecomponents
以今天为例,我如何确定230个工作日之前的日期?
我知道如何使用while循环检查日期迭代地执行它,如果它是工作日则减去1,但我想知道是否有更好的方法.
另外,我们以周日下午1点为例,减去3个工作日和2个小时.首先,从周末减去工作时间是没有意义的.因此,它必须将时间移至星期五的23:59:59,然后减去3天和2小时.
如果它是星期一凌晨1:30,我将减去5天和3个工作小时,那么结果应该是前一周的星期五晚上22:30.
用于测试Kevin方法的代码:
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]);
Run Code Online (Sandbox Code Playgroud)
输出日志:
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
Run Code Online (Sandbox Code Playgroud)
它永远不应该是12-18,因为那是一个星期天.
计算出您的日期距上周末还有多长时间,然后从您的日期和偏移量中减去该金额。现在,您可以将偏移量除以 5 来计算偏移量中有多少个整周,然后将其乘以 7 并从日期中减去这个新值。取之前的偏移量(除以 5 的偏移量)并除以 5,即可得到剩余天数。如果它大于 0,请从您的日期中减去该偏移量 + 2(周末)。
请注意,这假设每个工作日都是工作日。公司假期往往会使这一假设无效。如果你需要处理假期,你就会遇到更棘手的问题。
更新:这里尝试修复大卫的代码以实际表达这里的想法:
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];
}
Run Code Online (Sandbox Code Playgroud)