Analisando datas JSON no IPhone

Perdoe-me por ser novo no Objectivo C.

Estou recebendo datas de um webservice .NET no formato / Date (xxxxxxxxxxxxx-xxxx) /. Eu estou procurando alguma direção sobre como melhor analisar isso em um object NSDate. Eu tentei usar dateWithTimeIntervalSince1970 nele, mas ele volta com uma data no ano de 1969 para uma data que eu sei que é em 2006.

Procurando por alguma direção sobre a maneira correta de lidar com datas JSON.

Desde já, obrigado!

Como um programador .NET aprendendo Objective-C, tive o mesmo problema quando tentei consumir um .Net WebService.

No começo eu pensei que seria capaz de usar o NSDateFormatter … Eu encontrei uma referência muito boa para seus símbolos aqui , mas rapidamente percebi que precisava converter o número de milissegundos para segundos.

Eu escrevi o código para fazer isso … Eu ainda estou aprendendo Obj-C, mas eu não acho que deveria ter sido tão difícil …

- (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]; } 

Espero que alguém possa fornecer uma solução Obj-C melhor. Se não, eu posso manter isso ou procurar uma maneira de alterar o formato de serialização no .NET

EDITAR:

Sobre esse formato JSON DateTime … Se você tiver algum controle sobre o serviço, provavelmente seria melhor converter a data em uma string em seus objects DataContract.

Formatação para RFC1123 parece ser uma boa idéia para mim agora. Como eu provavelmente posso pegá-lo facilmente usando um NSDateFormatter.

Citação de Rick Strahl

Não há literal de data JavaScript e a Microsoft projetou um formato de data personalizado que é essencialmente uma string marcada. O formato é uma string codificada e contém o novo valor padrão de Data (milissegundos desde 1970).

Eu só escrevi isso para o iOS 4.0 + (porque ele usa NSRegularExpression). Ele lida com datas com ou sem desvios de fuso horário. Parece funcionar muito bem, o que você acha?

 + (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; } 

Eu estava no mesmo barco usando o json-framework que não suporta o formato de data, já que não é o JSON oficial. Minha fonte é de uma API criada usando o JSON.Net. Isto é o que eu criei:

 - (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]; } 

Eu não tenho a parte anexada no formato de data que você faz, então eu não lidei com isso como a resposta acima. Sem erros, também é novidade para mim neste momento.

Eu realmente achei o trecho com NSRegularExpression bastante útil, até que surgiu uma outra solução que usa NSCharecterSet para remover os milissegundos.

 + (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; } 

Salva muito do processamento manual de strings e torna o código muito mais limpo.

Teoria: MS codificou o C # DateTime em JSON como milissegundos desde 1970. Solução:

 NSString* dateAsString = @"/Date(1353720343336+0000)/"; dateAsString = [dateAsString stringByReplacingOccurrencesOfString:@"/Date(" withString:@""]; dateAsString = [dateAsString stringByReplacingOccurrencesOfString:@"+0000)/" withString:@""]; unsigned long long milliseconds = [dateAsString longLongValue]; NSTimeInterval interval = milliseconds/1000; NSDate* date = [NSDate dateWithTimeIntervalSince1970:interval]; 

Esta é a solução mais curta que eu posso pensar.

Use um método dateFromString: NSDateFormatter depois de definir o formato de data .

– (NSString *) convertToUTCTime: (NSString *) strDate {

 NSDate *currentDate = [NSDate date]; myDate = [commonDateFormatter dateFromString: strDate]; NSTimeInterval distanceBetweenDates = [currentDate timeIntervalSinceDate:myDate]; return [self stringFromTimeInterval:distanceBetweenDates]; 

} – (NSString *) stringFromTimeInterval: (NSTimeInterval) intervalo {NSInteger ti = (NSInteger) intervalo; NSInteger minutos = (ti / 60)% 60; NSInteger horas = (ti / 3600);

 if (hours > 24) { NSInteger days = hours/24; if (days > 30) { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"EEE d MMM, h:mm a"]; //[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"IST"]]; NSString *daydate = [dateFormatter stringFromDate:myDate]; return daydate; } else{ return [NSString stringWithFormat:@" %2ldd",(long)days]; } }else{ if (hours == 0 && minutes < 1) { return [NSString stringWithFormat:@"Today"]; } else if (hours == 0 && minutes < 60){ return [NSString stringWithFormat:@"%2ldm ",(long)minutes]; } else{ return [NSString stringWithFormat:@" %2ldh",(long)hours]; } } 

}