0%

iOS时间NSDate和NSDateFormatter时区设置

time

时间NSDate

首先需要弄清楚时间NSDate,大部分时候我们都会忽略掉时区,比如正确打印结果是下面模式:

1
2
2018-07-14 14:17:32 +0000
2018-07-14 09:17:32 GMT+3

这个才是完整模式,带有时区,前一个是格林威治时间,后一个是东3区的时间,因此在获取当前时区的时候可以使用[NSdate date]得到的是GMT的时间,打印结果如下:

1
2018-07-14 06:22:37 +0000

注意时区显示,NSDate是没有时区选项的,获取的永远都是GMT的时间,只有在格式化输出的时候才会有时区选项,所以正确获取当前时间需要加8小时,方法如下:

1
2
3
4
5
NSDate *date = [NSDate date];
NSTimeZone *zone = [NSTimeZone systemTimeZone];
NSTimeInterval interval = [timeZone secondsFromGMTForDate:date];
NSDate *currentDate = [date dateByAddingTimeInterval:interval];
NSLog(@"curentDate:%@", currentDate);

输出结果如下

1
currentDate:2018-07-14 14:31:18 +0000

注意时区还是GMT的,但是我们加了8个时区表示北京时间,时区这里是无法更改。

格式化NSDateFormatter

格式化相对于时间多了时区NSTimeZone设置,默认使用的是系统时区,格式化当前时间:

1
2
3
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss O";
NSLog(@"dateString:%@", [fmt stringFromDate:NSDate.date]);

输出结果

1
2018-07-14 14:56:06.830 StarSun[5335:1737047] dateString:2018-07-14 14:56:06 GMT+8

可以看到时间格式里面的时区为GMT+8,表示当前北京时间,因为NSDateFormatter默认时区为系统时区,现在改一下时区看结果

1
2
3
4
fmt.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
NSLog(@"GMT dateString:%@", [fmt stringFromDate:NSDate.date]);
fmt.timeZone = [NSTimeZone timeZoneWithName:@"Asia/Tokyo"];
NSLog(@"Tokyo dateString:%@", [fmt stringFromDate:NSDate.date]);

分别改为GMT和东京时区,打印结果:

1
2
2018-07-14 14:59:53.401 StarSun[5340:1738007] GMT dateString:2018-07-14 06:59:53 GMT
2018-07-14 14:59:53.401 StarSun[5340:1738007] Tokyo dateString:2018-07-14 15:59:53 GMT+9

时间刚好和我们的时间相差对应的时区小时。这里是时间转换为字符串格式,系统会直接使用对应时区打印出正确的结果,如果是字符串转换成NSDate,先看设置方式

1
2
fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss x";
NSLog(@"stringDate:%@", [fmt dateFromString:@"2018-07-14 14:59:53 +08"]);

再看打印结果

1
2018-07-14 15:13:55.906 StarSun[5373:1743377] stringDate:2018-07-14 06:59:53 +0000

然鹅,结果并不是我们想要的?再仔细看,不就是我们要的结果吗,看时区会发现在GMT,因此结果是正确,再一次说明了NSDate是没有时区概念的,统统转成标准时区,然后你们再根据各地时区格式化一下即可,这样想就觉得没毛病了。

小结

关于iOS时区问题就这些了,其实也不难,主要注意看时区就不难理解了,然后基于此随便转换都行。系统在处理日期问题的时候除了NSDate外都会涉及到时区问题,因此只有在我们需要直接拿NSDate使用的时候才需要添加时区(如北京时间为8小时),其他的时间格式化和日历相关(NScalendarNSdateComponents等)的都不需要我们直接去添加时区小时,只需传NSDate值即可,并不会影响最后的结果。