Apple开发_NSCalendar

前言

  • NSCalendar 对世界上现存的常用的历法进行了封装,既提供了不同历法的时间信息,又支持日历的计算。

    • NSCalendar -- 日历类,它提供了大部分的日期计算接口,并且允许您在NSDate和NSDateComponents之间转换
    • NSTimeZone -- 时区信息
    • NSLocale -- 本地化信息
    • NSDate -- 表示一个绝对的时间点
    • NSDateComponents -- 一个封装了具体年月日、时秒分、周、季度等的类
    • NSDateFormatter -- 用来在日期和字符串之间转换
  • firstWeekday

    • 大家在使用 dateComponents.weekday 获取某天对应的星期时,会发现,星期日对应的值为 1,星期一对应的值为 2,
    • 星期二对应的值为 3,依次递推,星期六对应的值为 7,这与我们平时理解的方式不一样。
    • 然后,我们就开始找是不是可以设置这种对应关系。终于,我们在 NSCalendar 中发现了 firstWeekday 这个变量,
    • 从字面意思上看貌似就是我们寻找的那个东西。可是,设置过 firstWeekday 后,我们又发现完全没有作用,真是郁闷啊!
    • 其实,大家不必郁闷,因为郁闷也没用,iOS 中规定的就是周日为 1,周一为 2,周二为 3,周三为 4,周四为 5,周五为 6,
    • 周六为 7,无法通过某个设置改变这个事实的,只能在使用的时候 注意一下这个规则了。那 firstWeekday 是干什么用的呢?
    • 大家设置一下 firstWeekday,再获取一下 dateComponents.weekOfYear 或 dateComponents.weekOfMonth,
    • 看看返回的数据是否发生了变化。firstWeekday 的作用确实是修改当前历法中周的起始位置,但是不能修改周日对应的数值,
    • 只能修改一年或一个月中周的数量,以及周的次序。

1、日历的创建

// 根据提供的日历标示符初始化。
/*
identifier 的范围可以是:

NSCalendarIdentifierGregorian         公历
NSCalendarIdentifierBuddhist          佛教日历
NSCalendarIdentifierChinese           中国农历
NSCalendarIdentifierHebrew            希伯来日历
NSCalendarIdentifierIslamic           伊斯兰日历
NSCalendarIdentifierIslamicCivil      伊斯兰教日历
NSCalendarIdentifierJapanese          日本日历
NSCalendarIdentifierRepublicOfChina   中华民国日历(台湾)
NSCalendarIdentifierPersian           波斯历
NSCalendarIdentifierIndian            印度日历
NSCalendarIdentifierISO8601           ISO8601
*/
NSCalendar *cal1 = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

// 返回当前客户端的逻辑日历
/*
取得的值会一直保持在 cache 中,第一次用此方法实例化对象后,即使修改了系统日历设定,这个对象也不会改变
*/
NSCalendar *cal2 = [NSCalendar currentCalendar];

// 返回当前客户端的逻辑日历
/*
当每次修改系统日历设定,其实例化的对象也会随之改变
*/
NSCalendar *cal3 = [NSCalendar autoupdatingCurrentCalendar];

2、日历的设置

NSCalendar *calendar = [NSCalendar currentCalendar];

// 设置区域
[calendar setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]];

// 设置时区
/*
设置时区,设置为 GMT+8,即北京时间(+8)
*/
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"CCT"]];
[calendar setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:+28800]];

// 设定每周的第一天从星期几开始
/*
1 代表星期日开始,2 代表星期一开始,以此类推。默认值是 1
*/
[calendar setFirstWeekday:2];

// 设置每年及每月第一周必须包含的最少天数
/*
设定第一周最少包括 3 天,则 value 传入 3
*/
[calendar setMinimumDaysInFirstWeek:3];

3、日历设置信息的获取

NSCalendar *calendar = [NSCalendar currentCalendar];

// 获取日历标示符
/*
有效的日历标示符包括:

gregorian
buddhist
chinese
hebrew
islamic
islamic-civil
japanese
roc
persian
indian
iso8601
*/
NSString *calendarIdentifier =  calendar.calendarIdentifier;

// 获取地区信息
/*
语言地区
*/
NSString *localeIdentifier = calendar.locale.localeIdentifier;
NSString *localeIdentifier2 = [calendar.locale objectForKey:NSLocaleIdentifier];

// 获取时区信息
NSTimeZone *timeZone = calendar.timeZone;

// 获取每周的第一天从星期几开始
/*
缺省为星期天
*/
NSUInteger firstWeekday = calendar.firstWeekday;

// 获取第一周必须包含的最少天数
/*
缺省为 1
*/
NSUInteger minimumDaysInFirstWeek = calendar.minimumDaysInFirstWeek;

