2013年10月9日水曜日

続・iOSの日付処理まとめ

Timeletを作成したときに、またもや日付周りでいろいろ悩みました。
そのネタをまとめてみます。
以前日付関連でまとめたブログ記事→ iOSの日付処理まとめ

日付時間フォーマットをiOS設定通りで表示する


NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle: NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
NSLog(@"%@", [dateFormatter stringFromDate:[NSDate date]]);

NSDateFormatterStyle はDate, Time毎に以下から選択します。
  •   NSDateFormatterNoStyle
  •   NSDateFormatterShortStyle
  •   NSDateFormatterMediumStyle
  •   NSDateFormatterLongStyle
  •   NSDateFormatterFullStyle
結果は以下の通り。

書式カレンダー24時間表示結果
Japan西暦2013/10/09 1:08
Japan西暦×2013/10/09 午前1:11
Japan和暦×H25/10/09 1:12
United States西暦Oct 9, 2013, 1:16
United States西暦×Oct 9, 2013, 1:13 AM
United States和暦×Oct 9, 25 Heisei, 1:14 AM

日本だと 0:00 AM である時刻表示は、他の国だと 12:00 AM なんですよね。
12時間表示でも、国によって "01:00 AM" の所もあれば、"1:00 AM" の所もある様子。

知らなかった! 忘れてた! 各国の書式の差をカバーしてくれます。
ただ、文字の長さがどれくらいになるかは設定依存になるので、文字がはみ出さないように画面上にレイアウトするように気をつける必要があります。


日付フォーマット書式


setDateStyle, setTimeStyle ですが、内部ではDateFormatの値に該当する書式を設定してくれています。その結果を見ることで書式の設定方法が分かります。

書式が日本、カレンダーが和暦、24時間表示OFF だと

NSDateFormatter *dateFormatter = [[NSDateFormatter allocinit];
[dateFormatter setDateStyle: NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
NSLog(@"%@", dateFormatter.dateFormat);

の結果は、
GGGGGyy/MM/dd aK:mm 
になります。

指定の文字は何を表しているのかは、LDML DateFormatPatterns で確認できます。

たとえば、時間は
h : 1 〜 12 の12時間表示。
H : 0 〜 23 の24時間表示。
K : 0 〜 11 の12時間表示。
k : 1〜 24 の24時間表示。
hh, HH など2つ重ねると 0Padding です。

書式を固定する


書式に固定したい場合は、NSLocaleを指定します。

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle: NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
NSLog(@"端末の書式:[%@]", dateFormatter.dateFormat);

NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
dateFormatter.locale = locale;
NSLog(@"en_US指定書式:[%@]", dateFormatter.dateFormat);
NSLog(@"結果 : %@", [dateFormatter stringFromDate:[NSDate date]]);

上記の結果は以下。(書式は日本、和暦の設定の場合)

端末の書式:[GGGGGyy/MM/dd H:mm]
en_US指定書式:[MMM d, y, h:mm a]
結果 : Oct 9, 2013, 1:48 PM

日付フォーマットとLocaleを一緒に指定することも可能です。

NSDateFormatter *dateFormatter = [[NSDateFormatter allocinit];
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
dateFormatter.locale = locale;
[dateFormatter setDateFormat:[NSDateFormatter dateFormatFromTemplate:@"
yyyyMMdd hmma" options:0 locale:locale]];
NSLog(@"%@", [dateFormatter stringFromDate:[NSDate date]]);

結果↓
10/09/2013, 2:01 PM

書式を固定すると、各国の表示形式に合わせることはできないので注意。
たとえば、日本でも 0:00 AM でなく、12:00 AM の表示になります。
(hなのか、Kなのか という書式のところ)

常に12時間表示の時刻を表示する


12時間表示の日付フォーマットは @"hhmm a"になるので、これを指定すれば12時間表示を期待するのですが、上手くいかないパターンもあります。

NGパターン1
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"h:mm a"];
NSLog(@"%@", [dateFormatter stringFromDate:[NSDate date]]);

書式カレンダー24時間表示結果
Japan西暦12:36 午前
Japan西暦×12:36 午前
United States西暦0:36
United States西暦×12:36 AM

NGパターン2
NSDateFormatter *dateFormatter = [[NSDateFormatter allocinit];

NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
[dateFormatter setDateFormat:[NSDateFormatter dateFormatFromTemplate:@"hmm a" options:0 locale:locale]];
NSLog(@"%@", [dateFormatter stringFromDate:[NSDate date]]);

書式カレンダー24時間表示結果
Japan西暦12:36 午前
Japan西暦×12:36 午前
United States西暦0:36
United States西暦×12:36 AM

NGパターン3
NSDateFormatter *dateFormatter = [[NSDateFormatter allocinit];

NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
dateFormatter.locale = locale;
[dateFormatter setDateFormat:[NSDateFormatter dateFormatFromTemplate:@"hmm a" options:0 locale:
[NSLocale currentLocale]]];
NSLog(@"%@", [dateFormatter stringFromDate:[NSDate date]]);

書式
カレンダー
24時間表示
結果
Japan
西暦
AM0:36
Japan
西暦
×
AM0:36
United States
西暦
0:36
United States
西暦
×
12:36 AM

OKパターン
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
dateFormatter.locale = locale;
[dateFormatter setDateFormat:[NSDateFormatter dateFormatFromTemplate:@"hmm a" options:0 locale:locale]];
NSLog(@"%@", [dateFormatter stringFromDate:[NSDate date]]);

書式
カレンダー
24時間表示
結果
Japan
西暦
12:36 AM
Japan
西暦
×
12:36 AM
United States
西暦
12:36 AM
United States
西暦
×
12:36 AM


端末の設定で、書式を日本にしていると一見上手くいっているのですが、違う国に設定すると上手くいかないのです。
これにハマった!

OKパターンは、en_US書式固定したパターンです。
端末設定に依存せず12時間表示 かつ 表示形式は端末設定の書式を使う
ができると嬉しいのですが、その方法がみつかりませんでした。
NGパターン3が惜しかったんだけどなー。

12時間表示の設定かどうかを判断する


+ (BOOL)timeIs24HourFormat {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setLocale:[NSLocale currentLocale]];
    [formatter setDateStyle:NSDateFormatterNoStyle];
    [formatter setTimeStyle:NSDateFormatterShortStyle];
    NSString *dateString = [formatter stringFromDate:[NSDate date]];
    NSRange amRange = [dateString rangeOfString:[formatter AMSymbol]];
    NSRange pmRange = [dateString rangeOfString:[formatter PMSymbol]];
    BOOL is24Hour = (amRange.location == NSNotFound && pmRange.location == NSNotFound);
    return is24Hour;

}
• • •