« 恣意散歩 | トップページ | ARC使用時の、動的確保されたid配列の扱いについて »

2012.04.19

NSDateFormatterとの戦い

 iOSのアプリ内で、日時を表示するためにいろいろ試したりすったりもんだりしてややこしくなったので、経緯を書いておく。

 標準のカレンダーで月表示にしてやると、"2012年4月"のように、年と月が表示される。設定で地域を変えて、たとえばアメリカにすると、"April 2012"と表示される。これは地域を判断して適宜な表示方式を作り出す仕組みがシステムに存在するからに他ならない。こういう基本的な事がカレンダーの中だけにしかない、ということはありえない(カレンダーの表示自体はカレンダーの中だけにしかないようだ。なのでカレンダーを作ったのだが)
 このような気の利いた事。つまり、日時の任意の部分を、設定された地域の記述方法に従い取得するにはどうすればいいのか。"2012年4月19日 10時10分24秒"から"2012年4月"だとか、"19日10時"だとかを作り出す方法についてさぐった。

 Foundationでは、日時を表した文字列(NSString)と日時(NSDate)を変換するために、NSDateFormatterというのがある。いちいちいろんなクラスが出てきてめんどくさいが、世界各国地域文化でまったく違う日時の表記方法を制御するためには、これらのクラスの分け方は理にかなっている。それがわかるまではなんでこんなにいろいろとめんどくせえなあ、と思っていた。簡潔に言うとこうなる。

NSDateFormatterは、NSDateをNSStringに、NSStringをNSDateに変換するクラスです

 具体的な話に入る。
 日時を適宜変換するためには、NSDateFormatterに日時の表記方法を指定しなければならない。これにはsetDateFormat:メソッドを使う。これは引数が日時フォーマットをあらわす文字列になっている。これが日時を適宜表す文字列になれば、国や地域に沿った日時文字列を取得できたも同然だ。だが、どう書けばいいのか。

 これを出来合いのものを使って簡単に済ます方法がある。setDateStyle:メソッドと、setTimeStyle:メソッドだ。これらは内部でsetDateFormat:を呼び出している。これは、setDateStyle:後にdateFormat:メソッドで日時フォーマットを取り出してみると変わっていることでわかる。なんだこんな便利なものがあったのか、しめしめと思ったが世の中そんなに便利にはいかない。setDateStyle:の引数であるNSDateFormatterStyleの説明を見ると、今回ほしい"2012年4月"といった表記方法は存在しない。となれば、やはりsetDateFormat:に今回の使用に適した文字列を書くしかない。

 上で書いた、出来合いの日時表記でよければ、地域情報(NSLocale)のデフォルトを使って日時文字列を取得するクラスメソッドがNSDateFormatterにある。localizedStringFromDate:dateStyle:timeStyle:メソッドだ。通常使うにはこれでいいかもしれない。

 話を戻して、"2012年4月"の日時フォーマットはどう書けばいいのか。調べると、NSLocaleに則した日時フォーマットを作り出すらしいクラスメソッドがある事を発見した。dateFormatFromTemplate:options:locale:だ。説明を見てもこれに違いないのだが、このメソッドにもやっぱりテンプレートとやらを指定しなければならない。メソッドの説明にテンプレートの書き方へのリンクもあったが… 日時を表記する手法の幅広さに驚くしかない。試行錯誤の結果、今回やる"2012年4月"は、"yMMMM"と表せばいい事がわかった。Mが4個も続くが、これが"April"と表記する方法だ。これは3個でも5個でもいけない。3個だと"Apr"、5個だと"A"となってしまう。

 今回やった日時の取り出し方を具体的にコードで書いてみる。

NSDateFormatter *dateFmt = [[NSDateFormatter alloc] init];
dateFmt.dateFormat = [NSDateFormatter dateFormatFromTemplate:@"yMMMM" options:0 locale:[NSLocale currentLocale]];

NSString *dateStr = [dateFmt stringFromDate:[NSDate date]]; //現在の日時から文字列を作り出す

[dateFmt release];

 dateFormatFromTemplate:options:locale:が出力する文字列を調べてみたら、日本語では"y年M月"、英語では"MMMM y"になっていた。yMMMMと書いた元の文字列の表記方法がカレントのNSLocaleをもとに変換されている事がわかる。元の文字列を"MMMMy"にしても結果は同じだ。ということは、テンプレートに表記する文字列それぞれ("MMMM"とか"y")とかに意味はあっても、順序に意味はないことになるのかもしれない。順序はNSLocaleを元に作り出されるので、関係あったらまたややこしい話になるし。

 今回はMMMMを使ったが、例えばMMMを使うとどうなるのか。アメリカでは"Apr 2012"、日本では"2012年4月"となる。日本では変化しないが、"4月"を短縮した形式が日本には存在しないので、これで正解だ。NSLocaleを使って自動的に変換する仕組みがうまくやってくれている。

 これで今回の問題は解決した。これを元に、例えば"4月19日"とか、"19日10時”とかいう表記も、フォーマットに"MMMMd"とか、"dH"を指定すればいい。自分が表記したい日時を、任意の地域の方式で表示してやる事が簡単にできるようになった。

 これらはFoundationのクラスとメソッドのみを使っているので、多分OS Xでもそのまま動くはず。これはまだ試してないがそのうち使うかも。

|

« 恣意散歩 | トップページ | ARC使用時の、動的確保されたid配列の扱いについて »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: NSDateFormatterとの戦い:

« 恣意散歩 | トップページ | ARC使用時の、動的確保されたid配列の扱いについて »