4、日历信息的获取

  • 1)获取一个小的单位在一个大的单位里面的序数

    NSUInteger count = [calendar ordinalityOfUnit:NSCalendarUnitWeekday inUnit:NSCalendarUnitWeekOfMonth forDate:[NSDate date]];
    - (NSUInteger)ordinalityOfUnit:(NSCalendarUnit)smaller inUnit:(NSCalendarUnit)larger forDate:(NSDate *)date;
    - NSCalendarUnit包含的值有:
    - NSCalendarUnitEra                 -- 纪元单位。对于 NSGregorianCalendar (公历)来说,只有公元前(BC)和公元(AD);
    - 而对于其它历法可能有很多,例如日本和历是以每一代君王统治来做计算。
    - NSCalendarUnitYear                -- 年单位。值很大,相当于经历了多少年,未来多少年。
    - NSCalendarUnitMonth               -- 月单位。范围为1-12
    - NSCalendarUnitDay                 -- 天单位。范围为1-31
    - NSCalendarUnitHour                -- 小时单位。范围为0-24
    - NSCalendarUnitMinute              -- 分钟单位。范围为0-60
    - NSCalendarUnitSecond              -- 秒单位。范围为0-60
    - NSCalendarUnitWeekOfMonth / NSCalendarUnitWeekOfYear -- 周单位。范围为1-53
    - NSCalendarUnitWeekday             -- 星期单位,每周的7天。范围为1-7
    - NSCalendarUnitWeekdayOrdinal      -- 没完全搞清楚
    - NSCalendarUnitQuarter             -- 几刻钟,也就是15分钟。范围为1-4
    - NSCalendarUnitWeekOfMonth         -- 月包含的周数。最多为6个周
    - NSCalendarUnitWeekOfYear          -- 年包含的周数。最多为53个周
    - NSCalendarUnitYearForWeekOfYear   -- 没完全搞清楚
    - NSCalendarUnitTimeZone            -- 没完全搞清楚
    <1>、当小单位为 NSCalendarUnitWeekday,大单位为 NSCalendarUnitWeekOfMonth / NSCalendarUnitWeekOfYear 时
    (即某个日期在这一周是第几天),根据 firstWeekday 属性不同,返回的结果也不同。具体说明如下:
    - 当 firstWeekday 被指定为星期天(即 = 1)时,它返回的值与星期几对应的数值保持一致。比如:
    - fromDate 传入的参数是星期日,则函数返回 1
    - fromDate 传入的参数是星期一,则函数返回 2
    - 当 firstWeekday 被指定为其它值时(即 <> 1)时,假设firstWeekday 被指定为星期一(即 = 2),那么:
    - fromDate 传入的参数是星期一,则函数返回 1
    - fromDate 传入的参数是星期二,则函数返回 2
    - fromDate 传入的参数是星期日,则函数返回 7
    <2>、当小单位为 参数为 NSCalendarUnitWeekOfMonth / NSCalendarUnitWeekOfYear,大单位为 NSCalendarUnitYear 时
    (即某个日期在这一年中是第几周),minimumDaysInFirstWeek 属性影响它的返回值。具体说明如下:
    2005年1月
    日   一    二   三   四    五   六
    --------------------------------
    1
    2    3    4    5    6    7    8
    9    10   11   12   13   14   15
    16   17   18   19   20   21   22
    23   24   25   26   27   28   29
    30   31
    2005年1月第一周包括1号。
    a. 如果将 minimumDaysInFirstWeek 设定 = 1
    则 fromDate 传入1月1号,方法均返回1  ==> 满足 minimumDaysInFirstWeek 指定的天数(最少1天),所以方法将其归为
    2005年的第1周
    则 fromDate 传入1月2-8号,方法均返回2
    则 fromDate 传入1月9-15号,方法均返回3
    ......
    b. 如果将 minimumDaysInFirstWeek 设定为 > 1,比如2
    则 fromDate 传入1月1号,方法均返回53  ==> 不足2天,所以方法将其归为2004年的第53周
    则 fromDate 传入1月2-8号,方法均返回1
    则 fromDate 传入1月9-15号,方法均返回2
    ......
    
    2008年1月
    日   一    二   三   四    五   六
    ---------------------------------
    1    2    3    4    5
    6    7    8    9    10   11   12
    13   14   15   16   17   18   19
    20   21   22   23   24   25   26
    27   28   29   30   31
    
    2005年1月第一周包括1-5号共5天。
    a. 如果将 minimumDaysInFirstWeek 设定为 <= 5时
    则 fromDate 传入1月1-5号,方法均返回1  ==> 满足 minimumDaysInFirstWeek 指定的天数,所以方法将其归为2008年的第1周
    则 fromDate 传入1月6-12号,方法均返回2
    则 fromDate 传入1月13-19号,方法均返回3
    ......
    
    b. 如果将 minimumDaysInFirstWeek 设定为 > 5,比如6
    则 fromDate 传入1月1-5号,方法均返回53  ==> 当周不足6天,所以方法将其归为2007年的第53周
    则 fromDate 传入1月2-8号,方法均返回1
    则 fromDate 传入1月9-15号,方法均返回2
    ......
    
    - ### <3>、当小单位为 参数为 NSCalendarUnitWeekOfMonth / NSCalendarUnitWeekOfYear,大单位为 NSCalendarUnitMonth 时
    (即某个日期在这一个月中是第几周),minimumDaysInFirstWeek 属性影响它的返回值。具体说明如下:
    
    2008年4月
    日   一    二   三   四    五   六
    ---------------------------------
    1    2    3    4    5
    6    7    8    9    10   11   12
    13   14   15   16   17   18   19
    20   21   22   23   24   25   26
    27   28   29   30
    2008年4月第一周包括1、2、3、4、5号。
    a. 如果将 minimumDaysInFirstWeek 设定为小于或等于5的数
    则 fromDate 传入4月1-5号,方法均返回1
    则 fromDate 传入4月6-12号,方法均返回2
    则 fromDate 传入4月13-19号,方法均返回3
    ....
    b. 如果将 minimumDaysInFirstWeek 设定为大于5的数
    则 fromDate 传入1-5号,方法均返回0
    则 fromDate 传入6-12号,方法均返回1
    则 fromDate 传入13-19号,方法均返回2
    ....
    
  • 2)获取一个小的单位在一个大的单位里面的取值范围

    NSRange range = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:[NSDate date]];
    NSLog(@"%zi -- %zi", range.location, range.length);
    - (NSRange)rangeOfUnit:(NSCalendarUnit)smaller inUnit:(NSCalendarUnit)larger forDate:(NSDate *)date;
    
    调用这个方法要明确一点,取得的是"范围"而不是"包含",下面是一些例子:
    <1>、小单位是 NSCalendarUnitDay,大单位是 NSCalendarUnitYear,并不是要取这一年包含多少天,而是要取"天"(Day)这个单位
    在这一年(Year)的取值范围。其实不管你提供的日期是多少,返回的值都是"1--31"。
    <2>、小单位是 NSCalendarUnitDay,大单位是 NSCalendarUnitMonth。要取得参数时间点所对应的月份下,"天"(Day)的取值范围。
    根据参数时间的月份不同,值也不同。例如2月是1--28、3月是 1--31、4月是1--30。
    <3>、小单位是 NSCalendarUnitWeekOfMonth / NSCalendarUnitWeekOfYear,大单位是 NSCalendarUnitMonth。要取得参数
    时间点所对应的月份下,"周"(Week)的取值范围。需要注意的是结果会受到 minimumDaysInFirstWeek 属性的影响。在默认 
    minimumDaysInFirstWeek 情况下,取得的范围值一般是"1--5",从日历上可以看出来这个月包含5排,即5个周。
    <4>、小单位是 NSCalendarUnitDay,大单位是 NSCalendarUnitWeekOfMonth / NSCalendarUnitWeekOfYear。要取得周所包含
    的"天"(Day)的取值范围。下面是一个示例日历图:
        2013年4月
        日   一    二   三   四    五   六
        ---------------------------------
        1    2    3    4    5    6    
        7    8    9    10   11   12  13   
        14   15   16   17   18   19  20   
        21   22   23   24   25   26  27   
        28   29   30
    
        在上图的日期条件下,假如提供的参数是4月1日--4月6日,那么对应的 week 就是1(第一个周),可以看到第一个周包含有6天,
        从1号开始,那么最终得到的范围值为1--6。
        假如提供的参数是4月18日,那么对应的 week 是3(第三个周),第三个周包含有7天,从14号开始,那么最终得到的范围值是14--7。
        假如提供的参数是4月30日,那么对应的 week 是5(第五个周),第五个周只包含3天,从28号开始,那么最终得到的范围值是28--3。
    
  • 3)获取所在日历单位的开始时间及所在日历单位的总秒数

    NSDate *startDate = nil;
    NSTimeInterval intervalCount = 0;
    
    BOOL bl = [calendar rangeOfUnit:NSCalendarUnitMonth 
    startDate:&startDate 
    interval:&intervalCount 
    forDate:[NSDate date]];
    
    if (bl) {
    
        // 得到本地时间,避免时区问题
        startDate = [startDate dateByAddingTimeInterval:[[NSTimeZone systemTimeZone] secondsFromGMTForDate:startDate]];
    
        NSLog(@"%@",startDate);
        NSLog(@"%f",intervalCount);
    }
    else {
        NSLog(@"无法计算");
    }
    

0、前言

1、创建示例

2、API说明

#define NS_CALENDAR_ENUM_DEPRECATED(A, B, C, D, ...) NS_ENUM_DEPRECATED(A, B, C, D, __VA_ARGS__)
#define NS_CALENDAR_DEPRECATED(A, B, C, D, ...) NS_DEPRECATED(A, B, C, D, __VA_ARGS__)
#define NS_CALENDAR_DEPRECATED_MAC(A, B, ...) NS_DEPRECATED_MAC(A, B, __VA_ARGS__)
#define NS_CALENDAR_ENUM_DEPRECATED(A, B, C, D, ...) NS_ENUM_AVAILABLE(A, C)
#define NS_CALENDAR_DEPRECATED(A, B, C, D, ...) NS_AVAILABLE(A, C)
#define NS_CALENDAR_DEPRECATED_MAC(A, B, ...) NS_AVAILABLE_MAC(A)

