关于NSDate,NSDateFormatter,NSTimeZone的一些通俗理解

基础概念

1.GMT 0:00 格林威治标准时间; UTC +00:00 校准的全球时间; CCD
  +08:00 中国标准时间 

2.iOS中的时间类NSDate中存储的时间,都是相对于GMT的,我们使用NSDate
时(NSDate必须是0时区的,UTC格式的),会根据App设置的当前时区设置返回
与时区对应的数据。

3.iOS中的时区表示方法:GMT+0800 GMT-0800。(+:东区 -:西区 08:小
时数 00:分钟数)。 GMT+0830就是指比GMT早8小时外加30分钟的时区。

4.世界标准时间,国际协调时间,简称UTC。不属于任意时区

5.系统认为NSDate是0时区的,NSString是东八区的

关于NSDate,NSDateFormatter,NSTimeZone的一些通俗理解_第1张图片


简单说下个人的理解 根据时区可以看到,我们在东八区,时间点比国际标准时间快八小时,而LA在在西7区,时间慢7小时,因此,同一时间下,你切换手机坐标,你获取的时间戳美国比中国的大,因为时间戳的计算都是根据0时区来算的,中国的要减去,美国自然要加上了,有个简单的例子,如果你默认NSDate TimeZone下,你切换计算时间戳是没有问题,但是如果你用东八区的时间戳去使用,肯定比实际上多出来八小时,这个时候如果要上传给服务器,那就尴尬了哈。。。如果你手动切换时区,记得算好时间戳。下面会给例子,有个很重要的思想就是,显示的时候用NSString,但是内部涉及到计算,比较,时间戳的问题,都是要NSDate,这样保证计算出来的东西肯定不会错

代码示例一:不同时区之间的时间转换

 // 获取usr/share/zoneinfo目录下所有已知的时区
    NSArray *arr = [NSTimeZone knownTimeZoneNames];

    // 获取所有时区的缩写
    NSDictionary *dict = [NSTimeZone abbreviationDictionary];
    NSLog(@"%@",dict);

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    NSString *timeStr = @"2017-05-10";
    NSDate *currentDate = [dateFormatter dateFromString:timeStr];
    NSLog(@"需要格式化的时区--->%@,格式后的Date--->%@",dateFormatter.timeZone,currentDate);


    [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
    NSDate *currentDate1 = [dateFormatter dateFromString:timeStr];
    NSLog(@"需要格式化的时区--->%@,格式后的Date--->%@",dateFormatter.timeZone,currentDate1);


    [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"America/Los_Angeles"]];
    NSDate *currentDate2 = [dateFormatter dateFromString:timeStr];
    NSLog(@"需要格式化的时区--->%@,格式后的Date--->%@",dateFormatter.timeZone,currentDate2);
    /*
     2017-05-05 14:32:13.893 NSData[10583:4643459] 需要格式化的时区--->Asia/Shanghai (GMT+8) offset 28800,格式后的Date--->2017-05-09 16:00:00 +0000
     个人理解:
     时间信息都是针对于GMT标准时区来的,那么NSDate是根据当前设置的时区来进行计算的,那么例如上面的时间,默认是上海东八区的话就是向前移动8小时就是0时区的时间,所以打印出来的就是少8小时

     OK,我们来设置下dateFormatter的时区为GMT和PDT(美国洛杉矶西七区),也就是NSDate默认为你就在标准时区的坐标下,你给出来的时间根本不需要进行时区的转换,直接显示出来接即可,但是PDT的情况下是西区,时间比0区小,因此要加上7小时
     2017-05-05 15:01:52.121 NSData[10996:4659886] 需要格式化的时区--->GMT (GMT) offset 0,格式后的Date--->2017-05-10 00:00:00 +0000
     2017-05-05 15:01:52.124 NSData[10996:4659886] 需要格式化的时区--->America/Los_Angeles (PDT) offset -25200 (Daylight),格式后的Date--->2017-05-10 07:00:00 +0000
     */



这一坨简单的代码和上面的图一结合,应该非常清楚的能明白
首先,NSDate是计算0时区的时间,默认情况下NSDateFormmater是获取当前手机设置的时区(咱们的是东八区),因此,这就解释了默认情况下你转换的时间NSDate比字符串少了八个小时,但是如果你手动表示,你就在GMT,那就不需要转换了,直接显示字符串时间,但是如果你说你在LA,西区,自然要加上7小时了




代码示例二:String和Date转换

 // 最简单的NSDate和NSString的转换
    NSString *timeStr1 = @"2017-5-20";
    NSDateFormatter *dateFormatter1 = [[NSDateFormatter alloc] init];
    [dateFormatter1 setDateFormat:@"yyyy-MM-dd"];
    NSDate *date1 = [dateFormatter1 dateFromString:timeStr1];
    // 加上了这句话 转换的时候无需再算上时区,直接转换
    // [dateFormatter1 setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
    NSString *resultStr = [dateFormatter1 stringFromDate:date1];
    NSLog(@"%@,%@",date1,resultStr);




这简单例子告诉我们,默认不设置时区的情况下,如果你在天朝东八区,你用的时间字符串,转换成NSDate(无论如何算出来的都是GMT/UTC国际标准时间0时期的时间)的时候会减去八小时,但是转换成NSString的时候又会转换成GMT标准时间下的(加上了八小时当前时期东八区)字符串,系统认为NSDate是0时区的,NSString是东八区的


