Разбор дат JSON на айфоне - PullRequest
36 голосов
/ 18 ноября 2009

Прости меня, поскольку я новичок в Цели C.

Я получаю даты от веб-службы .NET в формате / Date (xxxxxxxxxxxxx-xxxx) /. Я ищу направление о том, как лучше всего разобрать это в объект NSDate. Я попытался использовать dateWithTimeIntervalSince1970 на нем, но он возвращает дату 1969 года для даты, которую я знаю в 2006 году.

В поисках правильного способа обработки дат JSON.

Заранее спасибо!

Ответы [ 7 ]

47 голосов
/ 20 мая 2011

Я только что написал это для iOS 4.0+ (потому что он использует NSRegularExpression). Он обрабатывает даты с или без смещения часового пояса. Кажется, работает довольно хорошо, что вы думаете?

+ (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;
}
18 голосов
/ 10 марта 2010

Я был в той же лодке, когда использовал json-framework, который не поддерживает формат даты, поскольку это не официальный JSON. Мой источник взят из API, созданного с использованием JSON.Net. Вот что я придумал:

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

У меня нет добавленной части в формате даты, которую вы делаете, поэтому я не имел дело с этим, как ответ выше. Никаких ошибок тоже нет, для меня это все ново.

11 голосов
/ 09 июля 2012

Я действительно находил фрагмент с NSRegularExpression довольно полезным, пока не нашел другое решение, которое использует NSCharecterSet для сбрасывания миллисекунд.

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

Экономит много ручной обработки строк и делает код намного чище.

9 голосов
/ 19 ноября 2009

Как программист .NET, изучающий Objective-C, у меня была такая же проблема, когда я пытался использовать .Net WebService.

Сначала я подумал, что смогу использовать NSDateFormatter ... Я нашел действительно хорошую ссылку для его символов здесь , но я быстро понял, что мне нужно преобразовать число из миллисекунд в секунды.

Я написал код, чтобы сделать это ... Я все еще изучаю Obj-C, но не думаю, что это должно быть так сложно ...

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

Надеюсь, кто-то может предложить лучшее решение Obj-C. Если нет, я могу оставить это или поискать способ изменить формат сериализации в .NET

EDIT:

О том формате JSON DateTime ... Если у вас есть какой-либо контроль над службой, вероятно, было бы лучше преобразовать дату в строку в ваших объектах DataContract.

Форматирование в RFC1123 кажется мне хорошей идеей прямо сейчас. Как я могу, вероятно, легко подобрать его с помощью NSDateFormatter.

Цитата из Рик Штрал

В JavaScript нет литерала даты, и Microsoft разработала специальный формат даты, который по сути является размеченной строкой. Формат представляет собой строку, которая закодирована и содержит стандартное новое значение даты (в миллисекундах с 1970 года).

5 голосов
/ 24 ноября 2012

Теория: MS закодировала C # DateTime в JSON в миллисекундах с 1970 года. Решение:

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

Это самое короткое решение, которое я могу придумать.

0 голосов
/ 13 января 2017

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

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

} - (NSString *) stringFromTimeInterval: (NSTimeInterval) интервал { NSInteger ti = (NSInteger) интервал; NSInteger минут = (ti / 60)% 60; NSInteger часы = (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];
    }
}

}

0 голосов
/ 18 ноября 2009

Используйте метод NSDateFormatter * dateFromString: после установки формата даты .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...