// NSCalendar 日历的标识符
typedef NSString * NSCalendarIdentifier NS_TYPED_EXTENSIBLE_ENUM;

// 公历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierGregorian API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 佛教历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierBuddhist API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 农历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierChinese API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 科普特历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierCoptic API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 埃塞俄比亚历 (Amete Mihret)
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierEthiopicAmeteMihret API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 埃塞俄比亚历 (Amete Alem)
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierEthiopicAmeteAlem API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 希伯来历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierHebrew API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// ISO 8601
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierISO8601 API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 印度历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierIndian API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 伊斯兰历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierIslamic API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 伊斯兰民事历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierIslamicCivil API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 日本历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierJapanese API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 波斯历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierPersian API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 中华民国历
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierRepublicOfChina API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

// 伊斯兰历 (Tabular)
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierIslamicTabular API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));

// 伊斯兰历 (Umm al-Qura)
FOUNDATION_EXPORT NSCalendarIdentifier const NSCalendarIdentifierIslamicUmmAlQura API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));

// 日历单元
typedef NS_OPTIONS(NSUInteger, NSCalendarUnit) {
    // 纪元
    NSCalendarUnitEra = kCFCalendarUnitEra,
    // 年
    NSCalendarUnitYear = kCFCalendarUnitYear,
    // 月
    NSCalendarUnitMonth = kCFCalendarUnitMonth,
    // 日
    NSCalendarUnitDay = kCFCalendarUnitDay,
    // 小时
    NSCalendarUnitHour = kCFCalendarUnitHour,
    // 分钟
    NSCalendarUnitMinute = kCFCalendarUnitMinute,
    // 秒
    NSCalendarUnitSecond = kCFCalendarUnitSecond,
    // 星期几
    NSCalendarUnitWeekday = kCFCalendarUnitWeekday,
    // 每月第几周
    NSCalendarUnitWeekdayOrdinal = kCFCalendarUnitWeekdayOrdinal,
    // 季度
    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),
    // 纪元,已废弃
    NSEraCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitEra", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitEra,
    // 年,已废弃
    NSYearCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitYear", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitYear,
    // 月,已废弃
    NSMonthCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitMonth", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitMonth,
    // 日,已废弃
    NSDayCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitDay", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitDay,
    // 小时,已废弃
    NSHourCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitHour", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitHour,
    // 分钟,已废弃
    NSMinuteCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitMinute", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitMinute,
    // 秒,已废弃
    NSSecondCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitSecond", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitSecond,
    // 星期,已废弃
    NSWeekCalendarUnit API_DEPRECATED("NSCalendarUnitWeekOfMonth or NSCalendarUnitWeekOfYear, depending on which you mean", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = kCFCalendarUnitWeek,
    // 星期几,已废弃
    NSWeekdayCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitWeekday", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitWeekday,
    // 星期几的顺序,已废弃
    NSWeekdayOrdinalCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitWeekdayOrdinal", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitWeekdayOrdinal,
    // 季度,已废弃
    NSQuarterCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitQuarter", macos(10.6, 10.10), ios(4.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitQuarter,
    // 每月第几周,已废弃
    NSWeekOfMonthCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitWeekOfMonth", macos(10.7, 10.10), ios(5.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitWeekOfMonth,
    // 每年第几周,已废弃
    NSWeekOfYearCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitWeekOfYear", macos(10.7, 10.10), ios(5.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitWeekOfYear,
    // 年度中的第几周,已废弃
    NSYearForWeekOfYearCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitYearForWeekOfYear", macos(10.7, 10.10), ios(5.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitYearForWeekOfYear,
    // 日历,已废弃
    NSCalendarCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitCalendar", macos(10.7, 10.10), ios(4.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitCalendar,
    // 时区,已废弃
    NSTimeZoneCalendarUnit API_DEPRECATED_WITH_REPLACEMENT("NSCalendarUnitTimeZone", macos(10.7, 10.10), ios(4.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarUnitTimeZone,
};

// 日历选项
typedef NS_OPTIONS(NSUInteger, NSCalendarOptions) {
    // 如果日期组件超出了有效范围,则将其包装回范围内。
    NSCalendarWrapComponents = (1UL << 0),
    // 严格匹配日期组件,如果不能完全匹配则返回nil。
    NSCalendarMatchStrictly API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)) = (1ULL << 1),
    // 向后搜索日期组件。
    NSCalendarSearchBackwards API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)) = (1ULL << 2),
    // 匹配前一个时间并保留较小的单位。
    NSCalendarMatchPreviousTimePreservingSmallerUnits API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)) = (1ULL << 8),
    // 匹配后一个时间并保留较小的单位。
    NSCalendarMatchNextTimePreservingSmallerUnits API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)) = (1ULL << 9),
    // 匹配后一个时间。
    NSCalendarMatchNextTime API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)) = (1ULL << 10),
    // 匹配第一个时间。
    NSCalendarMatchFirst API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)) = (1ULL << 12),
    // 匹配最后一个时间。
    NSCalendarMatchLast API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)) = (1ULL << 13)
};

