LoginSignup
0
1

More than 1 year has passed since last update.

SwiftでISO8601形式の期間の文字列表現を扱う

Posted at

SwiftでISO8601形式の期間の文字列表現を扱います。

ISO8601形式の期間

ISO8601では期間を示す形式の文字列が存在します。
https://ja.wikipedia.org/wiki/ISO_8601#期間

次のような文字列は、2021年10月1日12時から2021年12月31日15時の期間を示す文字列になります。
2021-10-01T12:00:00+09:00/2021-12-31T15:00:00+09:00

これを、Swiftで扱えるようにします。

DateIntervalに変換する

FoundationにDateIntervalというクラスが含まれます。

これはstartからendまでの特定の期間を示すクラスです。
このクラスにはcontainsなどの便利なfunctionがあり、特定の日付が期間に含まれているかを簡単に調べることができます。
ですので、期間文字列をDateIntervalに変換することを最終的な形とします。

DateIntervalFormatter

Foundationには同じくDateIntervalFormatterというクラスも含まれます。

日付の処理するFormatterとしてDateFormatterがあるように、このDateIntervalFormatterを使えば簡単に期間文字列の処理ができそうな感じもしますが、残念ながらDateIntervalFormatterには、DateFormatterのようなdate(from:String)が用意されていません。
ですので、DateIntervalFormatterに対して文字列からDateIntervalに変換する機能を追加します。

DateIntervalFormatterを継承して機能を追加する

DateIntervalFormatterにextensionを追加する方法もありますが、せっかくなのでDateIntervalFormatterを継承した ISO8601DateIntervalFormatterというクラスを作成しようと思います。
getObjectValue(_:for:errorDescription:)にも対応してSwiftUIのText等にも使えるようにしてみます。

class ISO8601DateIntervalFormatter: DateIntervalFormatter {
    var formatOptions: ISO8601DateFormatter.Options?

    func dateInterval(from string: String) -> DateInterval? {
        let split = string.split(separator: "/")
        guard split.count == 2 else { return nil }
        let dateFormatter = ISO8601DateFormatter()
        if let formatOptions = formatOptions {
            dateFormatter.formatOptions = formatOptions
        }
        guard let start = dateFormatter.date(from: .init(split[0])),
              let end = dateFormatter.date(from: .init(split[1])) else {
                  return nil
              }

        return DateInterval(start: start, end: end)
    }

    override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
        if let measurement = dateInterval(from: string)  {
            obj?.pointee = measurement as AnyObject
            return true
        } else {
            return false
        }
    }
}

ISO8601DateIntervalFormatterを使う

内部的には文字列解析にISO8601DateFormatterを使っているので、ISO8601DateFormatterの使い方と同様にformatOptionsを設定して使う形になります。

let dateIntervalString = "2004-04-01/2005-07-01"
let formatOptions: ISO8601DateFormatter.Options = [
    .withYear,
    .withDashSeparatorInDate,
]
let formatter = ISO8601DateIntervalFormatter()
formatter.formatOptions = formatOptions

let dateInterval = formatter.dateInterval(from: dateIntervalString)
0
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
0
1