Date型とDateComponents型の相互関係
はじめに
Swiftでプログラミングをするうえで、日付を取り扱うことは比較的よくあるユースケースの1つでしょう。
実際に実務で日付を取り扱う際にはDate型やDateComponents型などを利用するケースが多いと思います。
その一方でDate型とDateComponents型には考え方に大きな違いがあり、この考え方の違いを踏まえて実装しないと意図した日付を表現できないという問題が発生します。
本記事ではDate型の説明から始まり、DateComponents型を利用して日付を表現する際に気をつける必要がある点について、説明します。
Date型とは
SwiftにおけるDate型とは、CalendarやTimeZoneに依存しない特定の日付を表す型になります。
これにより、CalendarやTimeZoneに依存しない形で「2025年1月28日 13:00:00」などの特定の時間を表現できます。
Date型は下記2つのイニシャライザによって生成可能です。
init(timeIntervalSinceReferenceDate: TimeInterval)
init(timeIntervalSince1970: TimeInterval)
引数で「ReferenceDate」と書かれている日付は2001年1月1日00:00:00 UTCを指しており、この点からの経過秒数によって内部表現を行っているようです。
このとき基準として使っている「2001年1月1日 00:00:00 UTC」の日付を参照日付、またはエポックと呼びます。
よくある日付型は1970年1月1日の00:00:00 UTCからの経過秒数によって日付を表現していますが、UNIXでよく使われるエポックとは異なるのが留意点かもしれません。
とはいえUNIXエポックからの初期化もサポートされますので、実務上の影響は無いと言えるでしょう。
Date型とDateComponents型との関係性
前述の通りDate型を利用することでCalendarやTimeZoneに依存しないで特定の日付を表現することができます。
その一方で、プログラム上で年や時間、日付などのCalendarやTimeZoneに依存する情報を用いて日付を表現したいケースもあります。
このときDateComponents型を利用することで、この問題を解決できます。
DateComponentsの性質上CalendarとTimeZoneに依存しているため、DateComponentsの説明を行う前にそれぞれの説明を行います。
- Calendar
- TimeZone
Calendar
Calendarは、人間は日付を扱う先にセットで取り扱っている「暦」に関する情報を保持するものです。
我々日本人はグレゴリオ暦をよく使いますが、別の暦として和暦や太陰暦もあります。
各々の暦において「1月」の概念が異なるケースも有るため単純に「1月先」といっても各暦事でおいて意図する日付が変わったりします。
このときCalendarを利用することで、意図する日付が違う問題問題を解決できます。
TimeZone
TimeZoneとはグリニッジ標準時からのズレを表現します。
グリニッジ標準時とは、イギリスにあるグリニッジ天文台での時間を基準時間とした時間です
日本においては日本標準時という名称にもなっており、これはグリニッジ標準時に対して+9時間になります。
グリニッジ標準時はGMTで省略されるため、GMT+9という表現もします。
DateComponents型について
DateComponents型はCalendarとTimeZoneを利用して、年や日付、時刻などの時間を構成する要素を使ってDateを表す型です。
その性質上CalendarとTimeZoneに依存するため、これらの設定が正しくない場合は、意図したDateを表すことができないケースがあります。
DateComponentsを初期化する際は下記関数を利用します。
init(calendar: Calendar?, timeZone: TimeZone?, era: Int?, year: Int?, month: Int?, day: Int?, hour: Int?, minute: Int?, second: Int?, nanosecond: Int?, weekday: Int?, weekdayOrdinal: Int?, quarter: Int?, weekOfMonth: Int?, weekOfYear: Int?, yearForWeekOfYear: Int?)
注意点として、初期化の際にCalendarとTimeZoneの指定を行わなかった場合は、端末に設定されているCalendarとTimeZoneが利用されます。
このため、DateComponentsを生成するときは、これから設定しようとしている時刻コンポーネントが依存しているCalnedarとTimeZoneを利用して初期化することが何よりも重要です。
終わりに
Swiftでプログラムを記述する際に日付を取り扱う情報としてDate型とDateComponents型が利用できますが、ここまで記述してきたようにCalendarとTimeZoneの概念を抑えてプログラムを行わない場合、意図した日付を取り扱うことができないケースが発生します。
特にDateComponents型を利用する場合は、プログラム上で取り扱う時間コンポーネントがどのCalendarとTimeZoneの情報なのかに注意して実装してください。
参考リンク
参考にしたリンクです。
- https://developer.apple.com/documentation/foundation/date
- https://developer.apple.com/documentation/foundation/locale
- https://developer.apple.com/documentation/foundation/calendar
- https://developer.apple.com/documentation/foundation/timezone
- https://ja.wikipedia.org/wiki/協定世界時
- https://developer.apple.com/documentation/foundation/datecomponents
おまけ
Locale
Localeとは各言語ごとの日付の省略記法や、小数点、通貨表記などの、言語ごとの設定方法をまとめたものです。
イメージしやすいものとしては、「2025年1月1日」と表現するか「Jan 1, 2025」と表現するかなどが挙げられます。
また状況によって致命的になりうるものとして小数点を表す「.」が別のLocaleでは「,」で表現されていることなどが挙げられます。
これらの点から、Localeを正しく設定しない場合、テキストで表現された情報を処理する際に意図しない形で処理をしてしまったり、ユーザーが期待する記法とは異なる記法でユーザーに提示してしまう可能性があります。
Discussion