日付書式


日付の文字列表現を作成し、文字列を解析して、日付書式を使用して日付オブジェクトを取得するには、それぞれ dateFromString: および stringFromDate: 使用する 2 つの基本的なメソッドがあります。解析したい文字列の範囲をより詳細に制御する必要がある場合、getObjectValue:forString:range:error: も使えます。


日付書式で取得および設定できる多くの属性があります。ユーザーに情報を提示するときは、通常、単に NSDateFormatter スタイル定数を使用して、書式設定された日付の表示方法を決定する、事前に定義された属性セットを指定する必要があります。ただし、正確な書式の日付表現を生成する必要がある場合は、書式文字列を使用する必要があります。


日付文字列を解析する必要がある場合は、再度行うアプローチは、達成したいことによって異なります。ユーザーからの入力を解析したい場合は、通常、スタイル定数を使用して期待値に一致させる必要があります。たとえば、データベースやWeb サービスから取得した日付を解析したい場合は、書式文字列を使用する必要があります。


いずれの場合でも、ユーザーのロケール (currentLocale) とユーザーの設定を重ね合わせて使用するように書式をデフォルトにすることを検討してください。ユーザーのロケールを個別の設定なしで使用したい場合は、現在のユーザーロケール (localeIdentifier) からロケール ID を取得し、新しい "標準" ロケールをそれから作成してから、標準ロケールを書式の locale として設定できます。


書式スタイルを使用して現在の日付と時刻をユーザーの設定に


NSDateFormatter を使用すると、システム環境設定の "インターナショナル" 環境設定パネル (訳注: 現在は "日付と時刻" です) で構成したユーザーの設定を使用して日付を簡単にフォーマットできます。NSDateFormatter スタイル定数、すなわち NSDateFormatterNoStyle、NSDateFormatterShortStyle、NSDateFormatterMediumStyle、NSDateFormatterLongStyle、および NSDateFormatterFullStyle であり、ユーザーの設定に従って日付を表示する方法を決定する属性のセットを指定します。


setDateStyle: および setTimeStyle: をそれぞれ使用して、日付書式の日付および時刻の構成部分のスタイルを個別に指定して下さい。リスト 1 は、書式スタイルを使用して日付をフォーマットする方法を示しています。NSDateFormatterNoStyle を使用して時間の構成部分を抑制し、日付だけを含む文字列を生成することに注目してください。


リスト 1 : 書式スタイルを使用した日付の書式設定


NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
 
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:162000];
 
NSString *formattedDateString = [dateFormatter stringFromDate:date];
NSLog(@"formattedDateString: %@", formattedDateString);
// Output for locale en_US: "formattedDateString: Jan 2, 2001".


書式文字列を使用してカスタム書式の指定


大まかに言って、カスタム書式を使用する必要がある 2 つの場合があります。


  1. インターネットの日付のような固定書式文字列の場合。
  2. どの既存のスタイルとも一致しないユーザーに可視の要素

固定書式


日付書式のカスタム固定フォーマットを指定するには、setDateFormat: を使用して下さい。書式文字列は、Unicode 技術標準#35 の書式パターンを使用します。標準のバージョンは、オペレーティングシステムのリリースによって異なります。


基本的に書式文字列は固定フォーマットを指定しますが、デフォルトでは NSDateFormatter はユーザーの環境設定 (ロケール設定を含む) を考慮します。書式文字列を使用するときは、以下の点を考慮しなければなりません。


Unicode 書式文字列フォーマットでは、アポストロフィ (' ') で書式文字列内のリテラルテキストを囲む必要があります。


以下の例は、書式文字列を使用して文字列を生成する方法を示しています。


NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd 'at' HH:mm"];
 
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:162000];
 
NSString *formattedDateString = [dateFormatter stringFromDate:date];
NSLog(@"formattedDateString: %@", formattedDateString);
// For US English, the output may be:
// formattedDateString: 2001-01-02 at 13:00


この例については、2つの注意点があります。


  1. yyyy を使用して年の構成部分を指定します。よくある間違いは、YYYY を使用することです。yyyy は暦年を指定し、一方 YYYY は ISO の年週カレンダーで使用される年 ("Week of Year") を指定します。ほとんどの場合、yyyyYYYY は同じ数字を返しますが、異なる場合があります。通常、暦年を使用する必要があります。
  2. 時間の表現は 13:00 であってもよい。ただし、iOS では、ユーザーが 24 時間制をオフに切り替えると、1:00 pm になることがあります。

ユーザー閲覧可能な日付のカスタム書式


特定の要素のセットを含む日付を表示するには、dateFormatFromTemplate:options:locale: を使用して下さい。このメソッドは、使用したい日付の構成部分を含む書式文字列を生成しますが、ユーザーに適した正しい句読点と順序 (つまり、ユーザーのロケールと環境設定に合わせてカスタマイズされた) を使用します。そして書式文字列を使用して書式を作成します。


