LoginSignup
3
0

W3CDTF形式のStringをDateに変換する

Posted at

W3CDTF形式のStringをDateに変換します。

W3CDTF形式について

W3CDTF(World Wide Web Consortium Date and Time Formats)は、World Wide Web Consortium(W3C)が定義した日付と時刻のフォーマットに関する標準です。

以下の形式があります。

  • Year:
    • YYYY (eg 1997)
  • Year and month:
    • YYYY-MM (eg 1997-07)
  • Complete date:
    • YYYY-MM-DD (eg 1997-07-16)
  • Complete date plus hours and minutes:
    • YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
  • Complete date plus hours, minutes and seconds:
    • YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
  • Complete date plus hours, minutes, seconds and a decimal fraction of a second
    • YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)

コード

上記の形式いずれが来ても変換できるようなフォーマッタを作成しようと思います。
基本的には ISO8601DateFormatter で全て対応ができます。

ただ、 Complete date plus hours and minutes に関しては ISO8601DateFormatterでの対応ができなさそうなので、Date.ParseStrategyでの対応を行います。

以下はコードです。
ただし、Complete date のような、タイムゾーンがテキスト中に表現できていない形式の場合、GMTのDateが返されるので、ISO8601DateFormatterのtimeZoneに明示的に目的のtimeZoneを与える必要があります。

struct W3cDateFormatter {
    func callAsFunction(string: String) -> Date? {
        let iso8601DateFormatter = ISO8601DateFormatter()
        
        // YYYY-MM-DDThh:mm:ss.sTZD
        iso8601DateFormatter.formatOptions = [.withFullDate, .withFullTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withColonSeparatorInTimeZone, .withFractionalSeconds]
        if let date = iso8601DateFormatter.date(from: string) {
            return date
        }
        
        // YYYY-MM-DDThh:mm:ssTZD
        iso8601DateFormatter.formatOptions = [.withInternetDateTime]
        if let date = iso8601DateFormatter.date(from: string) {
            return date
        }

        // YYYY-MM-DDThh:mmTZD
        let strategy = Date.ParseStrategy(format: "\(year: .defaultDigits)-\(month: .twoDigits)-\(day: .twoDigits)T\(hour: .twoDigits(clock: .twentyFourHour, hourCycle: .zeroBased)):\(minute: .twoDigits)\(timeZone: .iso8601(.short))",
                           timeZone: .current)
        if let date = try? Date(string, strategy: strategy) {
            return date
        }

        // YYYY-MM-DD
        iso8601DateFormatter.formatOptions = [.withFullDate, .withDashSeparatorInDate]
        if let date = iso8601DateFormatter.date(from: string) {
            return date
        }

        // YYYY-MM
        iso8601DateFormatter.formatOptions = [.withYear, .withMonth, .withDashSeparatorInDate]
        if let date = iso8601DateFormatter.date(from: string) {
            return date
        }

        // YYYY
        iso8601DateFormatter.formatOptions = [.withYear, .withDashSeparatorInDate]
        return iso8601DateFormatter.date(from: string)
    }
}

3
0
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
3
0