// 历法选项(已弃用)
enum {
    // 如果日期组件超出了有效范围,则将其包装回范围内。
    NSWrapCalendarComponents API_DEPRECATED_WITH_REPLACEMENT("NSCalendarWrapComponents", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSCalendarWrapComponents,
};

@interface NSCalendar : NSObject <NSCopying, NSSecureCoding>

/**
 * @brief 根据标识符创建日历对象
 *
 * @param calendarIdentifierConstant    日历标识符
 *
 * @return NSCalendar对象,如果标识符无效则返回nil
 *
 * @discussion 该方法用于创建一个指定标识符的NSCalendar对象,可以用于处理日期和时间相关的计算和比较。
 * 例如,创建一个公历的NSCalendar对象可以使用标识符NSCalendarIdentifierGregorian。
 */
+ (nullable NSCalendar *)calendarWithIdentifier:(NSCalendarIdentifier)calendarIdentifierConstant API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 初始化方法,不可用
 */
- (instancetype)init API_UNAVAILABLE(macos, ios, watchos, tvos);

/**
 * @brief 根据标识符初始化日历对象
 *
 * @param ident    日历标识符
 *
 * @return NSCalendar对象
 *
 * @discussion 该方法用于创建一个指定标识符的NSCalendar对象,可以用于处理日期和时间相关的计算和比较。
 * 例如,创建一个公历的NSCalendar对象可以使用标识符NSCalendarIdentifierGregorian。
 */
- (nullable id)initWithCalendarIdentifier:(NSCalendarIdentifier)ident NS_DESIGNATED_INITIALIZER;

/**
 * @brief 获取指定单位的最小范围
 *
 * @param unit    日历单位
 *
 * @return 最小范围
 *
 * @discussion 该方法用于获取指定日历单位的最小范围,例如,获取月份的最小范围可以使用NSCalendarUnitMonth。
 */
- (NSRange)minimumRangeOfUnit:(NSCalendarUnit)unit;

/**
 * @brief 获取指定单位的最大范围
 *
 * @param unit    日历单位
 *
 * @return 最大范围
 *
 * @discussion 该方法用于获取指定日历单位的最大范围,例如,获取月份的最大范围可以使用NSCalendarUnitMonth。
 */
- (NSRange)maximumRangeOfUnit:(NSCalendarUnit)unit;

/**
 * @brief 获取指定日期所在单位的范围
 *
 * @param smaller    小单位
 * @param larger     大单位
 * @param date       指定日期
 *
 * @return 范围
 *
 * @discussion 该方法用于获取指定日期所在单位的范围,例如,获取指定日期所在月份的范围可以使用NSCalendarUnitMonth作为小单位,
 * NSCalendarUnitYear作为大单位,指定日期作为date参数。
 */
- (NSRange)rangeOfUnit:(NSCalendarUnit)smaller inUnit:(NSCalendarUnit)larger forDate:(NSDate *)date;

/**
 * @brief 获取指定日期所在单位内的序数
 *
 * @param smaller    小单位
 * @param larger     大单位
 * @param date       指定日期
 *
 * @return 序数
 *
 * @discussion 该方法用于获取指定日期所在单位内的序数,例如,获取指定日期在该月份中的序数可以使用NSCalendarUnitDay作为小单位,
 * NSCalendarUnitMonth作为大单位,指定日期作为date参数。
 */
- (NSUInteger)ordinalityOfUnit:(NSCalendarUnit)smaller inUnit:(NSCalendarUnit)larger forDate:(NSDate *)date;

/**
 * @brief 获取指定日期所在单位的范围和间隔
 *
 * @param unit       日历单位
 * @param datep      指定日期指针
 * @param tip        时间间隔指针
 * @param date       指定日期
 *
 * @return 是否成功获取
 *
 * @discussion 该方法用于获取指定日期所在单位的范围和间隔,例如,获取指定日期所在月份的范围和间隔可以使用NSCalendarUnitMonth作为单位,
 * 指定日期作为date参数,范围和间隔会通过datep和tip参数返回。
 */
- (BOOL)rangeOfUnit:(NSCalendarUnit)unit startDate:(NSDate * _Nullable * _Nullable)datep interval:(nullable NSTimeInterval *)tip forDate:(NSDate *)date API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

/**
 * @brief 根据日期组件获取日期对象
 *
 * @param comps    日期组件
 *
 * @return 日期对象
 *
 * @discussion 该方法用于根据日期组件获取日期对象,例如,获取2022年10月1日10时20分的日期对象可以使用如下代码:
 * NSDateComponents *comps = [[NSDateComponents alloc] init];
 * [comps setYear:2022];
 * [comps setMonth:10];
 * [comps setDay:1];
 * [comps setHour:10];
 * [comps setMinute:20];
 * NSDate *date = [calendar dateFromComponents:comps];
 */
- (nullable NSDate *)dateFromComponents:(NSDateComponents *)comps;

/**
 * @brief 根据日期获取日期组件
 *
 * @param unitFlags    日历单位
 * @param date         日期对象
 *
 * @return 日期组件
 *
 * @discussion 该方法用于根据日期获取日期组件,例如,获取2022年10月1日10时20分的日期组件可以使用如下代码:
 * NSDateComponents *comps = [calendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute fromDate:date];
 */
- (NSDateComponents *)components:(NSCalendarUnit)unitFlags fromDate:(NSDate *)date;

/**
 * @brief 根据日期组件和间隔获取日期对象
 *
 * @param comps    日期组件
 * @param date     日期对象
 * @param opts     日历选项
 *
 * @return 日期对象
 *
 * @discussion 该方法用于根据日期组件和间隔获取日期对象,例如,获取2022年10月1日10时20分之后5天的日期对象可以使用如下代码:
 * NSDateComponents *comps = [[NSDateComponents alloc] init];
 * [comps setDay:5];
 * NSDate *newDate = [calendar dateByAddingComponents:comps toDate:date options:0];
 */
- (nullable NSDate *)dateByAddingComponents:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSCalendarOptions)opts;

/**
 * @brief 根据起始日期和终止日期获取日期组件
 *
 * @param unitFlags       日历单位
 * @param startingDate    起始日期
 * @param resultDate      终止日期
 * @param opts            日历选项
 *
 * @return 日期组件
 *
 * @discussion 该方法用于根据起始日期和终止日期获取日期组件,例如,获取2022年10月1日到2022年11月1日之间的日期组件可以使用如下代码:
 * NSDateComponents *comps = [calendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:startingDate toDate:resultDate options:0];
 */
- (NSDateComponents *)components:(NSCalendarUnit)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSCalendarOptions)opts;

/**
 * @brief 获取指定日期的纪元、年、月、日
 *
 * @param eraValuePointer     纪元指针
 * @param yearValuePointer    年份指针
 * @param monthValuePointer   月份指针
 * @param dayValuePointer     天数指针
 * @param date                指定日期
 *
 * @discussion 该方法用于获取指定日期的纪元、年、月、日,例如,获取2022年10月1日的纪元、年、月、日可以使用如下代码:
 * NSInteger era, year, month, day;
 * [calendar getEra:&era year:&year month:&month day:&day fromDate:date];
 */
- (void)getEra:(out nullable NSInteger *)eraValuePointer year:(out nullable NSInteger *)yearValuePointer month:(out nullable NSInteger *)monthValuePointer day:(out nullable NSInteger *)dayValuePointer fromDate:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 获取指定日期的纪元、周年、周数、星期几
 *
 * @param eraValuePointer       纪元指针
 * @param yearValuePointer      周年指针
 * @param weekValuePointer      周数指针
 * @param weekdayValuePointer   星期几指针
 * @param date                  指定日期
 *
 * @discussion 该方法用于获取指定日期的纪元、周年、周数、星期几,例如,获取2022年第40周的星期一的纪元、周年、周数、星期几可以使用如下代码:
 * NSDateComponents *comps = [[NSDateComponents alloc] init];
 * [comps setYear:2022];
 * [comps setWeekOfYear:40];
 * [comps setWeekday:2];
 * NSDate *date = [calendar dateFromComponents:comps];
 * NSInteger era, year, week, weekday;
 * [calendar getEra:&era yearForWeekOfYear:&year weekOfYear:&week weekday:&weekday fromDate:date];
 */
- (void)getEra:(out nullable NSInteger *)eraValuePointer yearForWeekOfYear:(out nullable NSInteger *)yearValuePointer weekOfYear:(out nullable NSInteger *)weekValuePointer weekday:(out nullable NSInteger *)weekdayValuePointer fromDate:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 从指定日期获取时分秒和纳秒值
 *
 * @param hourValuePointer     小时值的指针
 * @param minuteValuePointer   分钟值的指针
 * @param secondValuePointer   秒值的指针
 * @param nanosecondValuePointer 纳秒值的指针
 * @param date                 指定日期
 *
 * @discussion 此方法可以用于获取指定日期的时分秒和纳秒值,返回值为void,通过传入的指针参数返回具体的值。
 *
 * 示例:
 *    NSDate *date = [NSDate date];
 *    NSInteger hour, minute, second, nanosecond;
 *    [[NSCalendar currentCalendar] getHour:&hour minute:&minute second:&second nanosecond:&nanosecond fromDate:date];
 */
