2009-11-18 102 views
36

日期原谅我,因为我是新来的目的C.解析JSON在IPhone

我取回从/日期(XXXXXXXXXXXXX-XXXX)/格式的.NET Web服务的日期。我正在寻找一些关于如何最好的解析NSDate对象的方向。我已经尝试使用dateWithTimeIntervalSince1970上它,但它回来与在1969年的日期,我知道是在2006年的日期。

寻找一些正确的方式来处理JSON日期。

在此先感谢!

回答

9

作为一名.NET程序员学习Objective-C,当我尝试使用.Net WebService时,我遇到了同样的问题。

起初我还以为我将能够使用NSDateFormatter ... 我发现它的符号here一个很好的参考,但我很快意识到,我需要的数量从毫秒转换为秒。

我写的代码做... 我还在学习对象 - 但我不认为它应该一直这个硬...

- (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

编辑:

有关JSON DateTime格式... 如果您对本服务的任何控制它可能会最好将日期转换为DataContract对象中的字符串。

Formatting to RFC1123对我来说似乎是个好主意。正如我可以轻松地使用NSDateFormatter来捡起它。

报价从Rick Strahl

有没有JavaScript的日期文字和微软设计的自定义日期格式,本质上是一种标记的字符串。格式是经过编码并包含标准新Date(1970年以来的毫秒)值的字符串。

+0

感谢您的回答。我基本上采取了与你相同的方法。这感觉像一个黑客,我希望有一个更清洁的解决方案,但哦,它现在工作。 – user213517 2009-11-19 19:09:24

+1

[scanner dealloc];不应该是[扫描仪发布]; ! :) – 2012-11-12 17:56:04

+0

很好的解决方案,但secondNumber被解析后根本不使用。它应该更正格林威治标准时间日期 – ajonnet 2013-08-01 07:18:46

0
+2

你能请张贴的如何做到这一点的例子吗? – odyth 2011-03-05 22:23:00

+1

-1我不得不说,这是错误的,直到戴夫提供代码如何做到这一点。 Json日期自特定日期和时间开始以秒为单位。那么如何设置格式返回一个正确的NSDate。文档链接中没有提供如何将格式设置为除MM DD YY样式之外的其他范例的内容。 – J3RM 2012-01-18 16:19:08

+0

没有代码来详细说明答案 – Katushai 2014-09-28 05:40:03

18

我在同一条船上,同时使用json-framework,它不支持日期格式,因为它不是官方的JSON。我的源代码来自使用JSON.Net构建的API。这是我想出了:

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

我没有在日期格式,你这样做,我还没有处理,像上述的答案附加部分。没有任何错误,这一点对我来说都是新的。

+0

此方法中有一个FLAW,它只支持1/1/1970之后的日期时间。 1/1/1970之前的日期将返回真正错误的日期。发生这种情况的原因是毫秒是无符号的,这意味着它只支持正数,所以任何负数都会导致不良结果。 – J3RM 2012-01-18 17:43:47

+2

感谢downvote。如果你阅读这个问题,它说他们正在寻找“某个方向”,而不是每个可能的日期格式的答案。评论可能已经足够,但无论什么漂浮你的船。为了实际提供一个有用的答案而获得downvoted,这使我想帮助别人。 – toxaq 2012-01-19 04:20:12

47

我刚刚写了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; 
} 
+1

+1此函数支持1970年1月1日之前和之后的日期,这与其他方法的“无符号”毫秒不同。我的解决方案需要TZ的信息,所以我刚刚评论说部分和关闭的比赛。 – J3RM 2012-01-18 17:46:55

+0

+1,这工作正常。什么是@“^ \\/date \\(( - ?\\ d ++)(?:([+ - ])(\\ d {2})(\\ d {2}))?\ \)\\/$“。我无法理解它正在发生什么。 – 2013-05-10 05:11:06

+0

@ g-ganesh这是正则表达式。它解析这种格式:“/ Date(xxxxxxxxxxxxx-xxxx)/”。第一部分是unix时间,第二部分是时区。首先,所有那些双“\”,因为“\”需要在NSString对象中转义,然后单个“\”在正则表达式中转义。所以我们有“^ \/date \(”,它只在字符串的开始处匹配“/ date(”),然后我们有“( - ?\ d ++)”,它捕获可选的负秒,其中至少有两个数字(我不记得为什么它必须至少有两个) – jasongregori 2013-05-10 15:33:18

11

我居然发现NSRegularExpression片断非常有用的,直到我与使用NSCharecterSet为stipping关闭毫秒另一种解决方案上来。

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

节省了大量的手动字符串处理,并使代码更清洁。

+0

这是非常好的解决方案。只是想知道为什么没人赞成这个。谢谢。 – 2012-09-01 14:58:28

+0

这不适用于时代之前的日期,因为它也会剥离最终的符号字符。 – Niels 2013-03-01 14:44:50

5

理论值:MS编码的C#日期时间在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

这不是假设时间是UTC吗? – mkral 2013-01-08 14:59:30

0

- (的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的)间隔; NSIteger分钟数=(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]; 
    } 
} 

}