4

问候,

最近,我在 NSCalendar 课程中遇到了一个大问题(在我看来)。

在我的任务中,我需要处理从公元前 4000 年到公元 2000 年(公历)的较长时间段。在某些地方,我被迫以 100 年的间隔增加一些 NSDate。当在 AD 时间轴(0->...)中增加年份时,一切正常,但是当我用 BC 尝试同样的事情时,我有点困惑。

问题是,当您尝试将 100 年添加到 3000BC [edited] 年份时,无论如何都会得到 3100BC [edited] ... 我个人觉得这很奇怪且不合逻辑。正确的结果应该是 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。

顺便说一句。:方法 [NSCalendar components:fromDate:toDate:options:] 不允许我们计算公元前时代的年份之间的差异......额外的“为什么?” 在这个潘多拉的盒子里。

PS:我正在挖掘官方文档和其他资源,但没有发现关于这个问题的任何内容(或者它可能是为了工作而我是个白痴?)。

4

3 回答 3

3

我为这个错误找到了一个简单的解决方法。这里是:

@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

如果您想知道为什么我只反转年份,答案很简单,除了年份之外的所有其他组件都以正确的方式递增和递减(我没有对它们进行全部测试,但几个月和几天似乎工作正常)。

编辑:删除错误添加的自动释放,谢谢约翰。

于 2010-09-16T18:21:38.863 回答
0

这是一个错误或一个功能。Apple 文档从未说明将组件添加到日历日期的含义。他们完全可以自由地将 BCE 日期的“添加组件”定义为年份组件的添加。

是的,我同意你的观点,这是违反直觉的,我认为这是一个错误。

您需要将您的转换NSDate

  • 来自 UNIX 时代(1.1.1970)的第二个使用-timeIntervalSince1970
  • 来自 OS X 时代(1.1.2001)的第二个使用-timeIntervalSinceReferenceDate

然后,您可以执行计算,并将其转换回NSDate. 我认为一直在公历中工作是个坏主意……最好在将其显示在 GUI 上之前转换为公历。

于 2010-09-15T21:06:27.920 回答
0

想象一下,您与我们这个时代的第一刻约会 - AD 0001-01-01 00:00:00。前一刻是什么?公元前 0001-01-01 00:00:01。如果 Cocoa 开发人员为此任务使用基本算术,您将得到AD 0000-12-31 23:59:59。这对公历合理吗?我猜不是。因此,在我看来,实现日历最方便的方法是使用 Era 标志,并在处理 BC 时代时更改“时间方向”以在每种情况下获得人类可读的日期。

顺便说一句。:[NSCalendar dateByAddingComponents:toDate:options:]真的表现得很奇怪,无法计算 BC 日期之间的时间间隔,我也检查过。因此,对于 BC 日期,您可以使用解决方法,例如将日期转换为 AD,然后查找差异。

于 2010-09-15T16:35:06.343 回答