- (void)getHour:(out nullable NSInteger *)hourValuePointer minute:(out nullable NSInteger *)minuteValuePointer second:(out nullable NSInteger *)secondValuePointer nanosecond:(out nullable NSInteger *)nanosecondValuePointer fromDate:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 获取指定日期中指定单位的值
 *
 * @param unit 指定的单位
 * @param date 指定的日期
 *
 * @return 返回指定日期中指定单位的值
 *
 * @discussion 此方法可以用于获取指定日期中指定单位的值,例如获取年份、月份、日等。返回值为NSInteger类型。
 *
 * 示例:
 *    NSDate *date = [NSDate date];
 *    NSInteger year = [[NSCalendar currentCalendar] component:NSCalendarUnitYear fromDate:date];
 */
- (NSInteger)component:(NSCalendarUnit)unit fromDate:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 根据指定的年、月、日、时、分、秒和纳秒值获取日期
 *
 * @param eraValue         年代值
 * @param yearValue        年份值
 * @param monthValue       月份值
 * @param dayValue         日值
 * @param hourValue        小时值
 * @param minuteValue      分钟值
 * @param secondValue      秒值
 * @param nanosecondValue  纳秒值
 *
 * @return 返回根据指定的年、月、日、时、分、秒和纳秒值生成的日期
 *
 * @discussion 此方法可以用于根据指定的年、月、日、时、分、秒和纳秒值生成日期,返回值为NSDate类型。
 *
 * 示例:
 *    NSDate *date = [[NSCalendar currentCalendar] dateWithEra:1 year:2021 month:5 day:20 hour:15 minute:30 second:0 nanosecond:0];
 */
- (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 API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 根据指定的年代、周数、星期数、时、分、秒和纳秒值获取日期
 *
 * @param eraValue         年代值
 * @param yearValue        指定年份中的周数
 * @param weekValue        指定年份中的星期数
 * @param weekdayValue     指定星期中的天数
 * @param hourValue        小时值
 * @param minuteValue      分钟值
 * @param secondValue      秒值
 * @param nanosecondValue  纳秒值
 *
 * @return 返回根据指定的年代、周数、星期数、时、分、秒和纳秒值生成的日期
 *
 * @discussion 此方法可以用于根据指定的年代、周数、星期数、时、分、秒和纳秒值生成日期,返回值为NSDate类型。
 *
 * 示例:
 *    NSDate *date = [[NSCalendar currentCalendar] dateWithEra:1 yearForWeekOfYear:2021 weekOfYear:20 weekday:4 hour:15 minute:30 second:0 nanosecond:0];
 */
- (nullable NSDate *)dateWithEra:(NSInteger)eraValue yearForWeekOfYear:(NSInteger)yearValue weekOfYear:(NSInteger)weekValue weekday:(NSInteger)weekdayValue hour:(NSInteger)hourValue minute:(NSInteger)minuteValue second:(NSInteger)secondValue nanosecond:(NSInteger)nanosecondValue API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 获取指定日期的起始时间
 *
 * @param date 指定日期
 *
 * @return 返回指定日期的起始时间
 *
 * @discussion 此方法可以用于获取指定日期的起始时间,即将时、分、秒和纳秒值设置为0。返回值为NSDate类型。
 *
 * 示例:
 *    NSDate *date = [NSDate date];
 *    NSDate *startDate = [[NSCalendar currentCalendar] startOfDayForDate:date];
 */
- (NSDate *)startOfDayForDate:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 获取指定日期在指定时区下的日期组件
 *
 * @param timezone 指定时区
 * @param date     指定日期
 *
 * @return 返回指定日期在指定时区下的日期组件
 *
 * @discussion 此方法可以用于获取指定日期在指定时区下的日期组件,例如获取年份、月份、日等。返回值为NSDateComponents类型。
 *
 * 示例:
 *    NSDate *date = [NSDate date];
 *    NSDateComponents *components = [[NSCalendar currentCalendar] componentsInTimeZone:[NSTimeZone systemTimeZone] fromDate:date];
 */
- (NSDateComponents *)componentsInTimeZone:(NSTimeZone *)timezone fromDate:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 比较两个日期在指定精度下的大小
 *
 * @param date1            第一个日期
 * @param date2            第二个日期
 * @param unit             比较的精度
 *
 * @return 返回比较结果,NSOrderedAscending表示date1小于date2,NSOrderedDescending表示date1大于date2,NSOrderedSame表示相等
 *
 * @discussion 此方法可以用于比较两个日期在指定精度下的大小,例如比较年份、月份、日等。返回值为NSComparisonResult类型。
 *
 * 示例:
 *    NSDate *date1 = [NSDate dateWithTimeIntervalSince1970:0];
 *    NSDate *date2 = [NSDate date];
 *    NSComparisonResult result = [[NSCalendar currentCalendar] compareDate:date1 toDate:date2 toUnitGranularity:NSCalendarUnitYear];
 */
- (NSComparisonResult)compareDate:(NSDate *)date1 toDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 比较两个日期在指定精度下是否相等
 *
 * @param date1            第一个日期
 * @param date2            第二个日期
 * @param unit             比较的精度
 *
 * @return 如果两个日期在指定精度下相等,返回YES,否则返回NO
 *
 * @discussion 此方法可以用于比较两个日期在指定精度下是否相等,例如比较年份、月份、日等。返回值为BOOL类型。
 *
 * 示例:
 *    NSDate *date1 = [NSDate dateWithTimeIntervalSince1970:0];
 *    NSDate *date2 = [NSDate date];
 *    BOOL result = [[NSCalendar currentCalendar] isDate:date1 equalToDate:date2 toUnitGranularity:NSCalendarUnitYear];
 */
- (BOOL)isDate:(NSDate *)date1 equalToDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 判断两个日期是否在同一天
 *
 * @param date1            第一个日期
 * @param date2            第二个日期
 *
 * @return 如果两个日期在同一天,返回YES,否则返回NO
 *
 * @discussion 此方法可以用于判断两个日期是否在同一天。返回值为BOOL类型。
 *
 * 示例:
 *    NSDate *date1 = [NSDate dateWithTimeIntervalSince1970:0];
 *    NSDate *date2 = [NSDate dateWithTimeIntervalSince1970:86400];
 *    BOOL result = [[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2];
 */
- (BOOL)isDate:(NSDate *)date1 inSameDayAsDate:(NSDate *)date2 API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 判断指定日期是否在今天
 *
 * @param date 指定日期
 *
 * @return 如果指定日期在今天,返回YES,否则返回NO
 *
 * @discussion 此方法可以用于判断指定日期是否在今天。返回值为BOOL类型。
 *
 * 示例:
 *    NSDate *date = [NSDate date];
 *    BOOL result = [[NSCalendar currentCalendar] isDateInToday:date];
 */
- (BOOL)isDateInToday:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 判断指定日期是否在昨天
 *
 * @param date 指定日期
 *
 * @return 如果指定日期在昨天,返回YES,否则返回NO
 *
 * @discussion 此方法可以用于判断指定日期是否在昨天。返回值为BOOL类型。
 *
 * 示例:
 *    NSDate *date = [NSDate dateWithTimeIntervalSinceNow:-86400];
 *    BOOL result = [[NSCalendar currentCalendar] isDateInYesterday:date];
 */
- (BOOL)isDateInYesterday:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 判断指定日期是否在明天
 *
 * @param date 指定日期
 *
 * @return 如果指定日期在明天,返回YES,否则返回NO
 *
 * @discussion 此方法可以用于判断指定日期是否在明天。返回值为BOOL类型。
 *
 * 示例:
 *    NSDate *date = [NSDate dateWithTimeIntervalSinceNow:86400];
 *    BOOL result = [[NSCalendar currentCalendar] isDateInTomorrow:date];
 */
- (BOOL)isDateInTomorrow:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 判断指定日期是否在周末
 *
 * @param date 指定日期
 *
 * @return 如果指定日期在周末,返回YES,否则返回NO
 *
 * @discussion 此方法可以用于判断指定日期是否在周末。返回值为BOOL类型。
 *
 * 示例:
 *    NSDate *date = [NSDate date];
 *    BOOL result = [[NSCalendar currentCalendar] isDateInWeekend:date];
 */
- (BOOL)isDateInWeekend:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 获取某个日期所在周末的起始日期和持续时间
 *
 * @param datep          输出参数,周末起始日期
 * @param tip            输出参数,周末持续时间
 * @param date           输入参数,待查询日期
 *
 * @return               返回查询结果,YES表示查询成功,NO表示查询失败
 *
 * @discussion           该方法用于获取某个日期所在的周末的起始日期和持续时间。例如,查询2021年8月21日所在周末的起始日期和持续时间,可以这样调用:
 *                       NSDate *date = [NSDate dateWithTimeIntervalSince1970:1629504000];
 *                       NSDate *startDate = nil;
 *                       NSTimeInterval interval = 0;
 *                       BOOL result = [[NSCalendar currentCalendar] rangeOfWeekendStartDate:&startDate interval:&interval containingDate:date];
 *                       if (result) {
 *                           NSLog(@"%@ 所在周末起始日期:%@,持续时间:%f秒", date, startDate, interval);
 *                       } else {
 *                           NSLog(@"查询失败");
 *                       }
 */
- (BOOL)rangeOfWeekendStartDate:(out NSDate * _Nullable * _Nullable)datep interval:(out nullable NSTimeInterval *)tip containingDate:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 获取某个日期之后的下一个周末的起始日期和持续时间
 *
 * @param datep          输出参数,周末起始日期
 * @param tip            输出参数,周末持续时间
 * @param options        查询选项
 * @param date           输入参数,待查询日期
 *
 * @return               返回查询结果,YES表示查询成功,NO表示查询失败
 *
 * @discussion           该方法用于获取某个日期之后的下一个周末的起始日期和持续时间。例如,查询2021年8月21日之后的下一个周末的起始日期和持续时间,可以这样调用:
 *                       NSDate *date = [NSDate dateWithTimeIntervalSince1970:1629504000];
 *                       NSDate *startDate = nil;
 *                       NSTimeInterval interval = 0;
 *                       BOOL result = [[NSCalendar currentCalendar] nextWeekendStartDate:&startDate interval:&interval options:NSCalendarMatchNextTime afterDate:date];
 *                       if (result) {
 *                           NSLog(@"%@ 之后的下一个周末起始日期:%@,持续时间:%f秒", date, startDate, interval);
 *                       } else {
 *                           NSLog(@"查询失败");
 *                       }
 */
- (BOOL)nextWeekendStartDate:(out NSDate * _Nullable * _Nullable)datep interval:(out nullable NSTimeInterval *)tip options:(NSCalendarOptions)options afterDate:(NSDate *)date API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 计算两个日期组件之间的差值
 *
 * @param unitFlags      计算单位
 * @param startingDateComp 起始日期组件
 * @param resultDateComp   结束日期组件
 * @param options        计算选项
 *
 * @return               返回日期组件差值
 *
 * @discussion           该方法用于计算两个日期组件之间的差值。例如,计算2021年8月21日和2021年8月23日之间的天数差,可以这样调用:
 *                       NSDateComponents *startingDateComp = [[NSDateComponents alloc] init];
 *                       startingDateComp.year = 2021;
 *                       startingDateComp.month = 8;
 *                       startingDateComp.day = 21;
 *                       NSDateComponents *resultDateComp = [[NSDateComponents alloc] init];
 *                       resultDateComp.year = 2021;
 *                       resultDateComp.month = 8;
 *                       resultDateComp.day = 23;
 *                       NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay fromDateComponents:startingDateComp toDateComponents:resultDateComp options:0];
 *                       NSLog(@"2021年8月21日和2021年8月23日之间的天数差为:%ld", components.day);
 */
- (NSDateComponents *)components:(NSCalendarUnit)unitFlags fromDateComponents:(NSDateComponents *)startingDateComp toDateComponents:(NSDateComponents *)resultDateComp options:(NSCalendarOptions)options API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 在某个日期上增加指定时间单位的值
 *
 * @param unit           时间单位
 * @param value          增加的值
 * @param date           待修改日期
 * @param options        修改选项
 *
 * @return               返回修改后的日期
 *
 * @discussion           该方法用于在某个日期上增加指定时间单位的值。例如,将2021年8月21日增加3天,可以这样调用:
 *                       NSDate *date = [NSDate dateWithTimeIntervalSince1970:1629504000];
 *                       NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingUnit:NSCalendarUnitDay value:3 toDate:date options:0];
 *                       NSLog(@"%@ 增加3天后的日期为:%@", date, newDate);
 */
