2009-11-18 78 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]; 
    } 
} 

}