【Swift】Calendar構造体の使い方!暦法の変更と日付の計算
この記事からわかること
- SwiftのCalendar構造体の使い方
- ユーザー端末のカレンダー情報を取得する方法
- グレゴリオ暦(西暦)などの暦法を指定する方法
- 日付の一部(年、月、日など)だけを取得をする方法
- Calendar.Identifier型の種類
- Calendar.Component型の種類
- 日付の差分や加算、減算などの計算方法
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
参考文献: API Collection Dates and Times
Swiftの日付や時間操作API
Swiftでは日付や時間などを操作、管理するためにいくつかの構造体やクラスが基礎となるFoundationフレークワークの中に用意されています。
Date構造体
・・・日付(カレンダーやタイムゾーンと無関係)
DateInterval構造体
・・・期間
TimeIntervalタイプエイリアス
・・・秒数(Double型のエイリアス)
DateComponents構造体
・・・日付(カレンダーやタイムゾーン)
Calendar構造体
・・・カレンダー
TimeZone構造体
・・・タイムゾーン
DateFormatterクラス
・・・文字列表現など
ざっくり見ると上記の通りです。それぞれ日時に関する機能を提供するAPIですが細かい役割が異なります。
おすすめ記事
【Swift UI】typealias(タイプエイリアス)の使い方とメリット
【Swift】DateFormatterの使い方!書式や日付形式の調整方法
【Swift】DateComponentsとは?使用方法とDate型との違い
【Swift】Date構造体の使い方!日付の計算や比較方法
Calendar構造体とは?
Calendar
構造体とは暦単位の日時情報を定義するオブジェクトです。Swiftで日時情報を扱う上でDate
型は欠かせませんが、Date型はあくまで特定の日時を表現するオブジェクトであり、カレンダーやタイムゾーンとは基本的には無関係です。
カレンダーやタイムゾーンから特定の日時情報(Date型)を参照することで曜日や国ごとの時差などを識別することが可能になります。
Calendar
構造体は暦(こよみ:グレゴリオ暦や和暦など)の設定や曜日情報、日付の差分、計算、比較など日時に纏わる機能を提供しています。
ユーザー端末のカレンダーインスタンスを取得する
ユーザーによって言語や暦などが異なるのはいうまでもありませんが、アプリを開発する際にはそのユーザーや地域に沿ったカレンダー情報を適切に扱う必要があります。Calendar
構造体ではユーザーが端末で指定しているカレンダー情報を取得するcurrent
プロパティを保持しています。
let calendar = Calendar.current
任意の暦法のインスタンスを生成する
端末に倣ったものではなく、任意の暦法のカレンダーインスタンスを生成したい場合はinit(identifier:)
を使用します。引数には列挙型Calendar.Identifier
で定義された値を渡します。例えばグレゴリオ暦(西暦)の場合は.gregorian
を指定します。
let calendar = Calendar(identifier: .gregorian)
Calendar.Identifier型の種類
指定できるCalendar.Identifier型は以下の通りです。
値 | 説明 |
---|---|
gregorian | グレゴリオ暦を使用するカレンダー |
buddhist | 仏教の伝統に基づいたカレンダー |
chinese | 中国の伝統的な太陰太陽暦に基づいたカレンダー |
coptic | コプト正教会の暦に基づいたカレンダー |
ethiopicAmeteMihret | エチオピア正教会の暦に基づいたカレンダー |
ethiopicAmeteAlem | エチオピアの一般的な暦に基づいたカレンダー |
hebrew | ユダヤ暦に基づいたカレンダー |
indian | ヒンドゥー教やジャイナ教など、インド亜大陸の伝統的なカレンダーに基づいたカレンダー |
islamic | イスラム暦に基づいたカレンダー |
islamicCivil | イスラム暦の文明暦に基づいたカレンダー |
japanese | 日本の伝統的な太陽暦に基づいたカレンダー |
persian | ペルシャ暦に基づいたカレンダー |
republicOfChina | 中華民国(台湾)のカレンダー |
iso8601 | ISO8601 カレンダーの識別子。 |
日付(Date構造体)の生成
Calendar構造体からDate構造体を生成することも可能です。生成するためのメソッドは複数用意されているので使い方を見ていきます。
date(from:DateComponents)メソッド
date(from:DateComponents)
メソッドはDateComponents
型からDate型を生成するメソッドです。
let calendar = Calendar(identifier: .gregorian)
var dateComponent = DateComponents(calendar: Calendar.current, year: 2022, month: 10, day: 4)
let date = calendar.date(from: dateComponent)
print(date)
// Optional(2022-10-03 15:00:00 +0000)
逆にDate
型からDateComponents
型を生成するにはdateComponents(in:from:)
メソッドを使用します。
let calendar = Calendar(identifier: .gregorian)
var dateComponent = calendar.dateComponents(in: TimeZone.current, from: Date())
print(dateComponent)
// 結果:calendar: gregorian (fixed) timeZone: Asia/Tokyo (fixed (equal to current)) era: 1 year: 2023 month: 4 day: 18 hour: 19 minute: 17 second: 8 nanosecond: 276412963 weekday: 3 weekdayOrdinal: 3 quarter: 0 weekOfMonth: 4 weekOfYear: 16 yearForWeekOfYear: 2023 isLeapMonth: false
startOfDay(for: Date)メソッド
startOfDay(for: Date)
メソッドは引数に渡したDate型の最初の瞬間(= 0時00分00秒)のインスタンスを生成します。例えば以下のように現在時刻を保持したインスタンスから時間を初期化したインスタンスを生成できます。
llet calendar = Calendar(identifier: .gregorian)
let now = Date() // 現在日時インスタンスを生成
// 時刻を初期化したインスタンスを生成
let startToday = calendar.startOfDay(for: now)
print(startToday)
// 2023-04-17 15:00:00 +0000
print(startToday.description(with: Locale(identifier: "ja_JP")))
// 2023年4月18日 火曜日 0時00分00秒 日本標準時
DateオブジェクトはUTC(協定世界時)で日時情報を保持しているためであり、そのままprint
するとUTCと日本標準時(JTC)との誤差分(9時間)ズレてしまうため注意してください。
年や月、日など一部のみを取得
Calendar
構造体のcomponent(_:from:)
メソッドを使用して年や月、日など一部のみを取得することも可能です。
func component(
_ component: Calendar.Component,
from date: Date
) -> Int
引数には取得したい一部をCalendar.Component型
で渡します。
let calendar = Calendar.current
let now = Date() // "Apr 18, 2023 at 7:31 PM"
let day = calendar.component(.day, from: now)
print(day) // 18
Calendar.Component型
指定できるCalendar.Component型は以下の通りです。
値 | 説明 |
---|---|
era | 年代 |
year | 年 |
quarter | 四半期 |
month | 月 |
weekOfMonth | 月の中での週 |
weekOfYear | 年の中での週 |
weekday | 週の曜日 |
weekdayOrdinal | 週の中での曜日の順序 |
day | 日 |
hour | 時 |
minute | 分 |
second | 秒 |
nanosecond | ナノ秒 |
calendar | カレンダー |
timeZone | タイムゾーン |
quarterOfYear | 年の中での四半期 |
weekOfQuarter | 四半期の中での週 |
日付の計算
Calendar
構造体を使用して任意の日付(Date構造体)に対しての加算や減算、任意の日付(Date構造体)間同士の期間の計算などを行うメソッドも用意されています。
date(byAdding:,value:,to:)メソッド
date(byAdding:,value:,to:)
メソッドを使用することで任意の日付から2日後や3日前など日数を計算した日付を取得することができます。
let calendar = Calendar.current
let now = Date() // "Apr 18, 2023 at 7:29 PM"
let modifiedDate = calendar.date(byAdding: .day,value: 3,to: now)
print(modifiedDate!.description(with: Locale(identifier: "ja_JP")))
// 2023年4月21日 金曜日 19時29分14秒 日本標準時
任意の日付間の期間を計算する
任意の日付間の期間を計算する方法はいくつかあるかと思いますが、以下の方法でも取得することが可能です。
let calendar = Calendar.current
let startDate = calendar.date(from: DateComponents(year: 2023, month: 4, day: 1))!
let endDate = calendar.date(from: DateComponents(year: 2023, month: 4, day: 30))!
let dateInterval = DateInterval(start: startDate, end: endDate)
let numberOfDays = calendar.dateComponents([.day], from: dateInterval.start, to: dateInterval.end).day
print("日数: \(numberOfDays ?? 0)")
// 日数: 29
DateInterval型を取得する
日付の期間を保持するデータ型としてDateInterval
型が用意されています。Calender構造体ではdateInterval(of:for:)
メソッドを使用して任意の間隔のDateInterval
型を取得できます。
func dateInterval(
of component: Calendar.Component,
for date: Date
) -> DateInterval?
これを使用することで以下のように現在日時が含まれる週を取得することが可能です。
let calendar = Calendar.current
let weekInterval = calendar.dateInterval(of: .weekOfMonth, for:.now)
print(weekInterval!)
// 2023-04-15 15:00:00 +0000 to 2023-04-22 15:00:00 +0000
日時の特定の部分を再設定する
公式リファレンス:date(bySetting:value:of:)
日付情報の「秒数だけ0」にしたり、「年数だけ2024」にしたりといった特定の日時の部分だけを変更したい場合はdate(bySetting:value:of:)
メソッドを使用します。
let calendar = Calendar.current
let now = Date()
let initSecondsday = calendar.date(bySetting: .second, value: 0, of: now)
print(initSecondsday) // Optional(2024-02-05 11:40:00 +0000)
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。