NSDate对象封装单个时间点,与之相关的几个类分别是: NSCalendar, NSDateComponents, NSDateComponentsFormatter
日期时间编程指南
一、NSDate 只能单纯的获取到某个时间点
1.获取当前时间点:
NSDate *date = [NSDate date];
NSDate *date1 = [[NSDate alloc]init];
2.按时间间隔创建日期
- (instancetype)initWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti
NSTimeInterval secondsPerDay = 24 * 60 * 60;
NSDate *tomorrow = [[NSDate alloc] initWithTimeIntervalSinceNow:secondsPerDay];
NSDate *yesterday = [[NSDate alloc] initWithTimeIntervalSinceNow:-secondsPerDay];
3.通过添加时间间隔来创建日期
NSTimeInterval secondsPerDay = 24 * 60 * 60;
NSDate *today = [[NSDate alloc] init];
NSDate *tomorrow, *yesterday;
tomorrow = [today dateByAddingTimeInterval:secondsPerDay];
yesterday = [today dateByAddingTimeInterval:-secondsPerDay];
4.日期之间的精确比较,
这三个方法都是精确到亚秒级别的
-(NSDate *)earlierDate:(NSDate *)anotherDate;//返回较早的那个日期
-(NSDate *)laterDate:(NSDate *)anotherDate;//返回较晚的那个时期
-(BOOL)isEqualToDate:(NSDate *)otherDate;//比较两个日期是不是想等
[tomorrow isEqualToDate:NSDate.date];
如果在某个能接受的范围内就相等(1分钟内都算相等)
-(NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate;这个方法用来计算当前日期和另一个日期之间的时间差
if(fabs([date2 timeIntervalSinceDate:date1])<60){
//…
}
二、NSCalendar 日历对象封装有关计算时间的系统的信息,其中定义了年的开始,长度和分度。您可以使用日历对象在绝对时间和日期成分(例如年,天或分钟)之间进行转换。
1.创建日历了
用户首选语言环境的日历
NSCalendar *calender = [NSCalendar currentCalendar];
创建由给定标识符指定的新日历。
+(nullable NSCalendar *)calendarWithIdentifier:(NSCalendarIdentifier)calendarIdentifierConstant
标识由系统指定,随便看几个常用的:
NSCalendarIdentifierGregorian 阳历
NSCalendarIdentifierBuddhist 佛教日历
NSCalendarIdentifierChinese 中国日历,农历
......
NSCalendar *calender = [NSCalendar calendarWithIdentifier: NSCalendarIdentifierGregorian];
用户创建日历,和currentCalender是一样的
NSCalendar * usersCalendar = [[NSLocale currentLocale] objectForKey:NSLocaleCalendar];
2.相关属性,会影响到后面的计算结果
@property (nullable, copy) NSLocale *locale;地区
例如:en_US
@property (copy) NSTimeZone *timeZone;时区
例如:Asia/Shanghai (GMT+8) offset 28800
@property NSUInteger firstWeekday;每周星期几作为第一天,默认星期天是第一天
设置星期一是第一天:firstWeekday = 2;
比如:@property NSUInteger minimumDaysInFirstWeek;每周最少有几天,低于这个数的不算做一周
5月的第一天是星期五,第一周只有2天,如果设置minimumDaysInFirstWeek为3,那么通过这个方法计算,5月1日是这个月的第0周,5月3号属于第一周,5月31属于第5周
-(NSUInteger)ordinalityOfUnit:(NSCalendarUnit)smaller inUnit:(NSCalendarUnit)larger forDate:(NSDate *)date
//指定日期 2020-5-1 14:00:00
NSDateComponents *components = [[NSDateComponents alloc]init];
components.year = 2020;
components.month = 5;
components.day =30;
components.hour = 14;
NSDate *date = [[NSCalendar currentCalendar] dateFromComponents:components];
NSCalendar *calender = NSCalendar.currentCalendar;
//设置每周的最小天数 3
calender.minimumDaysInFirstWeek = 3;
NSInteger nums = [calender ordinalityOfUnit:NSCalendarUnitWeekOfMonth inUnit:NSCalendarUnitMonth forDate:date];
系统提供的日历单位:常用的如下
NSCalendarUnitYear 年
NSCalendarUnitMonth 月 1-12
NSCalendarUnitDay 天 1-31
NSCalendarUnitHour 小时 0-24
NSCalendarUnitMinute 分钟0-60
NSCalendarUnitSecond 秒 0-60
NSCalendarUnitWeekday 星期 1-7
NSCalendarUnitQuarter 季度 1-4
NSCalendarUnitWeekOfMonth 一个月多少周 最多6
NSCalendarUnitWeekOfYear 一年最多周53
3.接下来说一些常规操作,有些需要结合NSDateComponents类使用
3.1当前日历单位的最小,最大长度
-(NSRange)minimumRangeOfUnit:(NSCalendarUnit)unit;
-(NSRange)maximumRangeOfUnit:(NSCalendarUnit)unit;
例如:每月最大最小有多少天?
[calender minimumRangeOfUnit:NSCalendarUnitDay].length //28
[calender maximumRangeOfUnit:NSCalendarUnitDay].length//31
3.2.根据当前时间点,计算指定单位的长度,比如:当前时间所属的月(5月)的长度是31天
-(NSRange)rangeOfUnit:(NSCalendarUnit)smaller inUnit:(NSCalendarUnit)larger forDate:(NSDate *)date;
[NSCalendar.currentCalendar
rangeOfUnit:NSCalendarUnitMonth
inUnit:NSCalendarUnitYear
forDate:date].length;
3.3 根据给定时间点,计算在给定单位里的序数,比如:当前时间(5月1日) 是一年的第几周,5月的第几周,这个结果受minimumDaysInFirstWeek值的影响(不理解可以在看上文属性介绍)
-(NSUInteger)ordinalityOfUnit:(NSCalendarUnit)smaller inUnit:(NSCalendarUnit)larger forDate:(NSDate *)date;
3.4 根据给定时间,计算该时间所在单位的起始日期(第一天)
-(BOOL)rangeOfUnit:(NSCalendarUnit)unit startDate:(NSDate * _Nullable * _Nullable)datep interval:(nullable NSTimeInterval *)tip forDate:(NSDate *)date
例如:当前时间5月3日,计算当月起始天数
NSDate *firstDate;
NSTimeInterval timeInterval;
if([calender rangeOfUnit:NSCalendarUnitMonth
startDate:&firstDate
interval:&timeInterval
forDate:NSDate.date]){
NSLog(@"第一天是:%@",firstDate);
NSLog(@"%f",timeInterval);
}
获取一周的第一天
NSDate *today = [[NSDate alloc] init];
NSDate *beginningOfWeek = nil;
BOOL ok = [gregorian rangeOfUnit:NSWeekCalendarUnit startDate:&beginningOfWeek interval:NULL forDate:today];
当前日期在NSCalendarUnitMonth单位的起始日期:Sun May 3 00:00:00 2020
当月所有天数的秒数:604800
3.5 获取给定时间的指定单位的值,比如:2020-5-1,单位 月,返回值是 5
-(NSInteger)component:(NSCalendarUnit)unit fromDate:(NSDate *)date
[NSCalendar.currentCalendar component:NSCalendarUnitMonth fromDate:NSDate.date];
3.6 自定义时间,通过 年代,年,月,日.是,分,秒等返回一个具体的date 例如:2020-6-5 12:30:00
-(nullable NSDate *)dateWithEra:(NSInteger)eraValue year:(NSInteger)yearValue month:(NSInteger)monthValue day:(NSInteger)dayValue hour:(NSInteger)hourValue minute:(NSInteger)minuteValue second:(NSInteger)secondValue nanosecond:(NSInteger)nanosecondValue
[NSCalendar.currentCalendar dateWithEra:2
year:2020
month:6
day:5
hour:12
minute:30
second:0
nanosecond:0];
3.7根据指定单位排序(比较大小),-1 升序,0 等于 1 降序
同样可以用NSDate中earlierDate, laterDate方法比较
-(NSComparisonResult)compareDate:(NSDate *)date1 toDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit
比如: 2020-5-4 和2020-5-6 返回-1
[NSCalendar.currentCalendar compareDate:date1 toDate:date2 toUnitGranularity:NSCalendarUnitDay]
3.8 根据指定的日历单位,比较两个日期是否在同一个单位内
-(BOOL)isDate:(NSDate *)date1 equalToDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit
比如:比较2020-6-4和2020-6-5, 单位是 月 返回 YES,单位是 日 返回 NO
[NSCalendar.currentCalendar isDate:date2
equalToDate:NSDate.date
toUnitGranularity:NSCalendarUnitMonth]
3.9 从现在开始一个半小时后的时间
把一个日历组件添加到现有时间
-(nullable NSDate *)dateByAddingComponents:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSCalendarOptions)opts;
NSDate *today = [[NSDate alloc] init];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setHour:1];
[offsetComponents setMinute:30];
NSDate *endOfWorldWar3 = [gregorian dateByAddingComponents:offsetComponents toDate:today options:0];
3.10计算匹配(或最接近匹配)给定组件集的日期,并枚举匹配的结果
-(void)enumerateDatesStartingAfterDate:(NSDate *)start matchingComponents:(NSDateComponents *)comps options:(NSCalendarOptions)opts usingBlock:(void (NS_NOESCAPE ^)(NSDate * _Nullable date, BOOL exactMatch, BOOL *stop))block
参数 start:起始日期;
参数 comps日期组件(匹配模式)比如:闰年 2月29
参数 opts 匹配规则(严格匹配还是模糊匹配),文档中给的例子很详细
//自定义日期组件
NSDateComponents *cusDateComponents = [NSDateComponents new];
cusDateComponents.month = 2;
cusDateComponents.day = 29;
//匹配日期
[NSCalendar.currentCalendar enumerateDatesStartingAfterDate:NSDate.date matchingComponents:cusDateComponents options:NSCalendarMatchStrictly usingBlock:^(NSDate * _Nullable date, BOOL exactMatch, BOOL * _Nonnull stop) {
NSLog(@"%@",date);
if (exactMatch) {
*stop = YES;//匹配成功,修改stop的值为YES停止
}
}];
3.10给现有时间添加指定单位后得到一个新时间
比如,2020-6-5,给 天 的单位添加10 ,返回2020-6-15,也可以通过日历组件NSDateComponents实现
-(nullable NSDate *)dateByAddingUnit:(NSCalendarUnit)unit value:(NSInteger)value toDate:(NSDate *)date options:(NSCalendarOptions)options
3.1指定当前日期的某个单位的值,为NSDateComponents中对应单位的值
比如:当前时间2020-6-5,指定NSDateComponents中的 day = 10,那么返回2020-6-10
-(nullable NSDate *)nextDateAfterDate:(NSDate *)date matchingComponents:(NSDateComponents *)comps options:(NSCalendarOptions)options
直接通过日历单位改设置对应位置的值,效果和nextDateAfterDate一样
-(nullable NSDate *)dateBySettingUnit:(NSCalendarUnit)unit value:(NSInteger)v ofDate:(NSDate *)date options:(NSCalendarOptions)opts
三、`NSDateComponents 可以用来表示特定日期的组成部分,例如小时,分钟,天,年等。
1.创建一个日期组件对象,例如:2020-5-3 14:00:00
NSDateComponents *components = [[NSDateComponents alloc]init];
components.year = 2020;
components.month = 5;
components.day =3;
components.hour = 14;
2.NSDate
和NSDateComponents
之间的相互转换,需要用到NSCalendar
类中的方法
NSDateComponents转NSDate(必须确保指定组件在单位范围内,比如,设置阳历:2月30,会产生一个为定义的结果)
NSDate *date = [[NSCalendar currentCalendar] dateFromComponents:components];
NSDate转NSDateComponents
NSDate *today = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents =
[gregorian components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:today];
3.将日期组件从一个日历转换为另一个,例如:阳历转换成农历
自定义一个阳历时间:2020-6-5
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:5];
[comps setMonth:6];
[comps setYear:2020];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDate *date = [gregorian dateFromComponents:comps];
转换成农历年
NSCalendar *chineseCalender = [[NSCalendar alloc]
initWithCalendarIdentifier:NSCalendarIdentifierChinese];
NSUInteger unitFlags = NSCalendarUnitDay | NSCalendarUnitMonth |NSCalendarUnitYear;
NSDateComponents *components = [chineseCalender components:unitFlags fromDate:date];
NSLog(@"%ld-%ld-%ld",(long)[components year],(long)[components month],(long)[components day]);
查了一下农历确实是:庚子年闰四月十四( 第37年称“庚子年”)
37-4-14
四、NSDateFormatter 时间格式化指南
最常见的用法,时间字符串之间的互转
时间转字符串:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yy-MM-dd"];
NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];
NSLog(@"dateString:%@",dateString);
字符串转时间
NSDateFormatter *stringDate = [[NSDateFormatter alloc] init];
[stringDate setDateFormat:@"yyyy-MM-dd"];
NSDate *date = [stringDate dateFromString:@"2020-05-31"];
NSLog(@"date:%@",date);