4

ご挨拶、

最近、NSCalendarクラスで大きな問題に直面しました(私にはそう思われます)。

私の仕事では、紀元前4000年から紀元前2000年(グレゴリオ暦)までの長い期間で作業する必要があります。ある場所で、NSDateを100年間隔でインクリメントすることを余儀なくされました。ADタイムライン(0-> ...)で年をインクリメントすると、すべてが正常に機能しましたが、BCで同じことを試したとき、少し混乱しました。

問題は、紀元前3000年[編集]年に100年を追加しようとすると、何があっても紀元前3100年[編集]になるということです...個人的には、奇妙で非論理的だと感じました。正しい結果は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:]では、紀元前の年の差を計算できません...追加の「WHY?」このパンドラの箱に。

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

あなたが私たちの時代の最初の瞬間の日付を持っていると想像してください-AD0001-01-0100:00:00。前の瞬間は何でしたか?BC0001-01-0100:00:01。Cocoa開発者がこのタスクに基本的な算術演算を使用した場合、AD0000-12-3123:59:59が得られます。それはグレゴリオ暦にとって合理的ですか?私はそうは思わない。したがって、カレンダーを実装する最も便利な方法は、紀元フラグを使用し、紀元前の時代を扱うときに「時間方向」を変更して、すべての場合に人間が読める日付を取得することであるように思われます。

ところで:[NSCalendar dateByAddingComponents:toDate:options:]本当に奇妙に振る舞い、紀元前の日付間の時間間隔を数えることができません、私もチェックしました。したがって、BC日付の場合、たとえば日付をADに変換してから差分を見つけるなど、回避策を使用できます。

于 2010-09-15T16:35:06.343 に答える
0

これはバグや機能です。Appleのドキュメントでは、カレンダーの日付にコンポーネントを追加することで、それらが何を意味するのかを説明することはありません。BCE日付への「コンポーネントの追加」を、年コンポーネントへの単なる追加として定義することは、完全に無料です。

はい、直感に反し、バグだと思います。

NSDateどちらかに変換する必要があります

  • UNIXエポック(1.1.1970)からの2番目の-timeIntervalSince1970
  • OS Xエポック(1.1.2001)からの2番目の-timeIntervalSinceReferenceDate

次に、計算を実行して、に変換し直すことができますNSDate。常にグレゴリオ暦で作業するのは悪い考えだと思います...GUIに表示する直前にグレゴリオ暦に変換することをお勧めします。

于 2010-09-15T21:06:27.920 に答える