Как получить дату 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 98

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