在iOS中,我們處理時間的時候,往往會使用到NSDate這個類,但是有的時候我們或許也會使用到NSCalendar這個類,下面就先簡單介紹下NSDate這個類。
NSDate和字符串的相互轉(zhuǎn)換
1.將字符串轉(zhuǎn)為帶格式的日期
- 字符串有規(guī)則的樣式
void string2date() {
// 時間字符串
NSString *string = @"2015-11-20 09:33:22";
// 日期格式化類
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
// 設(shè)置日期格式(為了轉(zhuǎn)換成功)
fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
// NSString * -> NSDate *
NSDate *date = [fmt dateFromString:string];
NSString *newStr = [fmt stringFromDate:date];
NSLog(@"%@", date);
NSLog(@"%@", newStr);
}
// 打印結(jié)果
2016-10-20 01:33:22 +0000
2016-10-20 09:33:22
可以看出以上的打印結(jié)果是有八個小時的時差,這是由于上面的date所表示的區(qū)域是格林威治時間,我們處于的是東八區(qū)。
- 字符串的樣式不規(guī)則
以上的字符串是有著比較規(guī)則的樣式,假如有的服務(wù)器返回的結(jié)果是比較混亂的話,在對日期的格式樣式重新設(shè)置的話也是可以得到的想要的數(shù)據(jù)。
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]);
}
// 打印結(jié)果
2016-10-20 01:10:05 +0000
- 當(dāng)字符串中有英文的表達(dá)樣式
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";
// 設(shè)置語言區(qū)域(因為這種時間是歐美常用時間)
fmt.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
NSLog(@"%@", [fmt dateFromString:string]);
}
// 打印結(jié)果
2016-05-31 09:46:55 +0000
上面的代碼中的EEE表示的是星期的縮寫,MMM表示的月份的縮寫,其中的Z或ZZZZ表示的是時區(qū)。
- 時間戳樣式
有時候服務(wù)器返回我們的字符串不一定是以上的規(guī)則的樣式或者是不規(guī)則樣式的字符串,返回給我們就是一長串的數(shù)字,這就是時間戳,其意思是距離1970年1月1日0點(diǎn)0分0秒的時間,單位是秒。
void string2date4() {
// 時間戳 : 從1970年1月1號 00:00:00開始走過的秒數(shù)
// 時間字符串 - 時間戳
NSString *string = @"1745645645645";
// 轉(zhuǎn)為秒為單位
NSTimeInterval second = string.longLongValue / 1000.0;
// 時間戳 -> NSDate *
NSDate *date = [NSDate dateWithTimeIntervalSince1970:second];
NSLog(@"%@", date);
}
// 打印結(jié)果
2025-04-26 05:34:05 +0000
2.日期轉(zhuǎn)為字符串
- 轉(zhuǎn)為有固定格式的字符串
void date2string() {
// 獲取當(dāng)前的時間
NSDate *date = [NSDate date];
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
// 給轉(zhuǎn)換的字符串一個固定格式
fmt.dateFormat = @"yyyy年MM月dd號 HH:mm:ss";
NSString *string = [fmt stringFromDate:date];
NSLog(@"----%@+++++", string);
}
// 打印結(jié)果
----2016年10月24號 16:19:42+++++
在以上的代碼中需要特別值得注意的是給字符串一個固定的格式,不然轉(zhuǎn)換成的字符串就不知道以何種格式展示出來,打印出來為空。
獲取到日期的年月日時分秒
有的時候我們其實只需要獲取到時間中的年月日等元素,這時候就需要抽取時間元素中一些子元素。
如果返回的字符串的格式是規(guī)則的話就可以用定位的方式就可以截取到其中想要的元素。
void getComponentsOfDate() {
// 時間字符串
NSString *string = @"2016-10-20 09:10:05";
NSString *month = [string substringWithRange:NSMakeRange(5, 2)];
NSLog(@"%@", month);
}
// 打印結(jié)果
10
這樣是可以截取到想要的結(jié)果,但是如果我想得到時間中所有的元素,就要重復(fù)多次這樣的代碼,這樣就比較麻煩,所以不建議使用。我們可以考慮使用NSCalendar這個類中的方法去截取時間中的所有元素。
void getComponentsOfDate2() {
// 時間字符串
NSString *string = @"2016-10-20 09:10:05";
// 日期格式化類
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
// 設(shè)置日期格式(為了轉(zhuǎn)換成功)
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);
}
// 打印結(jié)果
10 09 10
假如要一次性得到時間中的所有元素就可以考慮使用NSCalendarUnit類去得到時間中年月日等元素,這些都是可以用或運(yùn)算進(jìn)行操作的。
void getComponentsOfDate3() {
// 時間字符串
NSString *string = @"2016-10-20 09:10:05";
// 日期格式化類
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
// 設(shè)置日期格式(為了轉(zhuǎn)換成功)
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);
}
// 打印結(jié)果
<NSDateComponents: 0x101018c10>
Calendar Year: 2016
Month: 10
Leap month: no
Day: 20
Hour: 9
Minute: 10
Second: 5
通過以上的unit可以取到想要的元素,放到NSDateComponents中打印出來。
時間的比較
往往有的時候會用到時間與時間的相互比較,例如微博中,一條微博的發(fā)布,會顯示是什么時候發(fā)布的,如:“剛剛”、“一個小時前”等,這需要用到發(fā)布時間和當(dāng)前時間的比較,并且通過一系列的判斷展示到界面上去。
- 簡單比較
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];
// 手機(jī)當(dāng)前時間
NSDate *nowDate = [NSDate date];
/**
NSComparisonResult的取值
NSOrderedAscending = -1L, // 升序, 越往右邊越大
NSOrderedSame, // 相等
NSOrderedDescending // 降序, 越往右邊越小
*/
// 獲得比較結(jié)果(誰大誰小)
NSComparisonResult result = [nowDate compare:createdAtDate];
if (result == NSOrderedAscending) { // 升序, 越往右邊越大
NSLog(@"createdAtDate > nowDate");
} else if (result == NSOrderedDescending) { // 降序, 越往右邊越小
NSLog(@"createdAtDate < nowDate");
} else {
NSLog(@"createdAtDate == nowDate");
}
}
// 打印結(jié)果
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];
// 手機(jī)當(dāng)前時間
// NSDate *nowDate = [NSDate date];
// 獲得createdAtDate和nowDate的時間間隔(間隔多少秒)
// NSTimeInterval interval = [nowDate timeIntervalSinceDate:createdAtDate];
NSTimeInterval interval = [createdAtDate timeIntervalSinceNow];
NSLog(@"%f", interval);
}
// 打印結(jié)果
2305313.187479
// 正表示當(dāng)前時間之后的時間,負(fù)表示當(dāng)前時間之前的時間。
timeIntervalSinceDate:表示一個時間到另一個時間的相隔的時間;
timeIntervalSinceNow表示的是一個時間到現(xiàn)在時間之間相隔的時間。
- 高級比較
以上的結(jié)果是可以得到兩個相比較的時間之間的間隔時間,但是并不能很好的反應(yīng)出到底是相差多少天或者是多少個月,可以借助到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);
}
// 打印結(jié)果
<NSDateComponents: 0x10060a5e0>
Calendar Year: 0
Month: 0
Day: -1
Hour: 0
Minute: -13
Second: -20
從打印的結(jié)果可以清楚的看出兩個時間之間的相差多少日、時、分、秒等。
判斷是否為今天、昨天等
有的時候需要判斷當(dāng)前的日期是否今天或者是在當(dāng)月等的需求,這就需要作出判斷。
系統(tǒng)方法
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"]]);
}
以上的打印結(jié)果為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之后出現(xiàn)的,所以在iOS8.0之前的版本是適用不了的,如果想要得到判斷的話就需要自己去封裝,其中還是需要用到NSCalendar這個類,因為這個類可以取到時間中的所有元素。
自定義封裝
- 判斷今天
- (BOOL)isToday {
// 判斷self這個日期是否為今天
NSCalendar *calendar = [NSCalendar calendar];
// 獲得年月日元素
NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
// 獲取到self這個日期中所有的元素
NSDateComponents *selfCmps = [calendar components:unit fromDate:self];
// 獲取到`現(xiàn)在`這個日期中的所有元素
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
總結(jié):
1.在NSDate這個類中可以對字符串轉(zhuǎn)換成date數(shù)據(jù),對轉(zhuǎn)換成的字符串的格式是有要求的。
2.時間戳的處理,要看清楚服務(wù)器返回的字符串的位數(shù),要仔細(xì)處理時間戳的單位。
3.NSCalendar這個類中可以對時間的處理有些比較高端的處理,有些功能是NSDate處理不了的。但是如果在iOS 8.0之前,有些用法是需要自定義封裝的。
4.寫的不對的地方,還望大家直接指出,小弟不勝感激。