LoginSignup
8
1

More than 3 years have passed since last update.

[Swift] Date生成時にありえない日付のときはnilを返したい

Last updated at Posted at 2020-06-27

TL;DR

DateFormatterを使い isLenient = false に設定する。

func makeDate(year: Int, month: Int, day: Int) -> Date? {
    let formatter = DateFormatter()
    formatter.calendar = Calendar(identifier: .gregorian)
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    formatter.isLenient = false
    formatter.dateFormat = "yyyy-MM-dd"
    return formatter.date(from: String(format: "%d-%02d-%02d", year, month, day))
}

let date = makeDate(year: 2021, month: 2, day: 29)
// -> nil

やりたいこと

例えば年と月と日を別々に入力するUIがあってそこからDate型を生成したいとき、ユーザーが2021年2月29日のような存在しない日付を入力したらnilを返したい。

❌ DateComponentsを使う方法

func makeDate(year: Int, month: Int, day: Int) -> Date? {
    var components = DateComponents()
    components.calendar = Calendar(identifier: .gregorian)
    components.timeZone = TimeZone(secondsFromGMT: 0)
    components.year = year
    components.month = month
    components.day = day
    return components.date
}

let date = makeDate(year: 2021, month: 2, day: 29)
// -> 2021年3月1日

自動で日が進んで別の日付を返してしまう。

❌ DateFormatterを使ってisLenientを指定しない方法

func makeDate(year: Int, month: Int, day: Int) -> Date? {
    let formatter = DateFormatter()
    formatter.calendar = Calendar(identifier: .gregorian)
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    formatter.dateFormat = "yyyy-MM-dd"
    return formatter.date(from: String(format: "%d-%02d-%02d", year, month, day))
}

let date = makeDate(year: 2021, month: 2, day: 29)
// -> 2021年3月1日

自動で日が進んで別の日付を返してしまう。

ただし、32日を指定するとnilが返ってくる。
この挙動はDateComponentsとは異なる。

let date = makeDate(year: 2021, month: 2, day: 32)
// -> nil

環境

Swift 5.1

謝辞

@kishikawakatsumi さんに教えていただきました。ありがとうございました。

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1