Mar 14th, 2012
NSDate是NS类库中基础类型之一。随着数字化发展,程序对数据处理量越来越大,我们经常从服务器取得的日期是字符串序列,格式化为正确的date类型是一个不可避免的工作。在Cocoa程序里提供了非常方便的函数和类,但是仍然需要我们了解一些技巧。尤其是当我们的程序面对大量的日期字符串转换的时候,要格外的注意。苹果文档中使用NSDateFormatter类格式化日期字符串,但是以防读者不知道,我这里提一下:它的速度非常慢!!这篇文章介绍如何处理这种情况。
1 2 3 4 5 6 7 8 9 - (NSDate *)dateFromString:(NSString *)string { //Wed Mar 14 16:40:08 +0800 2012 if (!string) return nil; NSDateFormatter *dateformatter=dateformatter = [[NSDateFormatter alloc] init]; NSTimeZone *tz = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; [dateformatter setTimeZone:tz]; [dateformatter setDateFormat:@"EEE MMM dd HH:mm:ss Z yyyy"];; return [dateformatter dateFromString:string]; }由于NSDateFormatter内部代码原因,所以格式化字符串代价很大。对于个别地方使用它做日期转换是非常方便的,但是如果是放在一个大的循环内部,直接使用NSDateFormatter绝对不是明智的选择。它很有可能成为拖慢你程序速度的元凶。
其实如果你知道你的程序将会取得什么格式的日期字符串,那么直接分解字符串后利用NSCalendar和NSDateComponents可以提高速度很多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 - (NSDate*)mydateFromString:(NSString *)string; { //Wed Mar 14 16:40:08 +0800 2012 if (!string) return nil; static NSCalendar *gregorian=nil; static NSDateComponents *comps=nil; static NSDictionary *month=nil; if (gregorian==nil) { gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; comps = [[NSDateComponents alloc] init]; month = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:1], @"Jan", [NSNumber numberWithInt:2], @"Feb", [NSNumber numberWithInt:3], @"Mar", [NSNumber numberWithInt:4], @"Apr", [NSNumber numberWithInt:5], @"May", [NSNumber numberWithInt:6], @"Jun", [NSNumber numberWithInt:7], @"Jul", [NSNumber numberWithInt:8], @"Aug", [NSNumber numberWithInt:9], @"Sep", [NSNumber numberWithInt:10], @"Oct", [NSNumber numberWithInt:11], @"Nov", [NSNumber numberWithInt:12], @"Dec", nil]; } @try { NSString *t=[string substringWithRange:NSMakeRange(26, 4)]; [comps setYear:[t intValue]]; t=[string substringWithRange:NSMakeRange(4, 3)]; [comps setMonth:[[month objectForKey:t] intValue]]; t=[string substringWithRange:NSMakeRange(8, 2)]; [comps setDay:[t intValue]]; t=[string substringWithRange:NSMakeRange(11, 2)]; [comps setHour:[t intValue]]; t=[string substringWithRange:NSMakeRange(14, 2)]; [comps setMinute:[t intValue]]; t=[string substringWithRange:NSMakeRange(17, 2)]; [comps setSecond:[t intValue]]; t=[string substringWithRange:NSMakeRange(20, 5)]; //全球共24个标准时区,每个时区为1个小时,下面计算该时区offset秒数 [comps setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:[t intValue]/100*3600]]; } @catch (NSException *exception) { } @finally { } return [gregorian dateFromComponents:comps]; }如果要更快,就需要抛弃ObjC,编写c代码格式化时间字符串。如下代码经过测试是最快的。
1 2 3 4 5 6 7 8 9 10 11 - (NSDate *)dateFromString:(NSString *)string { //Wed Mar 14 16:40:08 +0800 2012 if (!string) return nil; struct tm tm; time_t t; string=[string substringFromIndex:4]; strptime([string cStringUsingEncoding:NSUTF8StringEncoding], "%b %d %H:%M:%S %z %Y", &tm); tm.tm_isdst = -1; t = mktime(&tm); return [NSDate dateWithTimeIntervalSince1970:t]; }下面是我简单测试循环10000次解析日期字符串的时间比较。
1 2 3 2012-05-05 15:57:51.942 timetest[18488:707] 1.991521 //第一种 2012-05-05 15:57:52.096 timetest[18488:707] 0.921144 //第二种 2012-05-05 15:57:54.088 timetest[18488:707] 0.153897 //第三种最后作为参考资料,说明一下 OSX 10.6 下 NSDateFormatter 使用 Unicode Locale Data Markup Language (LDML) version tr35-10 标准。作为标准文档,Apple是不会全部写到开发文档里的,不明白的同学可以到这查看。
Posted by Xu Lian Updated May 5th, 2012 Cocoa, NSCalendar, NSDate,NSDateComponents, NSDateFormatter, NSString, Objective-C
« Web应用中一种用户友好Email验证模式 Cocoa中编写你自己的变参格式化函数 »
转载于:https://www.cnblogs.com/w-zhijun/archive/2012/11/06/2757785.html
相关资源:JAVA上百实例源码以及开源项目