iOS之时间相关

在iOS中,我们处理时间的时候,往往会使用到NSDate这个类,但是有的时候我们或许也会使用到NSCalendar这个类,下面就先简单介绍下NSDate这个类。

NSDate和字符串的相互转换

1.将字符串转为带格式的日期

  • 字符串有规则的样式
void string2date() {
    // 时间字符串
    NSString *string = @"2015-11-20 09:33:22";
    // 日期格式化类
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    // 设置日期格式(为了转换成功)
    fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    // NSString * -> NSDate *
    NSDate *date = [fmt dateFromString:string];
    NSString *newStr = [fmt stringFromDate:date];
    NSLog(@"%@", date);
    NSLog(@"%@", newStr);
}
// 打印结果
2016-10-20 01:33:22 +0000
2016-10-20 09:33:22

可以看出以上的打印结果是有八个小时的时差,这是由于上面的date所表示的区域是格林威治时间,我们处于的是东八区。

  • 字符串的样式不规则

以上的字符串是有着比较规则的样式,假如有的服务器返回的结果是比较混乱的话,在对日期的格式样式重新设置的话也是可以得到的想要的数据。

void string2date2() {
    // 时间字符串
    NSString *string = @"10月-20号/2016年 09-10:05秒";
    // 日期格式化类
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"MM月-dd号/yyyy年 HH-mm:ss秒";
    NSLog(@"%@", [fmt dateFromString:string]);
}
// 打印结果
2016-10-20 01:10:05 +0000
  • 当字符串中有英文的表达样式
void string2date3() {
    // 时间字符串
    NSString *string = @"Tue May 31 17:46:55 +0800 2011";
    // 日期格式化类
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy";
    // fmt.dateFormat = @"EEE MMM dd HH:mm:ss ZZZZ yyyy";
    // 设置语言区域(因为这种时间是欧美常用时间)
    fmt.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
    NSLog(@"%@", [fmt dateFromString:string]);
}
// 打印结果
2016-05-31 09:46:55 +0000

上面的代码中的EEE表示的是星期的缩写,MMM表示的月份的缩写,其中的ZZZZZ表示的是时区。

  • 时间戳样式

有时候服务器返回我们的字符串不一定是以上的规则的样式或者是不规则样式的字符串,返回给我们就是一长串的数字,这就是时间戳,其意思是距离1970年1月1日0点0分0秒的时间,单位是

void string2date4() {
    // 时间戳 : 从1970年1月1号 00:00:00开始走过的秒数
    // 时间字符串 - 时间戳
    NSString *string = @"1745645645645";
    // 转为秒为单位
    NSTimeInterval second = string.longLongValue / 1000.0;
    // 时间戳 -> NSDate *
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:second];  
    NSLog(@"%@", date);
}
// 打印结果
2025-04-26 05:34:05 +0000

2.日期转为字符串

  • 转为有固定格式的字符串
void date2string() {
    // 获取当前的时间
    NSDate *date = [NSDate date];
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    // 给转换的字符串一个固定格式
    fmt.dateFormat = @"yyyy年MM月dd号 HH:mm:ss";
    NSString *string = [fmt stringFromDate:date];
    NSLog(@"----%@+++++", string);  
}
// 打印结果
----2016年10月24号 16:19:42+++++

在以上的代码中需要特别值得注意的是给字符串一个固定的格式,不然转换成的字符串就不知道以何种格式展示出来,打印出来为空。

获取到日期的年月日时分秒

有的时候我们其实只需要获取到时间中的年月日等元素,这时候就需要抽取时间元素中一些子元素。
如果返回的字符串的格式是规则的话就可以用定位的方式就可以截取到其中想要的元素。

void getComponentsOfDate() {
    // 时间字符串
    NSString *string = @"2016-10-20 09:10:05";
    NSString *month = [string substringWithRange:NSMakeRange(5, 2)];
    NSLog(@"%@", month);
}
// 打印结果
10

这样是可以截取到想要的结果,但是如果我想得到时间中所有的元素,就要重复多次这样的代码,这样就比较麻烦,所以不建议使用。我们可以考虑使用NSCalendar这个类中的方法去截取时间中的所有元素。

