36 votes

Parsing Dates JSON sur iPhone

Pardonnez-moi car je suis nouveau sur Objective C.

Je reçois des dates d'un service Web .NET au format / Date (xxxxxxxxxxxxxxxxxxxxxxxxxxxx) Je cherche des indications sur la meilleure manière d’analyser cela dans un objet NSDate. J'ai essayé d'utiliser dateWithTimeIntervalSince1970 dessus, mais il revient avec une date datant de 1969 pour une date que je connais bien: 2006.

Vous recherchez des indications sur la manière appropriée de gérer les dates JSON.

Merci d'avance!

47voto

jasongregori Points 3026

Je viens d'écrire ceci pour iOS 4.0+ (car il utilise NSRegularExpression). Il gère les dates avec ou sans décalage horaire. Vous semblez bien travailler, qu'en pensez-vous?

 + (NSDate *)mfDateFromDotNetJSONString:(NSString *)string {
    static NSRegularExpression *dateRegEx = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        dateRegEx = [[NSRegularExpression alloc] initWithPattern:@"^\\/date\\((-?\\d++)(?:([+-])(\\d{2})(\\d{2}))?\\)\\/$" options:NSRegularExpressionCaseInsensitive error:nil];
    });
    NSTextCheckingResult *regexResult = [dateRegEx firstMatchInString:string options:0 range:NSMakeRange(0, [string length])];

    if (regexResult) {
        // milliseconds
        NSTimeInterval seconds = [[string substringWithRange:[regexResult rangeAtIndex:1]] doubleValue] / 1000.0;
        // timezone offset
        if ([regexResult rangeAtIndex:2].location != NSNotFound) {
            NSString *sign = [string substringWithRange:[regexResult rangeAtIndex:2]];
            // hours
            seconds += [[NSString stringWithFormat:@"%@%@", sign, [string substringWithRange:[regexResult rangeAtIndex:3]]] doubleValue] * 60.0 * 60.0;
            // minutes
            seconds += [[NSString stringWithFormat:@"%@%@", sign, [string substringWithRange:[regexResult rangeAtIndex:4]]] doubleValue] * 60.0;
        }

        return [NSDate dateWithTimeIntervalSince1970:seconds];
    }
    return nil;
}
 

18voto

toxaq Points 2427

J'étais dans le même bateau en utilisant json-framework, qui ne prend pas en charge le format de date car ce n'est pas JSON officiel. Mon source provient d'une API construite à l'aide de JSON.Net. Voici ce que je suis venu avec:

 - (NSDate*) getDateFromJSON:(NSString *)dateString
{
    // Expect date in this format "/Date(1268123281843)/"
    int startPos = [dateString rangeOfString:@"("].location+1;
    int endPos = [dateString rangeOfString:@")"].location;
    NSRange range = NSMakeRange(startPos,endPos-startPos);
    unsigned long long milliseconds = [[dateString substringWithRange:range] longLongValue];
    NSLog(@"%llu",milliseconds);
    NSTimeInterval interval = milliseconds/1000;
    return [NSDate dateWithTimeIntervalSince1970:interval];
}
 

Je n'ai pas la partie ajoutée dans le format de date que vous faites, donc je n'ai pas traité cela comme la réponse ci-dessus. Aucune erreur, non plus, c'est tout nouveau pour moi à ce stade.

11voto

Mehfuz Points 166

En fait, j'ai trouvé l'extrait de code avec NSRegularExpression très utile, jusqu'à ce que je propose une autre solution qui utilise NSCharecterSet pour arrêter les millisecondes.

 + (NSDate*) dateFromJSONString:(NSString *)dateString
{
    NSCharacterSet *charactersToRemove = [[ NSCharacterSet decimalDigitCharacterSet ] invertedSet ];
    NSString* milliseconds = [dateString stringByTrimmingCharactersInSet:charactersToRemove];   

    if (milliseconds != nil && ![milliseconds isEqualToString:@"62135596800000"]) {
        NSTimeInterval  seconds = [milliseconds doubleValue] / 1000;
        return [NSDate dateWithTimeIntervalSince1970:seconds];
    }
    return nil;
}
 

Enregistre une grande partie du traitement manuel des chaînes et rend le code beaucoup plus propre.

9voto

Stanley.Goldman Points 1648

Comme une .NET programmeur apprendre Objective-C, j'ai eu le même problème quand j'ai essayé de consommer .Net WebService.

Au début, je pensais que je serais en mesure d'utiliser le NSDateFormatter... J'ai trouvé une très bonne référence pour les symboles ici, mais j'ai vite réalisé que j'avais besoin de convertir le nombre de millisecondes à quelques secondes.

J'ai écrit le code pour le faire... Je suis encore à apprendre Obj-C, mais je ne pense pas qu'Il aurait été plus dur...

- (NSDate *) getJSONDate{
    NSString* header = @"/Date(";
    uint headerLength = [header length];

    NSString*  timestampString;

    NSScanner* scanner = [[NSScanner alloc] initWithString:self];
    [scanner setScanLocation:headerLength];
    [scanner scanUpToString:@")" intoString:&timestampString];

    NSCharacterSet* timezoneDelimiter = [NSCharacterSet characterSetWithCharactersInString:@"+-"];
    NSRange rangeOfTimezoneSymbol = [timestampString rangeOfCharacterFromSet:timezoneDelimiter];

    [scanner dealloc];

    if (rangeOfTimezoneSymbol.length!=0) {
        scanner = [[NSScanner alloc] initWithString:timestampString];

        NSRange rangeOfFirstNumber;
        rangeOfFirstNumber.location = 0;
        rangeOfFirstNumber.length = rangeOfTimezoneSymbol.location;

        NSRange rangeOfSecondNumber;
        rangeOfSecondNumber.location = rangeOfTimezoneSymbol.location + 1;
        rangeOfSecondNumber.length = [timestampString length] - rangeOfSecondNumber.location;

        NSString* firstNumberString = [timestampString substringWithRange:rangeOfFirstNumber];
        NSString* secondNumberString = [timestampString substringWithRange:rangeOfSecondNumber];

        unsigned long long firstNumber = [firstNumberString longLongValue];
        uint secondNumber = [secondNumberString intValue];

         NSTimeInterval interval = firstNumber/1000;

        return [NSDate dateWithTimeIntervalSince1970:interval];
    }

    unsigned long long firstNumber = [timestampString longLongValue];
    NSTimeInterval interval = firstNumber/1000;

    return [NSDate dateWithTimeIntervalSince1970:interval];
}

J'espère que quelqu'un peut fournir une meilleure Obj-C de la solution. Si non je peux garder cette ou de chercher un moyen de changer le format de sérialisation dans .NET

EDIT:

Sujet JSON format DateTime... Si vous avez aucun contrôle sur le service, il serait probablement préférable de convertir la date en une chaîne de caractères dans votre DataContract objets.

La mise en forme à RFC1123 semble être une bonne idée pour moi en ce moment. Comme je peux probablement ramasser facilement à l'aide d'un NSDateFormatter.

Citation de Rick Strahl

Il n'y a pas de JavaScript date littérale et Microsoft a mis au point un format de date personnalisé qui est essentiellement une hausse marquée de la chaîne. Le format est une chaîne codée et contient le standard de la nouvelle Date(en millisecondes depuis 1970) de valeur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X