时间NSDate
首先需要弄清楚时间NSDate
,大部分时候我们都会忽略掉时区,比如正确打印结果是下面模式:
1 | 2018-07-14 14:17:32 +0000 |
这个才是完整模式,带有时区,前一个是格林威治时间,后一个是东3区的时间,因此在获取当前时区的时候可以使用[NSdate date]
得到的是GMT
的时间,打印结果如下:
1 | 2018-07-14 06:22:37 +0000 |
注意时区显示,NSDate
是没有时区选项的,获取的永远都是GMT
的时间,只有在格式化输出的时候才会有时区选项,所以正确获取当前时间需要加8小时,方法如下:
1 | NSDate *date = [NSDate date]; |
输出结果如下
1 | currentDate:2018-07-14 14:31:18 +0000 |
注意时区还是GMT
的,但是我们加了8个时区表示北京时间,时区这里是无法更改。
格式化NSDateFormatter
格式化相对于时间多了时区NSTimeZone
设置,默认使用的是系统时区,格式化当前时间:
1 | NSDateFormatter *fmt = [[NSDateFormatter alloc] init]; |
输出结果
1 | 2018-07-14 14:56:06.830 StarSun[5335:1737047] dateString:2018-07-14 14:56:06 GMT+8 |
可以看到时间格式里面的时区为GMT+8
,表示当前北京时间,因为NSDateFormatter
默认时区为系统时区,现在改一下时区看结果
1 | fmt.timeZone = [NSTimeZone timeZoneWithName:@"GMT"]; |
分别改为GMT
和东京时区,打印结果:
1 | 2018-07-14 14:59:53.401 StarSun[5340:1738007] GMT dateString:2018-07-14 06:59:53 GMT |
时间刚好和我们的时间相差对应的时区小时。这里是时间转换为字符串格式,系统会直接使用对应时区打印出正确的结果,如果是字符串转换成NSDate
,先看设置方式
1 | fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss x"; |
再看打印结果
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小时),其他的时间格式化和日历相关(NScalendar
和NSdateComponents
等)的都不需要我们直接去添加时区小时,只需传NSDate
值即可,并不会影响最后的结果。