NSCalendar使用

一、NSCalendar

NSCalendar可以很方便的用来表示日期,获取日期的各种信息,包括年、月、日,时分秒。可以很方便的计算两个日期之前的关系。也可以很方便的根据一个日期获取另一个日期。

NSCalendar中有一个重要的概念NSCalendarUnit,这是一个位枚举,意味着作为参数可以采用位运算的方式传参。

typedef NS_OPTIONS(NSUInteger, NSCalendarUnit) {
        // 公元前、公元后
        NSCalendarUnitEra                = kCFCalendarUnitEra,
        // 获取年、月、日
        NSCalendarUnitYear               = kCFCalendarUnitYear,
        NSCalendarUnitMonth              = kCFCalendarUnitMonth,
        NSCalendarUnitDay                = kCFCalendarUnitDay,
        // 获取时、分、秒
        NSCalendarUnitHour               = kCFCalendarUnitHour,
        NSCalendarUnitMinute             = kCFCalendarUnitMinute,
        NSCalendarUnitSecond             = kCFCalendarUnitSecond,
        // 获取周几  周日为1 、周1为2
        NSCalendarUnitWeekday            = kCFCalendarUnitWeekday,
        // 获取本周是本月的第几周,7天为1个单位
        NSCalendarUnitWeekdayOrdinal     = kCFCalendarUnitWeekdayOrdinal,
        // 获取刻钟,15分钟为1刻钟
        NSCalendarUnitQuarter            API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)) = kCFCalendarUnitQuarter,
        // 本月第几周
        NSCalendarUnitWeekOfMonth        API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0)) = kCFCalendarUnitWeekOfMonth,
        // 本年第几周
        NSCalendarUnitWeekOfYear         API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0)) = kCFCalendarUnitWeekOfYear,
        NSCalendarUnitYearForWeekOfYear  API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0)) = kCFCalendarUnitYearForWeekOfYear,
        // 纳秒
        NSCalendarUnitNanosecond         API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0)) = (1 << 15),
        NSCalendarUnitCalendar           API_AVAILABLE(macos(10.7), ios(4.0), watchos(2.0), tvos(9.0)) = (1 << 20),
        NSCalendarUnitTimeZone           API_AVAILABLE(macos(10.7), ios(4.0), watchos(2.0), tvos(9.0)) = (1 << 21),

如下所示,使用上面的位组件,可以方便的获取一个时间的年月日等信息

NSDateComponents *comps = [NSCalendar.currentCalendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:[NSDate date]];

