NSDateFormatterの挙動

猫のお留守番の録音タイトルを設定する機能の実装で、一日くらい悩んだので、 書き残しておく。 猫のお留守番はXcode 3.2.5でBase SDK 10.4/GCC 4.0でビルドしている。 この環境で以下のコードを書いてみた。
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
[dateFormatter setDateStyle:NSDateFormatterLongStyle];
	
NSLog(@"Date %@", [dateFormatter stringFromDate:[NSDate date]]);
MacBook Air 10.6.8で実行するとこの結果は以下のようにおかしい。 フォーマットどころかロケールすら効いていない。
Date 12/16/12
BaseSDK 10.5/GCC 4.2でコンパイルすると以下のようになる。
Date 2012年12月16日
Base SDK 10.4/GCC 4.0でも以下のおまじないを唱えると正常に表示される。
[NSDateFormatter setDefaultFormatterBehavior: NSDateFormatterBehavior10_4];
NSDateFormatterは、はまり所が多い。。。

最終週の計算

そのNSDateが最終週かは、値に7×24×60秒を足した値が、1週になれば最終週と なる。猫のお留守番の1.4ではこのロジックで算出している。
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *nextTime = [thetime addTimeInterval:(7 * 24 * 60 * 60)];
weekNo = [cal ordinalityOfUnit:NSWeekCalendarUnit 
                        inUnit:NSMonthCalendarUnit 
                       forDate:nextTime];
if(weekNo == 1) {
// thetime is last week
}
実はこのコードにはバグありで最終週であった場合、weekNoは1になるとは限らず2 になる可能性もある。素直に一週間プラスしたNSDateがNSDateComponentsでdayが小 さくなっている事を確認んするように変更してみた。

Calendar

エアーチェックで第三火曜日のようなスケジュールが多いわけだが、ordinalityOfUnit では、例えば上の例では第三週は12から始まる週(日曜が始まり)で第三週の火曜日は14 日となってしまう。
NSDateComponents* curcompo = [cal
			  components: NSDayCalendarUnit
			  fromDate:thetime];
	
int dayNo = [curcompo day];
int weekNo = (dayNo - 1) / 7 + 1;
上で使っているaddTimeIntervalは"Deprecated in OS X v10.6"なのだが代わりの、 dateByAddingTimeIntervalが10.6以降なので10.5もサポートに入れている 猫のお留守番では使えない。addTimeIntervalは10.0からあるがそもそもNSDateを 返しているのでAppleの名前の規則に違反している事が問題だったんだろうが、 おそらくaddTimeIntervalが使えなくなる事は無いような気がするのだが。。。

Copyright (C) 2012 Hiroki Mori All Rights Reserved.