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")
}
}
}