たとえば、現在のロケールを使用して今日の曜日、日、月を表示する書式を作成するには、以下のように記述します。


NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"EdMMM" options:0
                                          locale:[NSLocale currentLocale]];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:formatString];
 
NSString *todayString = [dateFormatter stringFromDate:[NSDate date]];
NSLog(@"todayString: %@", todayString);


この必要性を理解するには、曜日、日、月を表示したい場合を考えます。書式スタイルを使用して日付のこの表現を作成することはできません (年を省略するスタイルはありません)。しかし、書式文字列を使って 簡単に一貫して 表現を正しく作成することもできません。しかし一見すると、単純なように思えるかもしれませんが、厄介な問題があります。アメリカのユーザーは、通常、"Mon,Jan 3" の形式で日付を期待しますが、一方英国のユーザーは通常、 "Mon 31 Jan" の形式の日付を期待します。


以下の例は、この点を示しています。


NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
NSString *usFormatString = [NSDateFormatter dateFormatFromTemplate:@"EdMMM" options:0 locale:usLocale];
NSLog(@"usFormatterString: %@", usFormatString);
// Output: usFormatterString: EEE, MMM d.
 
NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"];
NSString *gbFormatString = [NSDateFormatter dateFormatFromTemplate:@"EdMMM" options:0 locale:gbLocale];
NSLog(@"gbFormatterString: %@", gbFormatString);
// Output: gbFormatterString: EEE d MMM.


日付文字列の解析


NSFormatter から継承されたメソッド (getObjectValue:forString:errorDescription : のような) に加えて、NSDateFormatterdateFromString: および getObjectValue:forString:range:error: を追加します。これらのメソッドを使用すると、NSDateFormatter オブジェクトをコード内で直接使用することが容易になり、日付を文字列に整形するのが NSString 書式よりも複雑で便利になります。


getObjectValue:forString:range:error: メソッドは、解析される文字列の部分範囲を指定し、実際に解析された文字列の範囲を返します (失敗の場合は、どこで失敗したかを示します)。また、NSFormatter から継承した getObjectValue:forString:errorDescription: メソッドによって返された失敗文字列よりも豊富な情報を含む NSError オブジェクトも返します。


固定書式の日付で作業している場合は、最初に日付書式の ロケール を固定書式に適したものに設定する必要があります。ほとんどの場合、最適なロケールは en_US_POSIX です。en_US_POSIX は、ユーザーとシステムの両方の環境設定にかかわらず、US English の結果が得られるように特別に設計されたロケールです。en_US_POSIX はまた時間的に不変でもあります (US が、将来のある時点で、日付の書式を変更する場合、en_US は新しい動作を反映するように変更されますが、en_US_POSIX は変更されません)、プラットフォーム間でも変化しません(en_US_POSIX は iPhone OS でも OS X と同じように動作し、他のプラットフォームでも同様です)。


en_US_POSIX を日付書式のロケールに一度設定すると、日付書式文字列を設定することができ、日付書式はすべてのユーザに対して一貫して動作します。


リスト 2 は、上記に示した両方の役割に対して NSDateFormatter を使用する方法を示しています。最初に、en_US_POSIX 日付フォーマッタを作成して、到来する RFC 3339 の日付文字列を解析し、固定日付書式文字列と UTC を時間帯として使用します。次に、日付をユーザーに表示する文字列としてレンダリングする標準の日付書式を作成します。


リスト 2 : RFC 3339 の日付時刻の解析


