iOSでの時間を制する(NSDate, NSDateComponents)
もうひとつのプロフェッショナルプログラマーより転載です。
iOSで時間を利用する方法です。iOSでは, NSDate, NSDateComponentなどを使います。
アプリを開発する際に, 注意しなくてはならないのが, タイムゾーンと時間です。
APIがどこの時間を取得したかが問題になります。またユーザに対してどの時間を表示させるべきかも問題になります。
iOSで時間を扱う場合の基本方針
- Core Data に保存する値は, 常に GMT 時間を保存
- 表示するデータ(UIDatePickerも)は, 現地時間
- 保存したデータの検索は, GMT時間
- GMT, 現地時間との相互変換が必要
ユーザには, 現地時間, ソフトウェア内部ではGMT時間で操作する方法がよさそうです。
Sampleなど
時間を扱うクラスは, NSDate, NSDateComponentなんかがよさそうです。
ローカル時間(現在時間)を取得する
NSDate *now = [NSDate date];
NSDate を何も考えずに利用すると, ローカル時間が得られます。 NSLogなんかで
NSLog(@"Current Time %@", [NSDate date]);
と表示させてみるとGMTになります。
タイムゾーンの取得
NSDate *date = [NSDate date]; NSTimeZone *tz = [NSTimeZone systemTimeZone]; NSInteger seconds = [tz secondsFromGMTForDate: date];
NSDate *date = [NSDate date]; NSDateComponents *comps; NSCalendar *calendar = [NSCalendar currentCalendar]; comps = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date]; NSDateComponents *new_comps = [[NSDateComponents alloc] init]; [new_comps setYear:comps.year]; [new_comps setMonth:comps.month]; [new_comps setDay:comps.day]; [new_comps setHour:23]; [new_comps setMinute:59]; [new_comps setSecond:59]; NSDate *tmp = [calendar dateFromComponents:new_comps]; NSTimeZone *tz = [NSTimeZone systemTimeZone]; NSInteger seconds = [tz secondsFromGMTForDate:tmp]; NSDate *local_date = [tmp dateByAddingTimeInterval:seconds];
※応用編です。
NSCalendar を利用しています NSCalendar, NSDateCompoenents で得られたcomponentは
, 現地時間になります。(currentCalendar は現地時間を表します)
[NSDate date] で, GMTを得たはずなのに, currentCalendar を通すと, 現地時間に変わってしまいます。
さらに, NSDateComponents を使って, 時間の操作をしました。またカレンダーを使って, 時間を得ていますが, この時間はGMTに戻っています。そこで再び現地時間に戻します。
UIDatePicker の場合
UIDatePicker は, タイムゾーンをstoryboard 上もしくは, コードで設定します
コードで設定(datePicker は, UIdatePicker オブジェクトのインスタンス or リファレンス)
datePicker.timezone = [NSTimeZone systemTimeZone];
これで現地時間になります。
このUIDatePicker で得られた値を再度, GMT時間に戻すには, 以下のコードを押し込みます
NSDate *local_date = [datePicker date]; NSTimeZone *tz = [NSTimeZone systemTimeZone]; NSInteger seconds = [tz secondsFromGMTForDate: local_date]; [local_date dateByAddingTimeInterval:-(seconds)];
※これは現地時間を取得したときと逆の計算をしています。
GMT時間で保存しておけば, のちにi端末のタイムゾーンを変更しても, そのタイムゾーンに合わせた時間によしなに変更してくれるということです。
グローバルアプリの場合は, 多少気を付ける必要がありそうです。