2010-12-01 2 views
17

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

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

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

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

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

Я хочу, чтобы разобрать их в NSDates.

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

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

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

последний из которых требует буквального «Z», и бывший настаивает либо отсутствие толстой кишки или в присутствии " ВРЕМЯ ПО ГРИНВИЧУ". Тем не менее, они появились на работу до Ios 4.х (возможно, отбрасывая TZ смещение полностью, мои данные не ясны.)

Мои варианты на данный момент являются жалким много:

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

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

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

ответ

8

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

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

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

+0

Спасибо за указатель - Я посмотрел в его источник, и что вы знаете, вариант 4 (удалить последний двоеточие) - это именно то, что он делает. Поскольку это работает для него, я, вероятно, последую его примеру. – rgeorge 2010-12-02 15:02:02

11

- getObjectValue: forString: Диапазон: ошибка: на самом деле может разобрать 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]; 
+0

На самом деле мне здесь нечего улучшать и хотел поблагодарить плакат (sc0rp10n) за указание, что dateFromString: не работает с этими типами дат, пока getObjectValue: делает. Это приводило меня в бешенство, и я собирался попробовать getObjectValue: чтобы я мог указать диапазон, отбрасывающий часть часового пояса. Ваше предложение спасло меня. Благодарю. – 2012-08-31 18:35:01

5

строка не документируются нигде в документации 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; 
} 
+0

yep, в версию спецификации, поддерживаемую iOS 7 (tr35-31.), Добавлено семейство форматов «X» .... «ZZZZZ» определено эквивалентно «XXXXX» и доступно в ios6 (определено в tr35-25), поэтому для этого конкретного приложения я рекомендую первое. – rgeorge 2014-04-09 19:02:30