- (nullable NSDate *)dateByAddingUnit:(NSCalendarUnit)unit value:(NSInteger)value toDate:(NSDate *)date options:(NSCalendarOptions)options API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 枚举某个日期之后符合指定日期组件的所有日期
 *
 * @param start          枚举起始日期
 * @param comps          符合条件的日期组件
 * @param opts           枚举选项
 * @param block          枚举回调
 *
 * @discussion           该方法用于枚举某个日期之后符合指定日期组件的所有日期。例如,枚举2021年8月21日之后所有的周六,可以这样调用:
 *                       NSDate *start = [NSDate dateWithTimeIntervalSince1970:1629504000];
 *                       NSDateComponents *comps = [[NSDateComponents alloc] init];
 *                       comps.weekday = 7;
 *                       [[NSCalendar currentCalendar] enumerateDatesStartingAfterDate:start matchingComponents:comps options:NSCalendarMatchNextTime usingBlock:^(NSDate * _Nullable date, BOOL exactMatch, BOOL * _Nonnull stop) {
 *                           if (date) {
 *                               NSLog(@"%@ 是一个周六", date);
 *                           } else {
 *                               NSLog(@"枚举结束");
 *                               *stop = YES;
 *                           }
 *                       }];
 */
- (void)enumerateDatesStartingAfterDate:(NSDate *)start matchingComponents:(NSDateComponents *)comps options:(NSCalendarOptions)opts usingBlock:(void (NS_NOESCAPE ^)(NSDate * _Nullable date, BOOL exactMatch, BOOL *stop))block API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 获取某个日期之后符合指定日期组件的下一个日期
 *
 * @param date           待查询日期
 * @param comps          符合条件的日期组件
 * @param options        查询选项
 *
 * @return               返回查询结果,符合条件的下一个日期
 *
 * @discussion           该方法用于获取某个日期之后符合指定日期组件的下一个日期。例如,查询2021年8月21日之后的下一个周六,可以这样调用:
 *                       NSDate *date = [NSDate dateWithTimeIntervalSince1970:1629504000];
 *                       NSDateComponents *comps = [[NSDateComponents alloc] init];
 *                       comps.weekday = 7;
 *                       NSDate *nextDate = [[NSCalendar currentCalendar] nextDateAfterDate:date matchingComponents:comps options:NSCalendarMatchNextTime];
 *                       NSLog(@"%@ 之后的下一个周六是:%@", date, nextDate);
 */
