起因:最近有需求要把 1988-04-10类似的时间字符串使用NSDateFormatter转化成时间戳或者NSDate
现象:测试发现iOS格式化某些特殊时间字符串到NSDate的时候会后会返回空值,比如 1988-04-10,1989-04-16,1989-04-16 12:12等等时间
1 2 3 4 5 6 7 |
NSString *timeString = @"1988-04-10"; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd"]; NSDate *result = [dateFormatter dateFromString:timeString]; NSLog("@formater: %@", result); result 结果是nil |
当NSDateFormatter没有指定TimeZone的时候,在中国设备上一般默认都是Asia/Shanghai时区
查阅资料发现是夏令时问题
夏令时问题
1986年4月,我国采取夏令时,具体作法是:每年从四月中旬第一个星期日的凌晨2时整(北京时间),将时钟拨快一小时,即将表针由2时拨至3时,夏令时开始;到九月中旬第一个星期日的凌晨2时整(北京夏令时),再将时钟拨回一小时,即将表针由2时拨至1时,夏令时结束。从1986年到1991年的六个年度,除1986年因是实行夏时制的第一年,从5月4日开始到9月14日结束外,其它年份均按规定的时段施行。在夏令时开始和结束前几天,新闻媒体均刊登有关部门的通告。1992年起,夏令时暂停实行。
关于夏令时的详细资料
中国夏时制实施时间规定(夏令时)
1935年至1951年,每年5月1日至9月30日。
1952年3月1日至10月31日。
1953年至1954年,每年4月1日至10月31日。
1955年至1956年,每年5月1日至9月30日。
1957年至1959年,每年4月1日至9月30日。
1960年至1961年,每年6月1日至9月30日。
1974年至1975年,每年4月1日至10月31日。
1979年7月1日至9月30日。
1986年至1991年,每年4月中旬的第一个星期日1时起至9月中旬的第一个星期日1时止。具体如下:
1986年4月13日至9月14日,
1987年4月12日至9月13日,
1988年4月10日至9月11日,
1989年4月16日至9月17日,
1990年4月15日至9月16日,
1991年4月14日至9月15日。
以上所有日期时间格式化时候都会出现空值问题
使用Asia/Shanghai TimeZone 就会出现问题
而使用GMT市区 问题消失
[_dateForrmatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
那么问题来了.....app中之前的所有时间都是用的Asia/Shanghai市区,又不可能直接使用GMT时区替换...磕了 寻找解决方案
解决办法
为了把更改量降到最低
使用 [NSTimeZone timeZoneForSecondsFromGMT:3600*8]; 设置时区
不要使用[NSTimeZone timeZoneWithName:@"Asia/Shanghai"]
虽然理论上shanghai是比GMT多了8个时区,但是结果是不一样的....
1 2 3 4 5 6 7 8 9 10 11 12 |
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateFormat = @"yyyy-MM-dd"; [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:3600*8]]; NSLog(@"%@",dateFormatter.timeZone.name); NSDate *date = [dateFormatter dateFromString:@"1988-04-10"]; NSLog(@"date3600*8:%@", date); [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"Asia/Shanghai"]]; NSDate *date2 = [dateFormatter dateFromString:@"1988-04-10"]; NSLog(@"dateShanghai:%@", date2); |
多个国家切换问题
使用 [NSTimeZone timeZoneForSecondsFromGMT:3600*8]; 设置时区,的确可以解决大陆的夏令时时间问题.
如果APP需要多个时区使用那么写死3600*8就不那么完美了.
我们都知道3600*8是目标时区与GMT时区相差的秒数而已,那么动态计算出来这个Offset秒数即可.
1 2 3 4 5 6 7 8 9 10 |
//设置转换后的目标日期时区 NSTimeZone *toTimeZone = [NSTimeZone localTimeZone]; //转换后源日期与世界标准时间的偏移量 NSInteger toGMTOffset = [toTimeZone secondsFromGMTForDate:[NSDate date]]; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateFormat = @"yyyy-MM-dd"; [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:toGMTOffset]]; NSDate *date0 = [dateFormatter dateFromString:@"1988-04-10"]; NSLog(@"timeZoneForSecondsFromGMT:%@", date0); |
问题完美解决
写了一个NSTimeZone的Category
https://github.com/shaojiankui/NSTimeZone-JKLocalTimeZone
转载请注明:天狐博客 » iOS开发之夏令时,NSDateFormatter格式化失败