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)
}
}