DateFormatterの使い方まとめ

Swiftの`DateFormatter`（Objective-Cでは`NSDateFormatter`）の使い方をまとめました。

## 日付から文字列を取得する

### 規定のStyleを使う

一番簡単なのは`dateStyle`と`timeStyle`を利用する方法。日付、時刻それぞれについて長め、標準、短め、なしの４つのスタイルを選択すると、localeに応じた適切な文字列を生成できる。

```swift:Swift
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .none

let dateString = dateFormatter.string(from: Date())
print(dateString)
```
```objc:Objective-C
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateStyle = NSDateFormatterMediumStyle;
dateFormatter.timeStyle = NSDateFormatterNoStyle;

NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];
NSLog(@"%@", dateString);
```

* ja_JPのとき: 2013/11/26
* en_USのとき: Nov 26, 2013

### 固定のカスタムフォーマット

自由にフォーマットを指定したい場合、`dateFormat`で指定可能。書式は[Unicode Technical Standard #35](http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns)に準拠する。

```swift:Swift
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd 'at' HH:mm"

let date = Date()

let dateString = dateFormatter.string(from: date)
print(dateString)
```
```objc:Objective-C
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy-MM-dd 'at' HH:mm";

NSDate *date = [NSDate date];

NSString *dateString = [dateFormatter stringFromDate:date];
NSLog(@"%@", dateString);
```

注意点

* ユーザーが選択したカレンダー設定が反映される
* 時刻の24時間表記のユーザー設定によって指定したフォーマットが上書きされる

上記コードでlocaleがja_JPの場合、期待される結果はおそらく「2013-11-26 at 23:21」であるが、カレンダーを「和暦」、24時間表示をオフに設定していると、結果は「0025-11-26 at 午後11:21」となってしまう。

これを防ぎたければ、以下のようにlocaleを`en_US_POSIX`に指定する。これは書式が変わらないことが保証されている特別なlocale。

```swift:Swift
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
```
```objc:Objective-C
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
```

### Localeに応じたカスタムフォーマット

表示する要素を自由に選択しつつ、ユーザーのlocaleにあわせた適切なフォーマットで表示したい場合は、`dateFormat(fromTemplate:options:locale:)`を使って適切なフォーマット文字列を取得する。

```swift:Swift
guard let formatString = DateFormatter.dateFormat(fromTemplate: "MMMdd", options: 0, locale: Locale.current) else { fatalError() }
print(formatString)

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = formatString

let date = Date()

let dateString = dateFormatter.string(from: date)
print(dateString)
```
```objc:Objective-C
NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMdd" options:0 locale:[NSLocale currentLocale]];
NSLog(@"%@", formatString);

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = formatString;

NSDate *date = [NSDate date];

NSString *dateString = [dateFormatter stringFromDate:date];
NSLog(@"%@", dateString);
```

* ja_JPのとき
	* フォーマット: M月dd日
	* 結果: 11月26日
* en_USのとき
	* フォーマット: MMM dd
	* 結果: Nov 26
* en_GBのとき
	* フォーマット: dd MMM
	* 結果: 26 Nov

## 文字列から日付を取得する

RFC 3339な日付文字列をパースする例

```swift:Swift
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)

let string = "1985-04-12T23:20:50Z"
let date = dateFormatter.date(from: string)
```
```objc:Objective-C
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
dateFormatter.dateFormat = @"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'";
dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];

NSString *string = @"1985-04-12T23:20:50Z";
NSDate *date = [dateFormatter dateFromString:string];
```

ここでもlocaleを`en_US_POSIX`にしてフォーマットが固定であることを担保している。

## 参考リンク

* [Data Formatting Guide: Date Formatters](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html#//apple_ref/doc/uid/TP40002369-SW1)
* [Date and Time Programming Guide](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/DatesAndTimes/DatesAndTimes.html#//apple_ref/doc/uid/10000039-SW1)