代码示例三:反面教材,可以用TimeZone进行时区切换操作更好

NSDate *date3 = [NSDate date];
    NSLog(@"NSDate(0时区标准时间 所在东八区,要减去八小时)----当前时间1%@",date3);

    NSDate *date4 = [NSDate dateWithTimeIntervalSinceNow:0];
    NSLog(@"NSDate(0时区标准时间 所在东八区,要减去八小时)----当前时间2%@",date4);

    NSDate *date5 = [NSDate dateWithTimeIntervalSinceNow:8*60*60];
    NSLog(@"NSDate(0时区标准时间 所在东八区,要减去八小时)----当前时间3加上今天此刻时间%@",date5);


    NSDate *date6 = [NSDate dateWithTimeIntervalSinceNow:(8-24)*60*60];
    NSLog(@"NSDate(0时区标准时间 所在东八区,要减去八小时)----当前时间3昨天此刻时间%@",date6);


    NSDate *date7 = [NSDate dateWithTimeIntervalSinceNow:(8+24)*60*60];
    NSLog(@"NSDate(0时区标准时间 所在东八区,要减去八小时)----当前时间3明天此刻时间%@",date7);

    // 参数1比参数2小返回的是负数
    NSTimeInterval timeIntervel = [date6 timeIntervalSinceDate:date7];
    NSLog(@"NSDate(0时区标准时间 所在东八区,要减去八小时)----当前时间3昨天和明天时间间隔%.f",timeIntervel);



代码示例四:时间戳秒数转换NSDate注意点

/*
     不转换的时候NSDate出来的肯定是没有问题的0时区的时间
     */
    NSDate *date8 = [NSDate date];
    NSTimeInterval time8 = [date8 timeIntervalSince1970];
    NSLog(@"%.f",time8);

    NSDate *date9 = [NSDate dateWithTimeIntervalSince1970:1493968897];
    NSLog(@"%@",date9);

    // 这个例子只是说明,如果你用东八区的时间,然后你又手动修改了你当前的时区,你该到了GMT 0时区,这个时候的时间戳肯定比0时区多出八小时了,
    // 你只要明白,正确的时间戳都针对GMT 0时区的国际标准时间为准的,如果前后台需要涉及到时间上传交互,你如果你手动切换了时区,需要注意时区
    NSDate *date10 = [NSDate date];
    NSDateFormatter *fotmatter10 = [[NSDateFormatter alloc] init];
    [fotmatter10 setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *string10 = [fotmatter10 stringFromDate:date10];
    [fotmatter10 setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
    NSDate *date100 = [fotmatter10 dateFromString:string10];
    NSTimeInterval time10 = [date100 timeIntervalSince1970];
    NSLog(@"%.f",time10);

    NSDate *date11 = [NSDate dateWithTimeIntervalSince1970:1493998268];
    NSLog(@"%@",date11);



代码示例五:时间转换格式不对等兼容问题

    NSString *timeStringA = @"2017-05-05";
    NSDateFormatter *formatterA = [[NSDateFormatter alloc] init];
    [formatterA setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *dateA = [formatterA dateFromString:timeStringA];
    NSString *timeStringB = @"2017-05-05 00:00:00";
    NSDateFormatter *formatterB = [[NSDateFormatter alloc] init];
    [formatterB setDateFormat:@"yyyy-MM-dd"];
    NSDate *dateB = [formatterB dateFromString:timeStringB];
    NSLog(@"-----%@",dateA);---> (null)
    NSLog(@"-----%@",dateB);--->(null)

    NSDate *dateC = [formatterB dateFromString:[self dateFormatWithoutTimeWithFormatString:@"yyyy-MM-dd" timesString:timeStringB]];
    NSLog(@"%@",dateC);2017-05-04 16:00:00 +0000


// 当时间格式和formatter格式不对等的时候会出现null的情况,这个时候你对比时间计算就会出问题
- (NSString *)dateFormatWithoutTimeWithFormatString:(NSString *)formatString timesString:(NSString *)timeStr
{
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
    NSDateFormatter *dateFormatterNoYearAndSeconds = [[NSDateFormatter alloc] init];
    [dateFormatterNoYearAndSeconds setDateFormat:formatString];
    [dateFormatterNoYearAndSeconds setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
    return [dateFormatterNoYearAndSeconds stringFromDate:[dateFormatter dateFromString:timeStr]]?:timeStr;
}

很简单的知识点记录下而已,网上有很多关于NSDate的扩展,很多都包装好了,最近处理时间的时候打印看到了一些问题,就仔细看了下,一般来说都不会有问题,只是更加了解下时间时区之前的切换问题,明白一点就够了,NSDate就是0时区的时间点,如果你不手动设置时区,默认咱们就是东八区,时间转换成NSDate就会小八小时,但是转换成NSString默认又会加上时区差,还有一点,切换时间的时候,从默认时区修改成了其他时区,你小心你的时间戳会有时区上的差异,记得最后比较下你转换前的时区和转换后的时区,默认的时间戳也是0时区为准的

你可能感兴趣的:(基础知识)