Swiftの日付関連についてまとめてみる

7 min read読了の目安(約6400字

ごく最近、作っていたアプリで日付についての操作が多かったのですが、SwiftDateを入れてみるもなかなかうまくいかず...
色々と調べたので、忘れた時のために書き残しておく。

Calendar, Locale, TimeZone, DateFormatter

それぞれの役割について

  • Calendar
    絶対時間の管理や日付の計算、比較など
    カレンダーによる違い、うるう年、サマータイムなど考慮した計算が可能
  • Locale
    言語と地域を組み合わせたロケール情報を保持する
    identifierをみることで現在の言語を判定することができる
  • TimeZone
    タイムゾーン情報を保持する
    GMT(グリニッジ標準時)との時差で表す
    日本標準時(JST)はGMT+9時間で定義されている
  • DateFormatter
    日付と時間の書式を定義する
    Date⇄テキストの変換に使う

Calendar

  • Calendar.currentを使用するとローカル環境によってカレンダーが変わるので、西暦で指定したい場合は.gregorianと指定する
  • .japanese(和暦)
  • .gregorian(西暦)

今日、昨日、明日、週末を調べる

  • true/falseを返す
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let yesterday = date.addingTimeInterval(-60 * 60 * 24)
let tommorow = date.addingTimeInterval(60 * 60 * 24)

print(calendar.isDateInToday(date)) // 今日かどうか
print(calendar.isDateInYesterday(yesterday)) // 昨日かどうか
print(calendar.isDateInTomorrow(tommorow)) // 明日かどうか
print(calendar.isDateInWeekend(date)) // 週末かどうか

新しい日付(時刻)を生成する

  • 日付を生成する
let calendar = Calendar(identifier: .gregorian)
let date = calendar.date(from: DateComponents(year: 2021, month: 3, day: 1))
  • 時刻を生成する
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let new = calendar.date(bySettingHour: 10, minute: 0, second: 0, of: date)

分や秒数などの切り捨て

  • 分以下の切り捨て
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let compornent = calendar.dateComponents([.year, .month, .day, .hour], from: date)
let new = calendar.date(from: compornent)
  • 秒以下の切り捨て
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let compornent = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date)
let new = calendar.date(from: compornent)

日付(時刻)を取得する

  • 年を取得
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let year = calendar.component(.year, from: date) // 2021 
let calendar = Calendar(identifier: .japanese)
let date = Date()
let year = calendar.component(.year, from: date) // 3 
  • 月を取得
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let month = calendar.component(.month, from: date) // 3 
  • 日を取得
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let day = calendar.component(.day, from: date) // 1
  • 時間を取得
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let hour = calendar.component(.hour, from: date) // 10
  • 分を取得
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let minute = calendar.component(.minute, from: date) // 10
  • 秒を取得
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let second = calendar.component(.second, from: date) // 10

その日の0時0分を取得する

  • 日付だけで比較したい時に時刻を合わせるため等
let calendar = Calendar(identifier: .gregorian)
let date = Date()
calendar.startOfDay(for: date)

日付の差分を取得する

  • 何日間など経過日数を取得したい時
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let date2 = calendar.date(from: DateComponents(year: 2021, month: 3, day: 10)) 
calendar.dateComponents([.day], from: date, to: date2!).day // 9
  • ただし、上記の場合時刻も考慮しなければならず、1時間足りない場合など正しく経過日数が取得できないことがあります。時刻を合わせることで正しい経過日数を取得できます。
let calendar = Calendar(identifier: .gregorian)
let date = calendar.startOfDay(for: Date())
var date2 = calendar.date(from: DateComponents(year: 2021, month: 3, day: 10))
date2 = calendar.startOfDay(for: date2!)
calendar.dateComponents([.day], from: date, to: date2!).day // 9

日付の加算・減算

  • 日付の加算(1日後)
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let modifiedDate = calendar.date(byAdding: .day, value: 1, to: date)!
  • 日付の減算(1日前)
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let modifiedDate = calendar.date(byAdding: .day, value: -1, to: date)!

時刻の加算・減算

  • 時刻の加算(1時間後)
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let modifiedDate = calendar.date(byAdding: .hour, value: 1, to: date)!
  • 時刻の減算(1時間前)
let calendar = Calendar(identifier: .gregorian)
let date = Date()
let modifiedDate = calendar.date(byAdding: .hour, value: -1, to: date)!
  • .dayや.hourを.year/.minute/.secondと変更することで応用ができる

Locale

Locale識別子は、言語(Language)と地域(Region)を組み合わせたString型の文字列
言語と地域が基本形、例えば日本語+日本地域の場合はja_JP

  • 現在のLocale情報の取得
let locale = Locale.current
let identifier = locale.identifier
  • Locale構造体を生成する
let locale = Locale(identifier: "ja_JP") 

Xcodeからアプリのローカライズ言語を変更する

XcodeのTargets→infoで赤枠の箇所をJapanにする

TimeZone

iOSでは使用している端末の位置情報からタイムゾーンが設定される
タイムゾーンを指定したい場合は変更する

  • 現在のTimeZone情報の取得
let timezone = TimeZone.current 
  • TimeZone構造体を生成する
let timezone = TimeZone(identifier: "Asia/Shanghai")
  • DateFormatterのTimeZoneを変更すると、そのTimeZoneでの出力をしてくれる

DateFormatter

DateFormatterにはdateStyleとtimeStyleがある

  • Localeをgregorian/ja_JPとした場合の出力
dateStyle 出力
.full 2021年3月1日月曜日
.long 2021年3月1日
.midium 2021/03/01
.short 2021/03/01
timeStyle 出力
.full 15時21分30秒 日本標準時
.long 15:21:30 JST
.midium 15:21:30
.short 15:21
  • 日付→文字列へ変換(gregorian/ja_JP)
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .gregorian)
formatter.dateStyle = .long
formatter.locale = Locale(identifier: "ja_JP")
let date = Date()
let dateStr = formatter.string(from: date)
print(dateStr) // 2021年3月1日
  • 日付→文字列へ変換(japanese/ja_JP)
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .japanese)
formatter.dateStyle = .long
formatter.locale = Locale(identifier: "ja_JP")
let date = Date()
let dateStr = formatter.string(from: date)
print(dateStr) // 令和3年3月1日
  • 文字列→日付へ変換
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .gregorian)
formatter.locale = Locale(identifier: "ja_JP")
formatter.dateFormat = "yyyy年M月d日(EEEEE) H時m分s秒"
let dateStr = "2021年3月1日(月) 10時10分10秒"
let date = formatter.date(from: dateStr)
print(date!) // 2021-03-01 10:10:10 +0000

おわりに

間違いやもっとこうした方がいいよ!等ありましたら、教えていただけると嬉しいです。
以下に参考にさせていただいた記事をまとめます。

参考

https://qiita.com/rinov/items/bff12e9ea1251e895306
https://qiita.com/eKushida/items/541a65800efe1ffc523f
https://qiita.com/tamadeveloper/items/8e4f68d586cc5b0f9a5a
https://qiita.com/mishimay/items/8d67b583dc6809b2baf5
https://qiita.com/SaturnR7/items/ac304afee7358584b817