另外一个比较重要的类是NSDateComponents,上面是通过位参数获取每个单位(年月日)的信息,返回的结构可以看到是一个NSDateComponents,如果我要表示一个日期的信息,构建日期或者进行日期的计算,就少不了NSDateComponents,它可以将日期按照单位的形式封装起来,然后通过NSCalendar的方法进行计算

  • NSDateComponents中表示日期的单位与上面的位枚举NSCalendarUnit基本类似,用的时候只需要新建并且赋值即可
  •         // 构建一个日期
            NSDateComponents *mycoms = [NSDateComponents new];
            mycoms.year = 2018;
            mycoms.month = 1;
            mycoms.day = 3;
            NSLog(@"%@", [NSCalendar.currentCalendar dateFromComponents:mycoms]);
            // 如下:在当前日期加上3天
            NSDateComponents *coms = [NSDateComponents new];
            coms.day = 3;
            NSDate *newDate = [NSCalendar.currentCalendar dateByAddingComponents:coms toDate:[NSDate date] options:0];
            NSLog(@"%@", newDate);
    

    了解NSCalendarUnit和NSDateComponents之后,再回过头看NSCalendar的初始化方法

    NSCalendar提供了4中初始化方法

    // 使用用户手机设置的日期信息,有缓存,用户手机日历改变后不会变
    @property (class, readonly, copy) NSCalendar *currentCalendar;  
    // 使用用户手机设置的日期信息,并且用户改变之后会跟着改变
    @property (class, readonly, strong) NSCalendar *autoupdatingCurrentCalendar API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); // tracks changes to user's preferred calendar identifier
    // 使用指定的标识获取日期,比如农历、佛历,常用的是格里高利历(NSCalendarIdentifierGregorian)
    + (nullable NSCalendar *)calendarWithIdentifier:(NSCalendarIdentifier)calendarIdentifierConstant API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));
    - (nullable id)initWithCalendarIdentifier:(NSCalendarIdentifier)ident NS_DESIGNATED_INITIALIZER;
    
  • NSCalendar中有一个属性firstWeekday,代表周几作为一周的开始。默认周日是一周的开始,如果设置firstWeekDay = 2,代表着周一作为一周的开始,但是设置了该值之后,并不会改变NSCalendarUnitWeekday的值,如果是周日,该值返回的还是1,并不是7。该值设置只会可以用于计算两个日期是否在同一周,比如按照之前的设置,周日、周一周六是同一周,如果设置周一是起始日,那么周一、周二周日才是同一周。同理,在计算今天一年的第几周时同样受改属性影响

  • NSCalendar可以方便的获取国际化的月份信息,比如英语一月标识为February。设置NSCalendar的NSLocale之后,使用属性monthSymbols可以获取全部的月份表示,这样做国际化处理的时候只要获取月份,然后从数组中取出对应的值即可

  • 用来表示最小或者最大的范围,比如月份最小返回1~28,最大为1~31
    - (NSRange)minimumRangeOfUnit:(NSCalendarUnit)unit;
    - (NSRange)maximumRangeOfUnit:(NSCalendarUnit)unit;
    
  • 用来表示大范围内的小范围的取值范围获取具体数值
  • // 当前时间对应的月份中有几天
    [[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:[NSDate date]].length; 
    // 当前时间对应的月份中有几周(前面说到的firstWeekday会影响到这个结果)
    [[NSCalendar currentCalendar] rangeOfUnit:NSWeekCalendarUnit inUnit:NSMonthCalendarUnit forDate:[NSDate date]].length;
    // 当前时间对应的周是当前年中的第几周
    [[NSCalendar currentCalendar] ordinalityOfUnit:NSWeekOfYearCalendarUnit inUnit:NSYearCalendarUnit forDate:self]; [[NSCalendar currentCalendar] ordinalityOfUnit:NSWeekCalendarUnit inUnit:NSYearCalendarUnit forDate:[NSDate date]]; 
    // 当前时间对应的周是当前月中的第几周
    [[NSCalendar currentCalendar] ordinalityOfUnit:NSWeekOfMonthCalendarUnit inUnit:NSYearCalendarUnit forDate:self]; [[NSCalendar currentCalendar] ordinalityOfUnit:NSWeekCalendarUnit inUnit:NSMonthCalendarUnit forDate:[NSDate date]];
    
  • 判断给定日期是否为今天、昨天、明天或者周末
  • isDateInToday
    isDateInYesterday
    isDateInTomorrow
    isDateInWeekend
    
  • 计算两个日期之间的间隔,使用NSDateComponents表示
  • - (NSDateComponents *)components:(NSCalendarUnit)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSCalendarOptions)opts;
    
  • 根据NSCalendarUnit比较两个时间
  • - (NSComparisonResult)compareDate:(NSDate *)date1 toDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit
    

    二、NSDate

    要使用NSCalendar,离不开NSDate。

    NSDate用来表示一个具体的时间,默认时区为0时区,在中国使用的是GMT+8,代表比0时区偏移8个小时。

    在iOS中获取的时间都是基于0时区的,因此在中国获取的时间会少8个小时,需要使用下面的方式追加时间差值,或者使用NSDateFormatter的时候指定时区

    // 得到当前时间(世界标准时间 UTC/GMT) 
    NSDate *date = [NSDate date]; 
    // 设置系统时区为本地时区 
    NSTimeZone *zone = [NSTimeZone systemTimeZone]; 
    // 计算本地时区与 GMT 时区的时间差 
    NSInteger interval = [zone secondsFromGMT]; 
    // 在 GMT 时间基础上追加时间差值,得到本地时间 
    date = [date dateByAddingTimeInterval:interval];
    

    三、NSTimeZone

    用来表示时区信息

    // 系统支持时区简写
    abbreviationDictionary
    

    四、NSLocale

    用来表示本地化的相关信息.
    每一个NSLocale实例对应着一个地区标识符,例如en_US,fr_FR,ja_JP和en_GB,这些标识符包含一个语言码(例如en代表英语)和一个地区码(例如US代表美国)

    @property (class, readonly, copy) NSArray<NSString *> *ISOLanguageCodes;//所有ISO定义的语言编码`