iOS日期相关的NSDate,NSCalendar,NSDateComponents,NSDateFormatter详解

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;每周最少有几天,低于这个数的不算做一周

比如:
image.png

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.NSDateNSDateComponents之间的相互转换,需要用到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);

你可能感兴趣的:(iOS日期相关的NSDate,NSCalendar,NSDateComponents,NSDateFormatter详解)