- (NSString *)userVisibleDateTimeStringForRFC3339DateTimeString:(NSString *)rfc3339DateTimeString {
    /*
      Returns a user-visible date time string that corresponds to the specified
      RFC 3339 date time string. Note that this does not handle all possible
      RFC 3339 date time strings, just one of the most common styles.
     */
 
    NSDateFormatter *rfc3339DateFormatter = [[NSDateFormatter alloc] init];
    NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
 
    [rfc3339DateFormatter setLocale:enUSPOSIXLocale];
    [rfc3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
    [rfc3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
 
    // Convert the RFC 3339 date time string to an NSDate.
    NSDate *date = [rfc3339DateFormatter dateFromString:rfc3339DateTimeString];
 
    NSString *userVisibleDateTimeString;
    if (date != nil) {
        // Convert the date object to a user-visible date string.
        NSDateFormatter *userVisibleDateFormatter = [[NSDateFormatter alloc] init];
        assert(userVisibleDateFormatter != nil);
 
        [userVisibleDateFormatter setDateStyle:NSDateFormatterShortStyle];
        [userVisibleDateFormatter setTimeStyle:NSDateFormatterShortStyle];
 
        userVisibleDateTimeString = [userVisibleDateFormatter stringFromDate:date];
    }
    return userVisibleDateTimeString;
}


効率のため書式をキャッシュ


日付書式の作成は安価な操作ではありません。書式を頻繁に使用する可能性がある場合は、複数のインスタンスを作成して破棄するよりも、単一のインスタンスをキャッシュするほうが効率的です。1 つのアプローチは static 変数を使用することです。


リスト 3 は、リスト 2 に示したメソッドを再実装して、その後の再利用のために日付書式を保持します。


リスト 3 : キャッシュした書式を使用して RFC 3339 の日時を解析


static NSDateFormatter *sUserVisibleDateFormatter = nil;
 
- (NSString *)userVisibleDateTimeStringForRFC3339DateTimeString:(NSString *)rfc3339DateTimeString {
    /*
      Returns a user-visible date time string that corresponds to the specified
      RFC 3339 date time string. Note that this does not handle all possible
      RFC 3339 date time strings, just one of the most common styles.
     */
 
    // If the date formatters aren't already set up, create them and cache them for reuse.
    static NSDateFormatter *sRFC3339DateFormatter = nil;
    if (sRFC3339DateFormatter == nil) {
        sRFC3339DateFormatter = [[NSDateFormatter alloc] init];
        NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
 
        [sRFC3339DateFormatter setLocale:enUSPOSIXLocale];
        [sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
        [sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    }
 
    // Convert the RFC 3339 date time string to an NSDate.
    NSDate *date = [rfc3339DateFormatter dateFromString:rfc3339DateTimeString];
 
    NSString *userVisibleDateTimeString;
    if (date != nil) {
        if (sUserVisibleDateFormatter == nil) {
            sUserVisibleDateFormatter = [[NSDateFormatter alloc] init];
            [sUserVisibleDateFormatter setDateStyle:NSDateFormatterShortStyle];
            [sUserVisibleDateFormatter setTimeStyle:NSDateFormatterShortStyle];
        }
        // Convert the date object to a user-visible date string.
        userVisibleDateTimeString = [sUserVisibleDateFormatter stringFromDate:date];
    }
    return userVisibleDateTimeString;
}

日付書式 (またはユーザの現在のロケールに依存する他のオブジェクト) をキャッシュする場合は、NSCurrentLocaleDidChangeNotification 通知に登録し、現在のロケールが変更したときに、キャッシュされたオブジェクトを更新する必要があります。リスト 3 のコードは、メソッドの外で sUserVisibleDateFormatter を定義しているため、他のコード (示さず) が必要に応じて更新できます。対照的に、sRFC3339DateFormatter は、設計上、ユーザーのロケール設定に依存しないため、メソッド内で定義されています。


注意: 理論的には、自動更新ロケール(autoupdatingCurrentLocale) を使用して、ユーザーのロケール設定内の変更を自動的に考慮するロケールを作成することができます。実際上、これは現在、日付書式では機能しません。


固定書式のローカライズされていない日付用の Unix 関数の検討


固定した、ローカライズされていないカレンダーの日付と時刻は、常に同じカレンダーを使用することが保証されていますが、標準の C ライブラリ関数 strptime_lstrftime_l を使用する方がより簡単で効率的な場合があります。


C ライブラリには現在のロケールのアイデアもあることに注意してください。固定の日付書式を保証するには、これらのルーチンの loc パラメータとして NULL を渡す必要があります。これにより、POSIX ロケール (C ロケールとも呼ばれます) が使用され、これは、この例に示すように、Cocoa の en_US_POSIX ロケールに相当します。


struct tm  sometime;
const char *formatString = "%Y-%m-%d %H:%M:%S %z";
(void) strptime_l("2005-07-01 12:00:00 -0700", formatString, &sometime, NULL);
NSLog(@"NSDate is %@", [NSDate dateWithTimeIntervalSince1970: mktime(&sometime)]);
// Output: NSDate is 2005-07-01 12:00:00 -0700


前の章 次の章



目次
Xcode の新機能

Cocoa のデータ書式プログラミングガイドへの序言
この文書の構成
  • 日付書式
  • 書式スタイルを使用して現在の日付と時刻をユーザーの設定に
  • 書式文字列を使用してカスタム書式の指定
  • 日付文字列の解析
    効率のため書式をキャッシュ
    固定書式のローカライズされていない日付用の Unix 関数の検討
  • 数値書式
  • 書式スタイルを使用してユーザーの設定で数値を表示
    書式文字列を使用してカスタム書式を指定
    パーセント
    命名法
  • 書式とユーザインタフェース要素
  • セルと書式の関連付け
    エラー処理用デリゲートメソッド
    カスタム書式の作成
    文書改訂履歴












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)












    トップへ(Core Foundation)