BC時代のnscalendarの問題
-
03-10-2019 - |
質問
ご挨拶、
最近、私はnscalendarクラスで大きな問題に直面しました(私にはそう思われます)。
私のタスクでは、4000BCから2000AD(グレゴリオカレンダー)までの大規模な期間で作業する必要があります。ある場所では、100年間隔でNSDateを増やすことを余儀なくされました。広告タイムライン(0-> ...)で年を増やすと、すべてが正常に機能しましたが、BCで同じことを試したとき、私は少し混乱していました。
問題は、100年を3000年[編集]に追加しようとすると、何があっても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コンポーネント:fromdate:todate:options:] BC時代の年の違いを計算することはできません...追加「なぜ?」このパンドラの箱に。
PS:私は公式の文書やその他のリソースを掘り下げていましたが、この問題に関して何も見つかりませんでした(または、そうすることを意図していて、私はばかですか?)。
解決
このバグの簡単な回避策を見つけました。ここにあります:
@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を誤って追加した、Johnに感謝します。
他のヒント
それはバグや機能です。 Apple Docは、それらが何を意味するかを決して言いません カレンダーの日付にコンポーネントを追加します. 。年間コンポーネントへの追加として、BCE日付に「コンポーネントの追加」を定義するのは完全に無料です。
はい、私はそれが直感に反するものであり、それがバグだと思います。
あなたはあなたを変換する必要があります NSDate
どちらか
- Unix Epoch(1.1.1970)からの2番目の
-timeIntervalSince1970
- OS X Epoch(1.1.2001)からの2番目の
-timeIntervalSinceReferenceDate
その後、計算を実行し、それをに戻すことができます NSDate
. 。常にグレゴリオカレンダーで作業するのは悪い考えだと思います... GUIに表示する直前にグレゴリオカレンダーに変換する方が良いでしょう。
あなたが私たちの時代の最初の瞬間とデートしていると想像してください - AD 0001-01-01 00:00:00。 前の瞬間は何でしたか? BC 0001-01-01 00:00:01. 。ココア開発者がこのタスクに基本的な算術を使用した場合、あなたは取得するでしょう AD 0000-12-31 23:59:59. 。それはグレゴリオカレンダーにとって合理的ですか?そうではないと思います。ですから、カレンダーを実装する最も便利な方法は、ERAフラグを使用し、変更することだったように思えます。」時間の方向「あらゆる場合に人間が読みやすい日付を取得するためにBC時代を扱うとき。
ところで: [NSCalendar dateByAddingComponents:toDate:options:]
本当に奇妙に振る舞い、BC日付間の時間間隔を数えることができないので、私もチェックしました。したがって、BCの日付では、たとえば、日付をADに翻訳してからDIFFを見つけることにより、回避策を使用できます。