Swift に限った話ではありませんが、 日付 や 時刻 を扱う際に、特定の地域のみを対象にする場合は タイムゾーン や 時差 を意識することはありませんが、 グローバル な ユーザ を対象とする場合は、 ユーザ の ローカル 時間帯 を意識することがユーザの利便性向上につながります。 本記事では、 UTC で表現された 日付文字列 を タイムゾーン を意識しながら管理し、 別の タイムゾーン で表示する方法について整理していきます。
Xcode: 13.0 iOS: 14.5 Swift: 5
今回実現すること
今回は、 “2021-10-06T18:45:00+00:00” という UTC で表現された文字列を扱い、これを様々なタイムゾーンで表示してみます。。
例えば JST の場合、 UTC に +9 時間足した 2021年10月7日 3:45 AM と表示することを目指します。
Timezone の表示
まずは百聞は一見にしかずということで、 「 現在時刻 」 と 「 現在の タイムゾーン 」 を表示する View を作成して内容をみてみます。
struct DateTimeTzView: View { var body: some View { VStack(alignment: .leading) { HStack { Text("Current Time: ") Text(Date().description(with: .current)) .foregroundColor(Color.blue) } Divider() HStack { Text("Timezone: ") Text(TimeZone.current.abbreviation()!) .foregroundColor(Color.orange) } } .padding() } }
システムの設定を 日本 としているため、 以下のような結果となっています。
- Locale: Japan Standard Time (JST)
- Timezone: GMT+9
システム の設定を ロンドン に変更するとこの内容が変化していきます。
- Locale: British Summer Time (BST)
- Timezone: GMT+1
以降では、このように 文字列 を タイムゾーン を意識して扱い、 ユーザ が所属する タイムゾーン 別に表示を変更する方法を整理していきます。
日付文字列 を Date 型に変換
@State 変数の用意
それでは、日付文字列 を Date 型に変換していきます。最初に、アプリ上で 文字列や フォーマット の指定可能にするため、 @State として以下の 3 つの変数を用意します。
@State private var dateString = "2021-10-06T18:45:00+00:00" @State private var dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" @State private var dateObject: Date = Date()
入力領域と変換後の出力領域の作成
続いて、 日付文字列 と フォーマット 形式、 加えて Date 型に変換した結果 を表示する View を作成していきます。
VStack(alignment: .leading) { HStack { Text("Date String & Format: ") VStack { TextField("date string", text: $dateString) .foregroundColor(Color.red) TextField("date format", text: $dateFormat) .foregroundColor(Color.green) } } Divider() HStack { Text("Date Object: ") Text(dateObject.description(with: .current)) .foregroundColor(Color.blue) } Divider() HStack { Text("Timezone: ") Text(TimeZone.current.abbreviation()!) .foregroundColor(Color.orange) } }
変換処理 の作成
続いて、 変換処理 を実装していきます。 今回は 文字列 として処理するのは UTC で表現されたものとしています
private func convDate() { let dateFormatter = DateFormatter() let timeZone = TimeZone(abbreviation: "UTC") dateFormatter.dateFormat = dateFormat dateFormatter.timeZone = timeZone if let date = dateFormatter.date(from: dateString) { dateObject = date } else { print("dateFormatter Failed") } }
Date型 への 変換処理 については、以下の記事でも紹介していますので、参考にしてください。
様々な パターン に対応した フォーマット の指定方法
以下の サイト に様々な パターン に対応した フォーマット 指定方法が紹介されていますので、参考にしてください。
動的な変換処理の実装
最後に、 文字列の入力に応じて動的に Date型への変換処理を実施するようにします。
.onAppear { convDate() } .onChange(of: dateString) { newValue in convDate() } .onChange(of: dateFormat) { newValue in convDate() }
作成したアプリの動作 ( 日付文字列 から タイムゾーンを意識した Date型 の表示 )
JST として表示
システムの時間帯を JST ( GMT+) として表示すると、想定したとおり 10月7日3:45 AM となっています (青文字)
BST として表示
システムの時間帯を BST (GMT+1) とすると、それに追随して Date Object の内容(青文字)も変化します。
年またぎにも対応しています。
まとめ
- Swift では 現在時刻は Date().description(with: .current)) で取得可能
- Swift では 現在のタイムゾーンは TimeZone.current.abbreviation()! で取得可能
- UTC として 日付文字列を扱う場合は dateFormatter.timezone に TimeZone(abbreviation: “UTC”) を指定
関連記事
参照情報
今回作成した全ソースコード
// ContentView.swift import SwiftUI struct ContentView: View { var body: some View { DateTimeTzView() .padding() } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
// DateTimeTzView.swift import SwiftUI struct DateTimeTzView: View { @State private var dateString = "2021-10-06T18:45:00+00:00" @State private var dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" @State private var dateObject: Date = Date() var body: some View { VStack(alignment: .leading) { HStack { Text("Date String & Format: ") VStack { TextField("date string", text: $dateString) .foregroundColor(Color.red) TextField("date format", text: $dateFormat) .foregroundColor(Color.green) } } Divider() HStack { Text("Date Object: ") Text(dateObject.description(with: .current)) .foregroundColor(Color.blue) } Divider() HStack { Text("Timezone: ") Text(TimeZone.current.abbreviation()!) .foregroundColor(Color.orange) } } .padding() .onAppear { convDate() } .onChange(of: dateString) { newValue in convDate() } .onChange(of: dateFormat) { newValue in convDate() } } private func convDate() { let dateFormatter = DateFormatter() let timeZone = TimeZone(abbreviation: "UTC") dateFormatter.dateFormat = dateFormat dateFormatter.timeZone = timeZone if let date = dateFormatter.date(from: dateString) { dateObject = date } else { print("dateFormatter Failed") } } }