void getComponentsOfDate2() {
    // 时间字符串
    NSString *string = @"2016-10-20 09:10:05";
    // 日期格式化类
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    // 设置日期格式(为了转换成功)
    fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    // NSString * -> NSDate *
    NSDate *date = [fmt dateFromString:string];
    // 利用NSCalendar处理日期
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSInteger month = [calendar component:NSCalendarUnitMonth fromDate:date];
    NSInteger hour = [calendar component:NSCalendarUnitHour fromDate:date];
    NSInteger minute = [calendar component:NSCalendarUnitMinute fromDate:date];
    NSLog(@"%zd %zd %zd", month, hour, minute);
}
// 打印结果
10 09 10

假如要一次性得到时间中的所有元素就可以考虑使用NSCalendarUnit类去得到时间中年月日等元素,这些都是可以用或运算进行操作的。

void getComponentsOfDate3() {
    // 时间字符串
    NSString *string = @"2016-10-20 09:10:05";
    // 日期格式化类
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    // 设置日期格式(为了转换成功)
    fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    // NSString * -> NSDate *
    NSDate *date = [fmt dateFromString:string];
    // 利用NSCalendar处理日期
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
    NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *cmps = [calendar components:unit  fromDate:date];
    //    NSLog(@"%zd %zd %zd", cmps.year, cmps.month, cmps.day);
    NSLog(@"%@", cmps);
}
// 打印结果
<NSDateComponents: 0x101018c10>
    Calendar Year: 2016
    Month: 10
    Leap month: no
    Day: 20
    Hour: 9
    Minute: 10
    Second: 5

通过以上的unit可以取到想要的元素,放到NSDateComponents中打印出来。

时间的比较

往往有的时候会用到时间与时间的相互比较,例如微博中,一条微博的发布,会显示是什么时候发布的,如:“刚刚”、“一个小时前”等,这需要用到发布时间和当前时间的比较,并且通过一系列的判断展示到界面上去。

  • 简单比较
void dateCompare() {
    // 时间字符串
    NSString *createdAtString = @"2015-11-20 11:10:05";
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    NSDate *createdAtDate = [fmt dateFromString:createdAtString];

    // 手机当前时间
    NSDate *nowDate = [NSDate date];

    /**
     NSComparisonResult的取值
     NSOrderedAscending = -1L, // 升序, 越往右边越大
     NSOrderedSame,  // 相等
     NSOrderedDescending // 降序, 越往右边越小
     */
    // 获得比较结果(谁大谁小)
    NSComparisonResult result = [nowDate compare:createdAtDate];
    if (result == NSOrderedAscending) { // 升序, 越往右边越大
        NSLog(@"createdAtDate > nowDate");
    } else if (result == NSOrderedDescending) { // 降序, 越往右边越小
        NSLog(@"createdAtDate < nowDate");
    } else {
        NSLog(@"createdAtDate == nowDate");
    }
}
// 打印结果
createdAtDate < nowDate

以上只能比较出两个日期之前的先后或者是否为同一个时间,但是不能真实的比较出两个时间之间相差的时间;

  • 间隔时间
void dateCompare2() {
    // 时间字符串
    NSString *createdAtString = @"2016-11-20 09:10:05";
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    NSDate *createdAtDate = [fmt dateFromString:createdAtString];

    // 手机当前时间
    //    NSDate *nowDate = [NSDate date];

    // 获得createdAtDate和nowDate的时间间隔(间隔多少秒)
    //    NSTimeInterval interval = [nowDate timeIntervalSinceDate:createdAtDate];
    NSTimeInterval interval = [createdAtDate timeIntervalSinceNow];
    NSLog(@"%f", interval);
}
// 打印结果
2305313.187479 
// 正表示当前时间之后的时间,负表示当前时间之前的时间。

timeIntervalSinceDate:表示一个时间到另一个时间的相隔的时间;
timeIntervalSinceNow表示的是一个时间到现在时间之间相隔的时间。

  • 高级比较

以上的结果是可以得到两个相比较的时间之间的间隔时间,但是并不能很好的反应出到底是相差多少天或者是多少个月,可以借助到NSCalendar中的一些方法可以解决上述的问题。

