在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
表示的月份的缩写,其中的Z
或ZZZZ
表示的是时区。
- 时间戳样式
有时候服务器返回我们的字符串不一定是以上的规则的样式或者是不规则样式的字符串,返回给我们就是一长串的数字,这就是时间戳
,其意思是距离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);
}
// 打印结果
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);
}
// 打印结果
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.写的不对的地方,还望大家直接指出,小弟不胜感激。