NSCalendar 的 dateBySettingUnit 方法 returns 结果不明显

dateBySettingUnit method of NSCalendar returns not obvious result

我的问题已通过 NSDateComponents 解决,但我想了解为什么此方法如此有效

NSDate *today = [NSDate date];
NSLog(@"today is: %@", today);

NSDate *dayChanged = [calendar dateBySettingUnit:(NSCalendarUnitDay)
                                           value:10
                                          ofDate:today
                                         options:0];
NSLog(@"dayChanged is: %@", dayChanged);

NSDate *monthChanged = [calendar dateBySettingUnit:(NSCalendarUnitMonth)
                                             value:5
                                            ofDate:today
                                           options:0];
NSLog(@"monthChanged is: %@", monthChanged);

结果是:

today is: 2016-09-30 06:40:36 +0000
dayChanged is: 2016-10-10 00:00:00 +0000
monthChanged is: 2017-05-01 00:00:00 +0000

为什么 dateBySettingUnit 增加下一个更大的单位?

有趣的是,dateBySettingUnit 的行为可以是 "unexpected",因为所有组件实际上都绑定在一起。根据 NSCalendar 头文件文档(强调我的):

The specific behaviors here are as yet unspecified; for example, if I change the weekday to Thursday, does that move forward to the next, backward to the previous, or to the nearest Thursday? A likely rule is that the algorithm will try to produce a result which is in the next-larger unit to the one given (there's a table of this mapping at the top of this document). So for the "set to Thursday" example, find the Thursday in the Week in which the given date resides (which could be a forwards or backwards move, and not necessarily the nearest Thursday). For forwards or backwards behavior, one can use the -nextDateAfterDate:matchingUnit:value:options: method above.

因此,根据您的需要,使用 nextDateAfterDate:matchingUnit:value:options: 可能更合适。

根据观察,dateBySettingUnit does not return past date

因此,对于使用 dateBySettingUnit 的未来日期的快速测试设置,可以按预期工作,请参见下面的代码:

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDate *today = [NSDate date];
NSLog(@"today is: %@", today);

NSDate *dayChanged = [calendar dateBySettingUnit:(NSCalendarUnitDay)
                                           value:31
                                          ofDate:today
                                         options:NSCalendarWrapComponents];
NSLog(@"dayChanged is: %@", dayChanged);

NSDate *monthChanged = [calendar dateBySettingUnit:(NSCalendarUnitMonth)
                                             value:12
                                            ofDate:dayChanged
                                           options:NSCalendarWrapComponents];
NSLog(@"monthChanged is: %@", monthChanged);

日志:

2016-09-30 12:58:30.506 TestRegex[3785:72957] today is: 2016-09-30 07:58:30 +0000
2016-09-30 12:58:30.508 TestRegex[3785:72957] dayChanged is: 2016-09-30 19:00:00 +0000
2016-09-30 12:58:30.509 TestRegex[3785:72957] monthChanged is: 2016-11-30 19:00:00 +0000

您可以尝试 link 的答案中提到的 NSCalendar 扩展,它实际计算偏移量,或者您可以使用 NSDateComponents 解决方案:

 NSDateComponents *comps = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:today];
[comps setCalendar:calendar];
[comps setDay:5];

希望对您有所帮助!