void dateCompare3() {
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";

    // 时间字符串
    NSString *createdAtString = @"2015-11-01 09:10:05";
    NSDate *createdAtDate = [fmt dateFromString:createdAtString];
    // 其他时间
    NSString *otherString = @"2015-10-31 08:56:45";
    NSDate *otherDate = [fmt dateFromString:otherString];
    // 获得NSCalendar
    NSCalendar *calendar = nil;
    // 这个判断主要是由于iOS版本的限制,`calendarWithIdentifier: `这个方法是iOS8.0之后开始使用的
    if ([NSCalendar respondsToSelector:@selector(calendarWithIdentifier:)]) {
        calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
    } else {
        calendar = [NSCalendar currentCalendar];
    }

    // 获得日期之间的间隔
    NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *cmps = [calendar components:unit fromDate:createdAtDate toDate:otherDate options:0];  
    NSLog(@"%@", cmps);
}
// 打印结果
<NSDateComponents: 0x10060a5e0>
    Calendar Year: 0
    Month: 0
    Day: -1
    Hour: 0
    Minute: -13
    Second: -20

从打印的结果可以清楚的看出两个时间之间的相差多少日、时、分、秒等。

判断是否为今天、昨天等

有的时候需要判断当前的日期是否今天或者是在当月等的需求,这就需要作出判断。

系统方法

void judgeToday() {
    // 获得NSCalendar
    NSCalendar *calendar = nil;
    if ([NSCalendar respondsToSelector:@selector(calendarWithIdentifier:)]) {
        calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
    } else {
        calendar = [NSCalendar currentCalendar];
    }    
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    NSLog(@"%zd", [calendar isDateInToday:[fmt dateFromString:@"2015-11-10 01:09:56"]]);  
}

以上的打印结果为0,所以得知不是今天

// 今天的判断
- (BOOL)isDateInToday:(NSDate *)date NS_AVAILABLE(10_9, 8_0);
// 昨天的判断
- (BOOL)isDateInYesterday:(NSDate *)date NS_AVAILABLE(10_9, 8_0);
// 明天的判断
- (BOOL)isDateInTomorrow:(NSDate *)date NS_AVAILABLE(10_9, 8_0);
// 周末的判断
- (BOOL)isDateInWeekend:(NSDate *)date NS_AVAILABLE(10_9, 8_0);
// 是否为同一天
- (BOOL)isDate:(NSDate *)date1 inSameDayAsDate:(NSDate *)date2 NS_AVAILABLE(10_9, 8_0);

可以看出上面的代码都是iOS8.0之后出现的,所以在iOS8.0之前的版本是适用不了的,如果想要得到判断的话就需要自己去封装,其中还是需要用到NSCalendar这个类,因为这个类可以取到时间中的所有元素。

自定义封装

  • 判断今天
- (BOOL)isToday {
    // 判断self这个日期是否为今天
    NSCalendar *calendar = [NSCalendar calendar];  
    // 获得年月日元素
    NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
    // 获取到self这个日期中所有的元素
    NSDateComponents *selfCmps = [calendar components:unit fromDate:self];
     // 获取到`现在`这个日期中的所有元素
    NSDateComponents *nowCmps = [calendar components:unit fromDate:[NSDate date]];
    return selfCmps.year == nowCmps.year
    && selfCmps.month == nowCmps.month
    && selfCmps.day == nowCmps.day;
}
  • 判断昨天或是明天
NSDateComponents *cmps = [calendar components:unit fromDate:selfDate toDate:nowDate options:0];
return cmps.year == 0
    && cmps.month == 0
    // 1代表昨天,-1代表明天(具体的还是要看具体代码的逻辑)
    && cmps.day == -1;// 1

总结:
1.在NSDate这个类中可以对字符串转换成date数据,对转换成的字符串的格式是有要求的。
2.时间戳的处理,要看清楚服务器返回的字符串的位数,要仔细处理时间戳的单位。
3.NSCalendar这个类中可以对时间的处理有些比较高端的处理,有些功能是NSDate处理不了的。但是如果在iOS 8.0之前,有些用法是需要自定义封装的。
4.写的不对的地方,还望大家直接指出,小弟不胜感激。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,738评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,377评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,774评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,032评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,015评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,239评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,724评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,374评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,410评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,457评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,132评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,733评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,804评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,022评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,515评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,116评论 2 341

推荐阅读更多精彩内容