- (nullable NSDate *)nextDateAfterDate:(NSDate *)date matchingComponents:(NSDateComponents *)comps options:(NSCalendarOptions)options API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 获取某个日期之后指定时间单位值的日期
 *
 * @param date           待查询日期
 * @param unit           时间单位
 * @param value          增加的值
 * @param options        查询选项
 *
 * @return               返回查询结果,某个日期之后指定时间单位值的日期
 *
 * @discussion           该方法用于获取某个日期之后指定时间单位值的日期。例如,查询2021年8月21日之后3天的日期,可以这样调用:
 *                       NSDate *date = [NSDate dateWithTimeIntervalSince1970:1629504000];
 *                       NSDate *nextDate = [[NSCalendar currentCalendar] nextDateAfterDate:date matchingUnit:NSCalendarUnitDay value:3 options:NSCalendarMatchNextTime];
 *                       NSLog(@"%@ 之后3天的日期是:%@", date, nextDate);
 */
- (nullable NSDate *)nextDateAfterDate:(NSDate *)date matchingUnit:(NSCalendarUnit)unit value:(NSInteger)value options:(NSCalendarOptions)options API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 获取某个日期之后指定时间的日期
 *
 * @param date           待查询日期
 * @param hourValue      小时值
 * @param minuteValue    分钟值
 * @param secondValue    秒值
 * @param options        查询选项
 *
 * @return               返回查询结果,某个日期之后指定时间的日期
 *
 * @discussion           该方法用于获取某个日期之后指定时间的日期。例如,查询2021年8月21日之后10点30分的日期,可以这样调用:
 *                       NSDate *date = [NSDate dateWithTimeIntervalSince1970:1629504000];
 *                       NSDate *nextDate = [[NSCalendar currentCalendar] nextDateAfterDate:date matchingHour:10 minute:30 second:0 options:NSCalendarMatchNextTime];
 *                       NSLog(@"%@ 之后10点30分的日期是:%@", date, nextDate);
 */
- (nullable NSDate *)nextDateAfterDate:(NSDate *)date matchingHour:(NSInteger)hourValue minute:(NSInteger)minuteValue second:(NSInteger)secondValue options:(NSCalendarOptions)options API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 修改某个日期的指定时间单位的值
 *
 * @param unit           时间单位
 * @param v              修改后的值
 * @param date           待修改日期
 * @param opts           修改选项
 *
 * @return               返回修改后的日期
 *
 * @discussion           该方法用于修改某个日期的指定时间单位的值。例如,将2021年8月21日的月份修改为9月,可以这样调用:
 *                       NSDate *date = [NSDate dateWithTimeIntervalSince1970:1629504000];
 *                       NSDate *newDate = [[NSCalendar currentCalendar] dateBySettingUnit:NSCalendarUnitMonth value:9 ofDate:date options:0];
 *                       NSLog(@"%@ 修改后的日期为:%@", date, newDate);
 */
- (nullable NSDate *)dateBySettingUnit:(NSCalendarUnit)unit value:(NSInteger)v ofDate:(NSDate *)date options:(NSCalendarOptions)opts API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 修改某个日期的小时、分钟、秒值
 *
 * @param h              小时值
 * @param m              分钟值
 * @param s              秒值
 * @param date           待修改日期
 * @param opts           修改选项
 *
 * @return               返回修改后的日期
 *
 * @discussion           该方法用于修改某个日期的小时、分钟、秒值。例如,将2021年8月21日的时间修改为10点30分,可以这样调用:
 *                       NSDate *date = [NSDate dateWithTimeIntervalSince1970:1629504000];
 *                       NSDate *newDate = [[NSCalendar currentCalendar] dateBySettingHour:10 minute:30 second:0 ofDate:date options:0];
 *                       NSLog(@"%@ 修改后的日期为:%@", date, newDate);
 */
- (nullable NSDate *)dateBySettingHour:(NSInteger)h minute:(NSInteger)m second:(NSInteger)s ofDate:(NSDate *)date options:(NSCalendarOptions)opts API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 判断某个日期是否符合指定日期组件
 *
 * @param date           待判断日期
 * @param components     指定日期组件
 *
 * @return               返回判断结果,YES表示符合指定日期组件,NO表示不符合
 *
 * @discussion           该方法用于判断某个日期是否符合指定日期组件。例如,判断2021年8月21日是否是周六,可以这样调用:
 *                       NSDate *date = [NSDate dateWithTimeIntervalSince1970:1629504000];
 *                       NSDateComponents *comps = [[NSDateComponents alloc] init];
 *                       comps.weekday = 7;
 *                       BOOL result = [[NSCalendar currentCalendar] date:date matchesComponents:comps];
 *                       if (result) {
 *                           NSLog(@"%@ 是周六", date);
 *                       } else {
 *                           NSLog(@"%@ 不是周六", date);
 *                       }
 */
- (BOOL)date:(NSDate *)date matchesComponents:(NSDateComponents *)components API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/** 当前的日历对象 */
@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));
/** 日历标识符 */
@property(readonly, copy) NSCalendarIdentifier calendarIdentifier;
/** 区域设置 */
@property(nullable, copy) NSLocale *locale;
/** 时区 */
@property(copy) NSTimeZone *timeZone;
/** 每周的第一天 */
@property NSUInteger firstWeekday;
/** 第一周最少天数 */
@property NSUInteger minimumDaysInFirstWeek;
/** 纪元符号 */
@property(readonly, copy) NSArray<NSString *> *eraSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 长纪元符号 */
@property(readonly, copy) NSArray<NSString *> *longEraSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 月份符号 */
@property(readonly, copy) NSArray<NSString *> *monthSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 短月份符号 */
@property(readonly, copy) NSArray<NSString *> *shortMonthSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 非常短月份符号 */
@property(readonly, copy) NSArray<NSString *> *veryShortMonthSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 独立月份符号 */
@property(readonly, copy) NSArray<NSString *> *standaloneMonthSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 独立短月份符号 */
@property(readonly, copy) NSArray<NSString *> *shortStandaloneMonthSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 独立非常短月份符号 */
@property(readonly, copy) NSArray<NSString *> *veryShortStandaloneMonthSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 周日到周六的完整名称 */
@property(readonly, copy) NSArray<NSString *> *weekdaySymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 周日到周六的短名称 */
@property(readonly, copy) NSArray<NSString *> *shortWeekdaySymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 周日到周六的极短名称 */
@property(readonly, copy) NSArray<NSString *> *veryShortWeekdaySymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 周日到周六的完整名称(独立显示) */
@property(readonly, copy) NSArray<NSString *> *standaloneWeekdaySymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 周日到周六的短名称(独立显示) */
@property(readonly, copy) NSArray<NSString *> *shortStandaloneWeekdaySymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 周日到周六的极短名称(独立显示) */
@property(readonly, copy) NSArray<NSString *> *veryShortStandaloneWeekdaySymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 季度名称 */
@property(readonly, copy) NSArray<NSString *> *quarterSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 季度短名称 */
@property(readonly, copy) NSArray<NSString *> *shortQuarterSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 季度名称(独立显示) */
@property(readonly, copy) NSArray<NSString *> *standaloneQuarterSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 季度短名称(独立显示) */
@property(readonly, copy) NSArray<NSString *> *shortStandaloneQuarterSymbols API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 上午标识符 */
@property(readonly, copy) NSString *AMSymbol API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 下午标识符 */
@property(readonly, copy) NSString *PMSymbol API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));

