【Swift】Calendar構造体の使い方!暦法の変更と日付の計算

この記事からわかること

  • SwiftCalendar構造体使い方
  • ユーザー端末カレンダー情報取得する方法
  • グレゴリオ暦(西暦)などの暦法指定する方法
  • 日付の一部(年、月、日など)だけを取得をする方法
  • 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ですが細かい役割が異なります。

Calendar構造体とは?

公式リファレンス: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型

指定できる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型で渡します。

公式リファレンス: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)

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index