Подтвердить что ты не робот

Разбор rfc3339 с NSDateFormatter в iOS 4.x и MacOS X 10.6: невозможно?

Разбор даты rfc3339 с помощью NSDateFormatter представляется невозможным в общем случае. Я ошибаюсь? [Редактировать 2 года спустя: теперь есть способ! См. Ниже и сноску.]

Не-особенно податливый веб-сервис кормит меня такими датами, как:

2009-12-31T00:00:00-06:00

Rfc3339 совместимый, по умолчанию вывод библиотеки jaxb, которую они используют. Обратите внимание на двоеточие, для которого rfc3339 требуется, когда смещение не является литералом "z":

time-numoffset  = ("+" / "-") time-hour ":" time-minute
time-offset     = "Z" / time-numoffset

Я хочу проанализировать их в NSDates.

NSDateFormatter хочет шаблоны в синтаксисе, указанном Unicode, который предлагает символы поля даты для таких часовых поясов, как "PDT", "-0800", "GMT-08: 00", но не "-08: 00".

Googling и другие подобные вопросы SO вызывают только форматы даты, такие как

[myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"];
/* or: */ [myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];

Последний из которых требует буквального "Z" , а первый настаивает либо на отсутствии двоеточия, либо на присутствии "GMT". Тем не менее, они, похоже, работали до ios 4.x(возможно, полностью отбрасывая tz-смещение, мои данные не ясны.)

Мои параметры на данный момент - извините:

  • откройте какой-либо недокументированный спецификатор формата или какой-то странный режим, чтобы включить NSDateFormatter, который примет отклоненный двоеточие: longshot, вероятно, несуществующий. [Примечание]
  • убедить моего сервисного издателя включить все даты в zulu time и указать "Z" : политически сложно.
  • напишите мой собственный подкласс NSFormatter или исследуйте старый добрый strptime_l: work.:)
  • string-манипулировать моим вводом и вырезать последний двоеточие: хрупкий и уродливый, но вероятный путь наименьшего сопротивления.

Я точно понял ситуацию, что текущий NSDateFormatter следует за unicode строго без расширений; и форматы unicode недостаточны для полного описания даты rfc3339?

[FOOTNOTE] Я возвращаюсь к этим трем годам позже, чтобы применить небольшое приложение: Unicode и Apple добавили эту функцию в строки формата, начиная с iOS6/OSX10.8. Сравните Последняя редакция на момент написания статьи с ее ближайшим предшественником, и обратите внимание на добавление 5 "Z" s, что дает формат зоны, например "-08: 00". Поэтому, если вы можете уйти с канавкой поддержки 5.x/10.7, там будет правильный правильный путь. Я оставлю предыдущий стенд для ответа, поскольку он все же лучший подход, когда требуется обратная совместимость.

4b9b3361

Ответ 1

Разбор строки строк в Cocoa может быть больно, особенно если вам приходится иметь дело с датами, созданными веб-службами .NET.

Я бы предложил посмотреть категорию NSDate + InternetDateTime, которую Майкл Водопад имеет в NSDate в рамках своего проекта MWFeedParser на github. Это сработало для меня, разбора именно формата даты, которую вы описываете.

https://github.com/mwaterfall/MWFeedParser/

Ответ 2

- getObjectValue: forString: range: error: может корректно анализировать даты RFC3339. Я понятия не имею, почему - dateWithString: не может:

// RFC3339 date formatting
NSString *dateString = @"2012-04-11T18:34:19+00:00";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";

NSDate *date;
NSError *error;
[formatter getObjectValue:&date forString:dateString range:nil error:&error];

Ответ 3

Символы строкового формата нигде не документированы в документации Apple. Вместо этого есть ссылка, скрытая глубоко в каком-то документе, указывающем на стандарт Unicode в

http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns

Использование информации по этой ссылке довольно просто:

- (NSDate*)dateFromRFC3339String:(NSString*)aString
{
    static NSDateFormatter* sRFC3339DateFormatter = nil;
    static NSDateFormatter* sRFC3339DateFormatterSubSeconds = nil;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];

        sRFC3339DateFormatter = [[NSDateFormatter alloc] init];
        [sRFC3339DateFormatter setLocale:enUSPOSIXLocale];
        [sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssXXXXX"];
        [sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];

        sRFC3339DateFormatterSubSeconds = [[NSDateFormatter alloc] init];
        [sRFC3339DateFormatterSubSeconds setLocale:enUSPOSIXLocale];
        [sRFC3339DateFormatterSubSeconds setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSSSSXXXXX"];
        [sRFC3339DateFormatterSubSeconds setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    });

    NSDate* date = [sRFC3339DateFormatter dateFromString:aString];
    if (date == nil)
        date = [sRFC3339DateFormatterSubSeconds dateFromString:aString];

    return date;
}