@end

// NSCalendar日期变化通知
FOUNDATION_EXPORT NSNotificationName const NSCalendarDayChangedNotification API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));


NS_ENUM(NSInteger) {
    // 日期组件未定义
    NSDateComponentUndefined = NSIntegerMax,
    // 已弃用,使用NSDateComponentUndefined代替
    NSUndefinedDateComponent API_DEPRECATED_WITH_REPLACEMENT("NSDateComponentUndefined", macos(10.4, 10.10), ios(2.0, 8.0), watchos(2.0, 2.0), tvos(9.0, 9.0)) = NSDateComponentUndefined
};

@interface NSDateComponents : NSObject <NSCopying, NSSecureCoding>

/**
 * @brief 获取日期组件中的周数
 *
 * @return 返回日期组件中的周数
 *
 * @deprecated 从macOS 10.9/iOS 7.0/watchOS 2.0开始,建议使用-weekOfMonth或-weekOfYear方法
 *
 * @discussion 此方法已被弃用,建议使用-weekOfMonth或-weekOfYear方法来替代。weekOfMonth返回该月中的周数,weekOfYear返回该年中的周数。
 *
 * @example
 *   NSDateComponents *components = [[NSDateComponents alloc] init];
 *   [components setDay:1];
 *   [components setMonth:5];
 *   [components setYear:2021];
 *   NSInteger week = [components week]; // 返回5月1日所在的周数
 */
- (NSInteger)week API_DEPRECATED("Use -weekOfMonth or -weekOfYear, depending on which you mean", macos(10.4, 10.9), ios(2.0, 7.0), watchos(2.0, 2.0), tvos(9.0, 9.0));

/**
 * @brief 设置日期组件中的周数
 *
 * @param v 希望设置的周数
 *
 * @deprecated 从macOS 10.9/iOS 7.0/watchOS 2.0开始,建议使用-setWeekOfMonth:或-setWeekOfYear:方法
 *
 * @discussion 此方法已被弃用,建议使用-setWeekOfMonth:或-setWeekOfYear:方法来替代。setWeekOfMonth:设置该月中的周数,setWeekOfYear:设置该年中的周数。
 *
 * @example
 *   NSDateComponents *components = [[NSDateComponents alloc] init];
 *   [components setDay:1];
 *   [components setMonth:5];
 *   [components setYear:2021];
 *   [components setWeek:18]; // 设置5月第3周
 */
- (void)setWeek:(NSInteger)v API_DEPRECATED("Use -setWeekOfMonth: or -setWeekOfYear:, depending on which you mean", macos(10.4, 10.9), ios(2.0, 7.0), watchos(2.0, 2.0), tvos(9.0, 9.0));

/**
 * @brief 设置日期组件中指定单位的值
 *
 * @param value 希望设置的值
 * @param unit  希望设置的单位
 *
 * @available macOS 10.9/iOS 8.0/watchOS 2.0及以上
 *
 * @discussion 可以使用该方法设置日期组件中的各个单位的值,例如设置年份、月份、日期、小时数等。参数unit中可以传入多个单位,例如同时设置年份和月份的值,可以使用NSCalendarUnitYear | NSCalendarUnitMonth。
 *
 * @example
 *   NSDateComponents *components = [[NSDateComponents alloc] init];
 *   [components setDay:1];
 *   [components setMonth:5];
 *   [components setYear:2021];
 *   [components setValue:12 forComponent:NSCalendarUnitMonth]; // 将5月份设置为12月份
 */
- (void)setValue:(NSInteger)value forComponent:(NSCalendarUnit)unit API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 获取日期组件中指定单位的值
 *
 * @param unit  希望获取的单位
 *
 * @available macOS 10.9/iOS 8.0/watchOS 2.0及以上
 *
 * @discussion 可以使用该方法获取日期组件中的各个单位的值,例如获取年份、月份、日期、小时数等。参数unit中可以传入多个单位,例如同时获取年份和月份的值,可以使用NSCalendarUnitYear | NSCalendarUnitMonth。
 *
 * @example
 *   NSDateComponents *components = [[NSDateComponents alloc] init];
 *   [components setDay:1];
 *   [components setMonth:5];
 *   [components setYear:2021];
 *   NSInteger month = [components valueForComponent:NSCalendarUnitMonth]; // 获取5月份
 */
- (NSInteger)valueForComponent:(NSCalendarUnit)unit API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/**
 * @brief 判断日期组件是否在指定的日历中是有效的
 *
 * @param calendar 希望判断的日历
 *
 * @available macOS 10.9/iOS 8.0/watchOS 2.0及以上
 *
 * @return 如果日期组件在指定的日历中是有效的,则返回YES,否则返回NO
 *
 * @discussion 可以使用该方法判断日期组件是否在指定的日历中是有效的,例如判断2月30日是否是一个有效的日期。
 *
 * @example
 *   NSDateComponents *components = [[NSDateComponents alloc] init];
 *   [components setDay:30];
 *   [components setMonth:2];
 *   [components setYear:2021];
 *   NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
 *   BOOL isValid = [components isValidDateInCalendar:calendar]; // 返回NO,2月30日是无效的日期
 */
- (BOOL)isValidDateInCalendar:(NSCalendar *)calendar API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

/** 日历对象 */
@property(nullable, copy) NSCalendar *calendar API_AVAILABLE(macos(10.7), ios(4.0), watchos(2.0), tvos(9.0));
/** 时区 */
@property(nullable, copy) NSTimeZone *timeZone API_AVAILABLE(macos(10.7), ios(4.0), watchos(2.0), tvos(9.0));
/** 年代 */
@property NSInteger era;
/** 年份 */
@property NSInteger year;
/** 月份 */
@property NSInteger month;
/** 日 */
@property NSInteger day;
/** 小时 */
@property NSInteger hour;
/** 分钟 */
@property NSInteger minute;
/** 秒 */
@property NSInteger second;
/** 纳秒 */
@property NSInteger nanosecond API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 星期几 */
@property NSInteger weekday;
/** 当月第几个星期几 */
@property NSInteger weekdayOrdinal;
/** 季度 */
@property NSInteger quarter API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
/** 当月第几周 */
@property NSInteger weekOfMonth API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 当年第几周 */
@property NSInteger weekOfYear API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 当年的第几周 */
@property NSInteger yearForWeekOfYear API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
/** 是否为闰月 */
@property(getter=isLeapMonth) BOOL leapMonth API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0));
/** 根据当前日期计算出的 NSDate 对象 */
@property(nullable, readonly, copy) NSDate *date API_AVAILABLE(macos(10.7), ios(4.0), watchos(2.0), tvos(9.0));
/** 当前日期是否有效 */
@property(getter=isValidDate, readonly) BOOL validDate API_AVAILABLE(macos(10.9), ios(8.0), watchos(2.0), tvos(9.0));

@end
posted @ 2019-02-15 22:55  CH520  阅读(688)  评论(0编辑  收藏  举报