2010-09-15 27 views
4

問候,BC時代的NSCalendar問題

最近我遇到了一個很大的問題(對我來說)與NSCalendar類。

在我的任務中,我需要從4000BC到2000AD(公曆)開始的大量時間段工作。在某些地方,我被迫每隔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。

順便說一句:該方法[NSCalendar組件:fromDate:toDate:options:]不允許我們計算BC時代之間的差異...額外'爲什麼?'在這個潘多拉的盒子裏。

P.S .:我正在通過官方文檔和其他資源進行挖掘,但沒有發現任何關於這個問題(或者它的意圖是工作,所以我是個白癡?)。

+0

3000AD + 100AD = 3100AD。這是基本的算術。從你的描述來看,數學是正確的。在你的代碼中,你想添加-1000到-100來獲得1100BC,我懷疑,但是因爲你沒有向我們展示你的代碼的輸出結果,所以我們不知道它是如何行爲不端。 – 2010-09-15 16:00:46

+0

「...當你嘗試增加100年到3000AD年,你會得到3100AD無論如何...我個人覺得它很奇怪,不合邏輯。正確的結果應該是2900BC「你的意思是在整個段落中說」BC「?否則,它沒有意義:AD 3000 + 100 = AD 3100;那是正確的結果。 – 2010-09-15 18:52:20

+0

喬納森:對不起,我犯了一個錯誤,它不是公元,是公元前。 – GregoryM 2010-09-16 06:22:50

回答

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 

如果你想知道爲什麼我只反轉年,答案很簡單,除了多年的所有其他組件遞增和以正確的方式(我沒有測試過,而是個月遞減和幾天似乎工作正常)。

編輯:刪除錯誤地添加autorelease,謝謝約翰。

+1

我很高興你發現了這個,我花了一天的時間跟蹤BC日期偏移問題,最後我的問題是由這個非常錯誤/異常造成的。順便說一下,組件的結果:fromDate:不應該被autoreleased。 – 2012-05-07 17:09:07

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時代時更改「時間方向」,以便在每種情況下獲得人類可讀的日期。

隨着:[NSCalendar dateByAddingComponents:toDate:options:]真的很奇怪,無法計算BC日期之間的時間間隔,我也檢查了。因此,對於BC日期,您可以使用解決方法,例如通過將日期轉換爲AD然後發現差異。

+3

其實,第二個是BC 0001-12-31 23:59:59。只有年份數字倒退。 – 2010-09-15 17:45:34

+0

基本算法在NSCalendar中正常工作(除了我描述的情況)。當你從50AD減去100年後,你會得到51BC。但是當你處理BC日期時似乎是「倒置的」。 – GregoryM 2010-09-16 06:27:41

0

這是一個錯誤和/或功能。 Apple文檔從未說明將組件添加到日曆日期中意味着什麼。他們完全免費的將BCE日期中的「添加組件」定義爲年份組件的添加。

是的,我同意你的看法,這是違反直覺的,我認爲這是一個錯誤。

你需要轉換你的NSDate要麼

  • 第二使用-timeIntervalSince1970
  • 第二從OS X時代(2001年1月1日)的UNIX紀元(1.1.1970)使用-timeIntervalSinceReferenceDate

然後,您可以執行計算,並將其轉換回NSDate。我認爲在公曆中一直工作是一個壞主意......在GUI上顯示它之前,最好轉換爲公曆。

+0

你的想法其實是對的,但有一個問題。當你試圖添加100年到特定的NSDate時,你使用[NSCalendar dateByAddingComponents:...],爲什麼?因爲你不知道這100年到底有多少秒,對吧?正如我之前指出的,方法[NSCalendar組件:fromDate:toDate:options:]在BC時代根本不起作用,因此100年內沒有機會獲得精確的秒數,是嗎? – GregoryM 2010-09-16 06:38:44

+0

如果你真的需要這個特定的操作,我想你需要自己編寫它們。老實說,我不明白你的意思是「準確添加100年」。什麼是100年加上「400AD 2月29日」?無論如何,你需要制定一些特別的規則來處理閏年。 – Yuji 2010-09-16 15:21:26

+0

我認爲在某個日期添加100年並不是特定的操作:)並且我應該編寫自己的方法來執行此操作。我只是想知道如何未經測試的蘋果類。 Afaik單元測試是很早以前發明的...... – GregoryM 2010-09-16 18:14:37