Dates de RFC3339 Parsing avec NSDateFormatter dans iOS 4.x et Mac OS X 10.6: impossible?
-
30-09-2019 - |
Question
une date de Parsing RFC3339 avec NSDateFormatter semble impossible, dans le cas général. Ai-je tort? [Edit 2 ans plus tard: il y a maintenant un moyen! Voir ci-dessous et la note.]
Un service Web non particulièrement malléable me nourrit des dates comme:
2009-12-31T00:00:00-06:00
compatible RFC3339, sortie par défaut de la bibliothèque de JAXB qu'ils utilisent. Notez le côlon, qui RFC3339 nécessite lorsque le décalage n'est pas un littéral "z":
time-numoffset = ("+" / "-") time-hour ":" time-minute time-offset = "Z" / time-numoffset
Je veux analyser ceux-ci dans NSDates.
NSDateFormatter veut motifs dans la syntaxe spécifiée par Unicode , qui offre symboles de champ de date pour timezones comme "PDT", "-0800", "GMT-08: 00" mais pas "-08: 00".
recherche sur Google, et d'autres questions similaires de SO, produit des formats de date seulement comme
[myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"];
/* or: */ [myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
Le dernier qui exige un littéral « Z », et l'ancienne insiste soit l'absence d'un colon ou de la présence d'un « GMT ». Cependant, ils sont apparus au travail avant ios 4.x (éventuellement en éliminant le tz complètement compensé;. Mes données ne sont pas claires)
Mes options à ce stade sont beaucoup désolé:
- Découvrez quelques spécificateur de format sans papier, ou un étrange mode pour mettre en NSDateFormatter, qui accepte le côlon parasite: Longshot, probablement inexistante. [Note]
- persuader mon éditeur de services pour transformer toutes les dates dans le temps zulu et spécifiez « Z »:. Défi politique
- écrire ma propre sous-classe ou de recherche NSFormatter bon vieux
strptime_l
: le travail. :) - string-manipuler mon entrée et la bande le dernier colon. Fragile et laid, mais le chemin probable de moindre résistance
Ai-je compris la situation précise que NSDateFormatter actuelle suit strictement unicode sans extensions; et les formats unicode ne suffisent pas pour décrire complètement une date de RFC3339?
[FOOTNOTE] Je reviens à ces trois ans plus tard pour virer de bord sur un petit supplément: Unicode et Apple ont ajouté cette fonctionnalité aux chaînes de format, à partir de iOS6 / OSX10.8. Comparer La dernière révision de cette écriture avec son prédécesseur immédiat, et notez l'ajout de 5 "Z" s, ce qui donne un format de zone comme "-08: 00". Donc, si vous pouvez vous en sortir avec le soutien amerrissage forcé 5.x / 10.7, il y a une nouvelle bonne façon de le faire. Je vais laisser le stand de réponse précédente, comme il est toujours la meilleure approche quand la compatibilité descendante est nécessaire.
La solution
chaîne de date d'analyse syntaxique Cocoa peut être une douleur, surtout si vous avez à traiter avec des dates générées par les services Web .NET.
Je suggère à la recherche dans la catégorie NSDate + InternetDateTime que Michael a Waterfall sur NSDate dans le cadre de son projet de MWFeedParser sur GitHub. Il a bien fonctionné pour moi exactement le format de l'analyse de la date que vous décrivez.
Autres conseils
- getObjectValue: forString: Gamme: Erreur: en fait parse les dates de RFC3339 correctement. Je ne sais pas pourquoi - dateWithString: ne peut pas:
// 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];
Les caractères de format de chaîne sont documentées nulle part dans la documentation Apple. Au lieu de cela il y a un lien caché au plus profond dans certains pointage de documents à la norme Unicode à
http://www.unicode.org/reports/tr35/tr35 -31 / TR35-dates.html # Date_Format_Patterns
En utilisant les informations à ce lien, il est assez simple:
- (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;
}