SwiftでDateを自然な方法でフォーマットする【SwiftUI】
iOS18では日付を参照する新しいフォーマットスタイルが追加され、特定の日付を自然な方法でフォーマットできるようになりました。
特定の日付を言及する時、その日付までの距離によってフォーマットを変えるのが自然な方法です。
例えば10分後にイベントが始まる場合は相対的に、イベントは「10分後に」始まる。と書くのが自然です。しかし
例えば10分後にイベントが始まる時、多くの人は相対的に「10分後」イベントが始まると言うでしょう。日付が非常に遠い未来や過去の場合、絶対的な方法で言及する方が簡単になります。例えば、初代iPhoneは「2007年1月に」発表されたと言うでしょう。
新しいフォーマッター
iOS18からはSystemFormatStyle.DateReference
が追加され、便利な機能を使うことができます。
例えば10分後の日付を参照する際は相対的に言及するのが自然なため「10分後」と表示されます。
言語設定が日本語以外でも自動でローカライズしてくれるので、ハードコードする量が減って安心です。
let tenMinutesLaterDate = Date().addingTimeInterval(600)
// in SwiftUI View
Text(.currentDate, format: .reference(to: tenMinutesLaterDate))
フォーマットされた日付と他の文章を繋げる
実際のユースケースとして、「10分後にイベントが始まります」のように「10分後」と"イベントが始まります"をつなげて使いたい場合があります。
SwiftUIでは2通りのやり方があります。
Textの入れ子
Textの中にTextを埋め込むことができます。
Text("\(Text(.currentDate, format: .reference(to: tenMinutesLaterDate))にイベントが始まります)")
Text同士を + でつなげる
Text() + Text()
のように、複数のTextを連結することもできます。
こちらの方法はそれぞれにforegroundStyle
やfont
などのModifierを指定できるので柔軟性が高いです。
Text(.currentDate, format: .reference(to: tenMinutesLaterDate))
+ Text("にイベントが始まります。)
参考資料はこちら
フォーマットされた日付をローカライズする
SystemFormatStyle.DateReference
がせっかくデバイスの言語設定に応じて日付をローカライズしてくれるので、"にイベントが始まります。"の部分もローカライズしましょう
Strings Catalog
等で各言語ごとにローカライズされた文章を用意します
ローカライズできているか確認してみましょう。
.environment(\.locale, Local(identifier: ...))
で日本語環境、英語環境でフォーマットされているか確認してみます。
VStack {
ForEach(["ja_JP", "en_US"], id: \.self) { localeID in
HStack {
Image(systemName: "calendar.badge.clock")
Text("next event is up \(Text(.now, format: .reference(to: tenMinutesLaterDate)))")
.environment(\.locale, Locale(identifier: localeID))
}
.bold()
.foregroundStyle(.white)
.padding(16)
.background(.pink.gradient)
.clipShape(.capsule(style: .continuous))
.padding()
}
}
いい感じにローカライズされました
参考・関連資料
Discussion