问候,
最近我遇到了NSCalendar类的一个大问题(在我看来)。
在我的任务中,我需要处理从公元前4000年到公元前2000年(格里高利历)的大量时间段。在某些地方,我被迫以100年的间隔增加一些NSDate。当在AD时间轴(0-> ...)中递增年份时,一切正常,但是当我尝试与BC相同的事情时,我有点困惑。
问题是,当你尝试将100年添加到3000BC [编辑]年时,你得到3100BC [编辑]无论如何...我个人发现它很奇怪而且不合逻辑。正确的结果应该是2900BC。
以下是您看到此“不正确”行为的代码示例:
NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
// initing
NSDateComponents *comps = [[[NSDateComponents alloc] init] autorelease];
[comps setYear:-1000];
NSDate *date = [gregorian dateFromComponents:comps];
// math
NSDateComponents *deltaComps = [[[NSDateComponents alloc] init] autorelease];
[deltaComps setYear:100];
date = [gregorian dateByAddingComponents:deltaComps toDate:date options:0];
// output
NSString *dateFormat = @"yyyy GG";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:dateFormat];
NSLog(@"%@", [formatter stringFromDate:date]);
你对这种行为有什么看法?这是它应该如何工作或这是一个错误?我很困惑:S。
BTW:方法[NSCalendar components:fromDate:toDate:options:]不允许我们计算不列颠哥伦比亚省时代之间的差异...另外'为什么?'在潘多拉的盒子里。P.S。:我正在挖掘官方文档和其他资源,但没有发现任何关于这个问题(或者它可能是这样的,我是个白痴?)。
答案 0 :(得分:3)
我找到了这个bug的简单解决方法。 这是:
@interface NSCalendar (EraFixes)
- (NSDate *)dateByAddingComponentsRegardingEra:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSUInteger)opts;
@end
@implementation NSCalendar (EraFixes)
- (NSDate *)dateByAddingComponentsRegardingEra:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSUInteger)opts
{
NSDateComponents *toDateComps = [self components:NSEraCalendarUnit fromDate:date];
NSDateComponents *compsCopy = [[comps copy] autorelease];
if ([toDateComps era] == 0) //B.C. era
{
if ([comps year] != NSUndefinedDateComponent) [compsCopy setYear:-[comps year]];
}
return [self dateByAddingComponents:compsCopy toDate:date options:opts];
}
@end
如果你想知道为什么我只反转几年,答案很简单,除了几年之外的所有其他组件都以正确的方式递增和递减(我没有全部测试过,但是几个月和几天似乎工作正常)。 / p>
编辑:删除了错误添加的自动释放,感谢John。
答案 1 :(得分:0)
想象一下,你有我们这个时代的第一时刻的日期 - AD 0001-01-01 00:00:00。之前的那一刻? BC 0001-01-01 00:00:01 。如果Cocoa开发人员使用基本算术来完成此任务,那么你将获得 AD 0000-12-31 23:59:59 。格里高利历是否合理?我猜不会。因此,在我看来,实现日历最方便的方法是使用Era标志,并在处理BC时代时更改“时间方向”,以便在每种情况下获得人类可读日期。
BTW:[NSCalendar dateByAddingComponents:toDate:options:]
确实表现得很奇怪,无法计算BC日期之间的时间间隔,我也查了一下。因此,对于BC日期,您可以使用解决方法,例如通过将日期转换为AD然后找到差异。
答案 2 :(得分:0)
这是一个错误和/或功能。 Apple文档从未说明将组件添加到日历日期的含义。他们完全免费为BCE日期定义“添加组件”,只是添加到年份组件。
是的我同意你的观点,这是违反直觉的,我认为这是一个错误。
您需要将NSDate
转换为
-timeIntervalSince1970
-timeIntervalSinceReferenceDate
然后,您可以执行计算,并将其转换回NSDate
。我认为一直在格里高利历中工作是个坏主意......最好在你在GUI上显示之前转换为公历。