Как получить дату ISO 8601 на iOS?
достаточно легко получить строку даты ISO 8601 (например,2004-02-12T15:19:21+00:00
) в PHP через date('c')
, но как получить его в Objective-C (iPhone)? Есть ли такой же короткий способ сделать это?
здесь долго способ я нашел, чтобы сделать это:
NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
NSDate *now = [NSDate date];
NSString *formattedDateString = [dateFormatter stringFromDate:now];
NSLog(@"ISO-8601 date: %@", formattedDateString);
// Output: ISO-8601 date: 2013-04-27T13:27:50-0700
это кажется ужасно много вздора для чего-то настолько Центрального.
10 ответов:
использовать
NSDateFormatter
:NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; [dateFormatter setLocale:enUSPOSIXLocale]; [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"]; NSDate *now = [NSDate date]; NSString *iso8601String = [dateFormatter stringFromDate:now];
и в Swift:
let dateFormatter = DateFormatter() let enUSPosixLocale = Locale(identifier: "en_US_POSIX") dateFormatter.locale = enUSPosixLocale dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" let iso8601String = dateFormatter.string(from: Date())
iOS 10 представляет новый
NSISO8601DateFormatter
класс, чтобы справиться именно с этим. Если вы используете Swift 3, ваш код будет выглядеть примерно так:let formatter = ISO8601DateFormatter() let date = formatter.date(from: "2016-08-26T12:39:00Z") let string = formatter.string(from: Date())
в дополнение к ответу Мэдди, формат часового пояса должен быть "ZZZZZ "(5 раз Z) для ISO 8601 вместо одного" Z " (который для формата RFC 822). По крайней мере на iOS 6.
(см. http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns)
Так что используйте категорию Сэма Софи на nsdate found здесь. С помощью этого кода, добавленного в ваш проект, вы можете с этого момента использовать один метод на NSDate:
- (NSString *)sam_ISO8601String
Это не только одна строка, ее гораздо быстрее, чем подход NSDateFormatter, так как она написана в чистом C.
С IS8601, проблемы-это представление и часовой пояс
- ISO 8601 =
year-month-day time timezone
- дата и время, есть базовые (запись в формате ччммсс ...) и расширенный формат (гггг-ММ-ДД, чч:мм: СС, ...)
- часовой пояс может быть Зулу, смещение или GMT
- разделитель даты и времени может быть пробел или
T
- есть формат недели для даты, но он редко используется
- часовой пояс может быть много пробелов после
- второй не является обязательным
вот некоторые допустимые строки
2016-04-08T10:25:30Z 2016-04-08 11:25:30+0100 2016-04-08 202530GMT+1000 20160408 08:25:30-02:00 2016-04-08 11:25:30 +0100
решений
- разбираем шаг за шагом, как soffes ISO8601
- конвертировать в основной формат, например onmyway133 ISO8601
NSDateFormatter
так вот формат, который я использую в onmyway133 В формате iso8601
let formatter = NSDateFormatter() formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") formatter.dateFormat = "yyyyMMdd HHmmssZ"
о
Z
идентификатор Таблица Символов Поля ДатыZ: The ISO8601 basic format with hours, minutes and optional seconds fields. The format is equivalent to RFC 822 zone format (when optional seconds field is absent)
о
locale
форматирование данных с помощью настроек локалилокали представляют выбор форматирования для конкретного пользователя, а не предпочтительный язык пользователя. Они часто одинаковы, но могут быть разными. Например, носитель английского языка, который живет в Германии, может выбрать английский в качестве языка и Германия как регион
о
en_US_POSIX
технические Q & A QA1480 NSDateFormatter и интернет-датыС другой стороны, если вы работаете с датами фиксированного формата, вы должны сначала установить локаль средства форматирования даты на что-то подходящее для вашего фиксированного формата. В большинстве случаев лучший язык для выбора- "en_US_POSIX", языковой стандарт, специально разработанный для получения результатов на английском языке США независимо от пользователя и системы предпочтения. "en_US_POSIX "также инвариантен во времени (если США в какой-то момент в будущем изменят способ форматирования дат," en_US "изменится, чтобы отразить новое поведение, но" en_US_POSIX"не будет) и между машинами ("en_US_POSIX" работает так же на iOS, как и на OS X, и как на других платформах).
интересные обзоры вопросы
часто упускается из виду, что строки в формате ISO 8601 могут иметь миллисекунды, а могут и не иметь.
другими словами, оба "2016-12-31T23:59:59.9999999" и "2016-12-01T00:00:00" являются законными, но если вы используете статический форматер даты, один из них не будет проанализирован.
начиная от iOS 10 вы должны использовать
ISO8601DateFormatter
который обрабатывает все варианты строк даты ISO 8601. Смотрите пример ниже:let date = Date() var string: String let formatter = ISO8601DateFormatter() string = formatter.string(from: date) let GMT = TimeZone(abbreviation: "GMT") let options: ISO8601DateFormatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withTimeZone] string = ISO8601DateFormatter.string(from: date, timeZone: GMT, formatOptions: options)
на iOS 9 и ниже использовать следующий подход с множеством средств форматирования данных.
Я не нашел ответа, который охватывает оба случая и абстрагирует это тонкое различие. Вот решение, которое обращается к нему:
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(fromISO8601String 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(fromISO8601String: dateToString) // dateTo: 2016-12-31 23:59:59 +0000 let dateFromString = "2016-12-01T00:00:00" let dateFrom = DateFormatter.date(fromISO8601String: dateFromString) // dateFrom: 2016-12-01 00:00:00 +0000
Я также рекомендую проверить статья Apple о дате форматирования.
на основе этого gist:https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift, Следующий метод может быть использован для преобразования NSDate в строку даты ISO 8601 в формате yyyy-MM-dd'T'HH:mm:ss.СССЗ
-(NSString *)getISO8601String { static NSDateFormatter *formatter = nil; if (!formatter) { formatter = [[NSDateFormatter alloc] init]; [formatter setLocale: [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]]; formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation: @"UTC"]; [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS"]; } NSString *iso8601String = [formatter stringFromDate: self]; return [iso8601String stringByAppendingString: @"Z"]; }
просто использовать NSISO8601DateFormatter от основы фундамента.
let isoDateFormatter = ISO8601DateFormatter() print("ISO8601 string: \(isoDateFormatter.string(from: Date()))") // ISO8601 string: 2018-03-21T19:11:46Z
https://developer.apple.com/documentation/foundation/nsiso8601dateformatter?language=objc
Это немного проще и помещает дату в UTC.
extension NSDate { func iso8601() -> String { let dateFormatter = NSDateFormatter() dateFormatter.timeZone = NSTimeZone(name: "UTC") let iso8601String = dateFormatter.stringFromDate(NSDate()) return iso8601String } } let date = NSDate().iso8601()
использование Swift 3.0 и iOS 9.0
extension Date { private static let jsonDateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" formatter.locale = Locale(identifier: "en_US_POSIX") formatter.timeZone = TimeZone(identifier: "UTC")! return formatter }() var IOS8601String: String { get { return Date.jsonDateFormatter.string(from: self) } } init?(fromIOS8601 dateString: String) { if let d = Date.jsonDateFormatter.date(from: dateString) { self.init(timeInterval: 0, since:d) } else { return nil } } }