18
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

iOSでISO8601を扱う

Last updated at Posted at 2018-02-13

ISO8601とは

日付や時間を文字列形式で表現する際のフォーマット1です。
WebサービスのAPIなどでよく使われます。

表記方法には、大きく分けると基本形式と拡張形式の2つがあります。

iOSでの書式指定 出力例
基本形式 yyyyMMdd'T'HHmmssZZZZZ 20180214T003318+09:00
拡張形式 yyyy-MM-dd'T'HH:mm:ssZZZZZ 2018-02-14T00:33:18+09:00

※ 余談ですが、iOSでの書式指定では、年(yyyy)と日(dd)の部分は必ず小文字にしましょう。

iOSでの変換方法

通常、iOSで日付(Date)と文字列の相互変換にはDateFormatterを使います。上の表に記載したのと同じ書式を指定すればISO8601形式も変換できます。

iOS10またはmacOS10.12以降であれば、ISO8601形式の場合は専用のISO8601DateFormatterが使えます。

Xcode9.2時点ではDateFormatterの動作も問題なさそうですが、Appleのドキュメントでは、

DateFormatter

と記載されているので、使える場合はISO8601DateFormatterを使った方が良いです。

ISO8601DateFormatterの使い方

ISO8601DateFormatterDateFormatterとよく似ています。

基本的な使い方は、

let fmt = ISO8601DateFormatter()

という様に生成してから、

// ISO8601表記の文字列から日付(Date)へ変換
fmt.date(from: "2018-02-14T00:51:31+09:00")

// 日付(Date)からISO8601表記の文字列へ変換
fmt.string(from: Date()) // 2018-02-13T15:51:31Z

となります。

フォーマット指定

デフォルトでのフォーマットは、拡張形式(yyyy-MM-dd'T'HH:mm:ssZZZZZ)となります。
フォーマットを変更したい場合は、ISO8601DateFormatter.Options2を指定します。

例えば、日付のみを"-"区切りで表示したい場合は、

let fmt = ISO8601DateFormatter()
fmt.formatOptions = .withFullDate
fmt.string(from: Date()) // 2018-02-14

と指定できます。

RFC 3339形式

RFC33393形式の表記にしたい場合は、ISO8601DateFormatter.Options.withInternetDateTimeを指定します。

タイムゾーンの指定

特に何も指定しなかった場合、タイムゾーンはUTCとして扱われます。
現地時間での表記にしたい場合は、次の様にtimeZoneを指定します。

fmt.timeZone = TimeZone.current

この場合、端末のタイムゾーンが日本(JST)になっていれば、+09:00での表記となります。

yyyyMMdd'T'HHmmssZZZZZ形式

ISO8601の基本形式で表記したい場合は、少し工夫が必要となります。
というのも、デフォルトの形式から"-"や":"を取り除いたものが基本形式となりますが、フォーマットのオプションとしてそれらを取り除く様なオプションが存在していないからです。

では、どうするかというと以下の様に指定します。


let fmt = ISO8601DateFormatter()

var opt: ISO8601DateFormatter.Options = [.withFullDate, .withFullTime]
opt.remove([.withDashSeparatorInDate, .withColonSeparatorInTime, .withColonSeparatorInTimeZone])
fmt.formatOptions = opt

fmt.timeZone = TimeZone.current    // 現地時間表記の場合
fmt.string(from: Date())           // 20180214T005131+0900

ポイントは、opt.remove()の部分です。このremoveで、指定したオプションを除外しています。

例えば、.withFullDateには元から.withDashSeparatorInDateの指定が含まれている為、日付の表記には"-"が入ってしまいます。それでremoveを使い、.withDashSeparatorInDateの指定を取り除くことで"-"のない表記にしています。

これは、ISO8601DateFormatter.OptionsOptionSetという型なのでできる方法です。このOptionSetはいわゆるビットフラグと同じ仕組みで、特定のオプションを追加するだけでなく、簡単に除外することも可能です。便利ですね。

まとめ

ISO8601形式の表記を扱う時は、ISO8601DateFormatterを使いましょう。
yyyyMMddの表記の場合の様に細かいことを考えなくて良いので楽です。
OptionSetを上手く使えば、柔軟なフォーマットの設定も可能です。

ちなみに、通常のDateFormatterとの速度の違いは見ていません・・・

  1. 規格の定義はISO8601を参照

  2. 指定できるオプションの一覧はISO8601DateFormatter.Optionsを参照

  3. 規格の定義はRFC3339を参照

18
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?