Как разобрать ISO 8601 с использованием NSDateFormatter с дополнительной частью миллисекунд
Я пытаюсь использовать NSDateFormatter для анализа дат, которые находятся в любом из этих форматов.
@"2013-02-01T14:21:00"
или
@"2013-02-01T14:21:56.345"
В настоящее время я использую метод ниже для синтаксического анализа строки и возврата даты:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
NSDate *date = [dateFormatter dateFromString:dateToFormat];
Это отлично работает для первого стиля даты, но возвращает nil для строки, которая включает в себя миллисекундную часть.
Я предполагаю, что могу проверить существование миллисекунд и разбить их, но мне было интересно, могу ли я изменить формат даты для обработки .SSS как необязательного?
Спасибо за помощь
Ответы
Ответ 1
Насколько я знаю, нет способа сделать необязательные параметры.
Обычное решение - использовать два форматирования, по одному для каждого формата.
Чтобы решить, какой форматтер использовать, вы можете либо
Поскольку ваши форматы дат похожи, вы можете использовать только один форматировщик, а если строка даты слишком короткая, добавьте .000
перед использованием форматирования.
Ответ 2
Я написал универсальный парсер, который удалял миллисекундную часть.
@implementation JSONModel(NSPAdditions)
- (NSDate *)NSDateFromNSString:(NSString*)string {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
NSArray* parts = [string componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@" T"]];
if ([parts count] <= 1) {
return [formatter dateFromString:string];
}
NSString *part0 = parts[0];
NSAssert([part0 length] == [@"yyyy-MM-dd" length], @"Date format error");
NSString *part1 = parts[1];
if ([part1 length] > [@"HH:mm:ss" length]) {
part1 = [part1 substringToIndex:[@"HH:mm:ss" length]];
}
NSString *fmted = [NSString stringWithFormat:@"%@ %@", part0, part1];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
return [formatter dateFromString:fmted];
}
@end
Ответ 3
Вот решение, которое я использую (Swift 3):
extension DateFormatter {
static let iso8601DateFormatter: DateFormatter = {
let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX")
let iso8601DateFormatter = DateFormatter()
iso8601DateFormatter.locale = enUSPOSIXLocale
iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
return iso8601DateFormatter
}()
static let iso8601WithoutMillisecondsDateFormatter: DateFormatter = {
let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX")
let iso8601DateFormatter = DateFormatter()
iso8601DateFormatter.locale = enUSPOSIXLocale
iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
return iso8601DateFormatter
}()
static func date(fromISO8601StringWithOptionalMilliseconds string: String) -> Date? {
if let dateWithMilliseconds = iso8601DateFormatter.date(from: string) {
return dateWithMilliseconds
}
if let dateWithoutMilliseconds = iso8601WithoutMillisecondsDateFormatter.date(from: string) {
return dateWithoutMilliseconds
}
return nil
}
}
Применение:
let dateToString = "2016-12-31T23:59:59.9999999"
let dateTo = DateFormatter.date(fromISO8601StringWithOptionalMilliseconds: dateToString)
// dateTo: 2016-12-31 23:59:59 +0000
let dateFromString = "2016-12-01T00:00:00"
let dateFrom = DateFormatter.date(fromISO8601StringWithOptionalMilliseconds: dateFromString)
// dateFrom: 2016-12-01 00:00:00 +0000
Я также рекомендую проверить статью Apple о форматах даты.