iOS NSCalendar 日歷【轉(zhuǎn)】

NSCalendar 對世界上現(xiàn)存的常用的歷法進(jìn)行了封裝喉誊,既提供了不同歷法的時間信息,又支持日歷的計算纵顾∥榍眩可以很方便的用來表示日期,獲取日期的各種信息施逾,包括年敷矫、月例获、日,時分秒曹仗≌ヌ溃可以很方便的計算兩個日期之前的關(guān)系。也可以很方便的根據(jù)一個日期獲取另一個日期怎茫。

  • NSCalendar -- 日歷類收壕,它提供了大部分的日期計算接口,并且允許您在NSDate和NSDateComponents之間轉(zhuǎn)換
  • NSTimeZone -- 時區(qū)信息
  • NSLocale -- 本地化信息
  • NSDate -- 表示一個絕對的時間點
  • NSDateComponents -- 一個封裝了具體年月日轨蛤、時秒分蜜宪、周、季度等的類
  • NSDateFormatter -- 用來在日期和字符串之間轉(zhuǎn)換

1. 日歷的創(chuàng)建

根據(jù)提供的日歷標(biāo)示符初始化祥山。
identifier 的范圍可以是:

        NSCalendarIdentifierGregorian         公歷
        NSCalendarIdentifierBuddhist          佛教日歷
        NSCalendarIdentifierChinese           中國農(nóng)歷
        NSCalendarIdentifierHebrew            希伯來日歷
        NSCalendarIdentifierIslamic           伊斯蘭日歷
        NSCalendarIdentifierIslamicCivil      伊斯蘭教日歷
        NSCalendarIdentifierJapanese          日本日歷
        NSCalendarIdentifierRepublicOfChina   中華民國日歷(臺灣)
        NSCalendarIdentifierPersian           波斯歷
        NSCalendarIdentifierIndian            印度日歷
        NSCalendarIdentifierISO8601           ISO8601
// 使用用戶手機設(shè)置的日期信息圃验,有緩存,用戶手機日歷改變后不會變
@property (class, readonly, copy) NSCalendar *currentCalendar;  
// 使用用戶手機設(shè)置的日期信息缝呕,并且用戶改變之后會跟著改變
@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
// 使用指定的標(biāo)識獲取日期澳窑,比如農(nóng)歷、佛歷供常,常用的是格里高利歷(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中有一個重要的概念NSCalendarUnit摊聋,這是一個位枚舉,意味著作為參數(shù)可以采用位運算的方式傳參话侧。
  • 另外一個比較重要的類是NSDateComponents,上面是通過位參數(shù)獲取每個單位(年月日)的信息闯参,返回的結(jié)構(gòu)可以看到是一個NSDateComponents瞻鹏,如果我要表示一個日期的信息,構(gòu)建日期或者進(jìn)行日期的計算鹿寨,就少不了NSDateComponents新博,它可以將日期按照單位的形式封裝起來,然后通過NSCalendar的方法進(jìn)行計算
NSDateComponents *comps = [NSCalendar.currentCalendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:[NSDate date]];

2. 日歷的設(shè)置

NSCalendar *calendar = [NSCalendar currentCalendar];
    
    // 獲取日歷標(biāo)示符
NSString *calendarIdentifier =  calendar.calendarIdentifier;
    
    // 獲取地區(qū)信息
    /*
        語言地區(qū)
    */
NSString *localeIdentifier = calendar.locale.localeIdentifier;
NSString *localeIdentifier2 = [calendar.locale objectForKey:NSLocaleIdentifier];
        
    // 獲取時區(qū)信息
    NSTimeZone *timeZone = calendar.timeZone;
        
    // 獲取每周的第一天從星期幾開始
    /*
        缺省為星期天
    */
    NSUInteger firstWeekday = calendar.firstWeekday;
        
    // 獲取第一周必須包含的最少天數(shù)
    /*
        缺省為 1
    */
    NSUInteger minimumDaysInFirstWeek = calendar.minimumDaysInFirstWeek;

3. 日歷信息的獲取

1) 獲取一個小的單位在一個大的單位里面的序數(shù)
NSUInteger count = [calendar ordinalityOfUnit:NSCalendarUnitWeekday
inUnit:NSCalendarUnitWeekOfMonth
forDate:[NSDate date]];

  • (NSUInteger)ordinalityOfUnit:(NSCalendarUnit)smaller inUnit:(NSCalendarUnit)larger forDate:(NSDate *)date;

    NSCalendarUnit包含的值有:

      NSCalendarUnitEra                 -- 紀(jì)元單位脚草。對于 NSGregorianCalendar (公歷)來說赫悄,只有公元前(BC)和公元(AD);
                                           而對于其它歷法可能有很多馏慨,例如日本和歷是以每一代君王統(tǒng)治來做計算埂淮。
      NSCalendarUnitYear                -- 年單位。值很大写隶,相當(dāng)于經(jīng)歷了多少年倔撞,未來多少年。
      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         -- 月包含的周數(shù)想际。最多為6個周
      NSCalendarUnitWeekOfYear          -- 年包含的周數(shù)培漏。最多為53個周
      NSCalendarUnitYearForWeekOfYear   -- 沒完全搞清楚
      NSCalendarUnitTimeZone            -- 沒完全搞清楚
    

    <1>、當(dāng)小單位為 NSCalendarUnitWeekday胡本,大單位為 NSCalendarUnitWeekOfMonth / NSCalendarUnitWeekOfYear 時
    (即某個日期在這一周是第幾天)牌柄,根據(jù) firstWeekday 屬性不同,返回的結(jié)果也不同侧甫。具體說明如下:

      當(dāng) firstWeekday 被指定為星期天(即 = 1)時珊佣,它返回的值與星期幾對應(yīng)的數(shù)值保持一致。比如:
          fromDate 傳入的參數(shù)是星期日披粟,則函數(shù)返回 1
          fromDate 傳入的參數(shù)是星期一咒锻,則函數(shù)返回 2
      當(dāng) firstWeekday 被指定為其它值時(即 <> 1)時,假設(shè)firstWeekday 被指定為星期一(即 = 2)守屉,那么:
          fromDate 傳入的參數(shù)是星期一惑艇,則函數(shù)返回 1
          fromDate 傳入的參數(shù)是星期二,則函數(shù)返回 2
          fromDate 傳入的參數(shù)是星期日拇泛,則函數(shù)返回 7
    

    <2>滨巴、當(dāng)小單位為 參數(shù)為 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 設(shè)定 = 1
          則 fromDate 傳入1月1號熄守,方法均返回1  ==> 滿足 minimumDaysInFirstWeek 指定的天數(shù)(最少1天)蜈垮,所以方法將其歸為
                                                2005年的第1周
          則 fromDate 傳入1月2-8號,方法均返回2
          則 fromDate 傳入1月9-15號裕照,方法均返回3
          ......
    
          b. 如果將 minimumDaysInFirstWeek 設(shè)定為 > 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 設(shè)定為 <= 5時
          則 fromDate 傳入1月1-5號紊扬,方法均返回1  ==> 滿足 minimumDaysInFirstWeek 指定的天數(shù)蜒茄,所以方法將其歸為2008年的第1周
          則 fromDate 傳入1月6-12號,方法均返回2
          則 fromDate 傳入1月13-19號餐屎,方法均返回3
          ......
    
          b. 如果將 minimumDaysInFirstWeek 設(shè)定為 > 5檀葛,比如6
          則 fromDate 傳入1月1-5號,方法均返回53  ==> 當(dāng)周不足6天腹缩,所以方法將其歸為2007年的第53周
          則 fromDate 傳入1月2-8號屿聋,方法均返回1
          則 fromDate 傳入1月9-15號,方法均返回2
          ......
    

    <3>藏鹊、當(dāng)小單位為 參數(shù)為 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 設(shè)定為小于或等于5的數(shù)
          則 fromDate 傳入4月1-5號影涉,方法均返回1
          則 fromDate 傳入4月6-12號变隔,方法均返回2
          則 fromDate 傳入4月13-19號,方法均返回3
          ....
    
          b. 如果將 minimumDaysInFirstWeek 設(shè)定為大于5的數(shù)
          則 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;

調(diào)用這個方法要明確一點,取得的是"范圍"而不是"包含"肌厨,下面是一些例子:

<1>、小單位是 NSCalendarUnitDay岔留,大單位是 NSCalendarUnitYear夏哭,并不是要取這一年包含多少天检柬,而是要取"天"(Day)這個單位
     在這一年(Year)的取值范圍献联。其實不管你提供的日期是多少,返回的值都是"1--31"何址。

<2>里逆、小單位是 NSCalendarUnitDay,大單位是 NSCalendarUnitMonth用爪。要取得參數(shù)時間點所對應(yīng)的月份下原押,"天"(Day)的取值范圍。
     根據(jù)參數(shù)時間的月份不同偎血,值也不同诸衔。例如2月是1--28盯漂、3月是 1--31、4月是1--30笨农。

<3>就缆、小單位是 NSCalendarUnitWeekOfMonth / NSCalendarUnitWeekOfYear,大單位是 NSCalendarUnitMonth谒亦。要取得參數(shù)
     時間點所對應(yīng)的月份下竭宰,"周"(Week)的取值范圍。需要注意的是結(jié)果會受到 minimumDaysInFirstWeek 屬性的影響份招。在默認(rèn) 
     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

        在上圖的日期條件下,假如提供的參數(shù)是4月1日--4月6日炼蛤,那么對應(yīng)的 week 就是1(第一個周),可以看到第一個周包含有6天嗽上,
    從1號開始兽愤,那么最終得到的范圍值為1--6逐沙。

    假如提供的參數(shù)是4月18日酱吝,那么對應(yīng)的 week 是3(第三個周),第三個周包含有7天崎岂,從14號開始冲甘,那么最終得到的范圍值是14--7。

    假如提供的參數(shù)是4月30日陶夜,那么對應(yīng)的 week 是5(第五個周),第五個周只包含3天羽嫡,從28號開始杭棵,那么最終得到的范圍值是28--3。

3)獲取所在日歷單位的開始時間及所在日歷單位的總秒數(shù)

NSDate *startDate = nil;
NSTimeInterval intervalCount = 0;

BOOL bl = [calendar rangeOfUnit:NSCalendarUnitMonth 
                      startDate:&startDate 
                       interval:&intervalCount 
                        forDate:[NSDate date]];

if (bl) {

    // 得到本地時間密浑,避免時區(qū)問題
    startDate = [startDate dateByAddingTimeInterval:[[NSTimeZone systemTimeZone] secondsFromGMTForDate:startDate]];

    NSLog(@"%@",startDate);
    NSLog(@"%f",intervalCount);
}
else {
    NSLog(@"無法計算");
}
//獲取日期date對應(yīng)月的第一天日期
+ (NSString *)getMonthFirstDayWithDate:(NSDate *)date format:(NSString *)aformat;
//獲取日期date對應(yīng)月的最后一天日期
+ (NSString *)getMonthLastDayWithDate:(NSDate *)date format:(NSString *)aformat;
//獲取對應(yīng)日期是周幾
+ (NSInteger)getWeekDayFromDate:(NSDate *)date;


+ (NSString *)getMonthFirstDayWithDate:(NSDate *)date format:(NSString *)aformat{
    NSDate *newDate = date;
    double interval = 0;
    NSDate *firstDate = nil;
    NSCalendar *calendar = [NSCalendar currentCalendar];
    BOOL bl = [calendar rangeOfUnit:NSCalendarUnitMonth startDate:& firstDate interval:&interval forDate:newDate];
    if (bl) {
        NSDateFormatter *myDateFormatter = [[NSDateFormatter alloc] init];
        [myDateFormatter setDateFormat:aformat];
        NSString *firstString = [myDateFormatter stringFromDate: firstDate];
        return firstString;
    }
    return @"";
}
+ (NSString *)getMonthLastDayWithDate:(NSDate *)date format:(NSString *)aformat{
    NSDate *newDate = date;
    double interval = 0;
    NSDate *firstDate = nil;
    NSDate *lastDate = nil;
    NSCalendar *calendar = [NSCalendar currentCalendar];
    BOOL bl = [calendar rangeOfUnit:NSCalendarUnitMonth startDate:& firstDate interval:&interval forDate:newDate];
    if (bl) {
        lastDate = [firstDate dateByAddingTimeInterval:interval - 1];
        NSDateFormatter *myDateFormatter = [[NSDateFormatter alloc] init];
        [myDateFormatter setDateFormat:aformat];
        NSString *lastString = [myDateFormatter stringFromDate: lastDate];
        return lastString;
    }
    return @"";
}

+ (NSInteger)getWeekDayFromDate:(NSDate *)date{
    NSArray *tempWeek = @[@"7",@"1",@"2",@"3",@"4",@"5",@"6"];
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    
    NSDateComponents *comps = [[NSDateComponents alloc] init];
    
    NSInteger unitFlags = NSCalendarUnitYear |NSCalendarUnitMonth | NSCalendarUnitDay |NSCalendarUnitWeekday | NSCalendarUnitHour |NSCalendarUnitMinute |NSCalendarUnitSecond;
    
    comps = [calendar components:unitFlags fromDate:date];
    //  1餐济、2絮姆、3蚁阳、4、5定血、6、7 分別對應(yīng) 周日、周一席噩、周二、周三脾拆、周四馒索、周五、周六
    NSInteger week = [comps weekday];
    NSLog(@"---%ld",week);
    return  [tempWeek[week-1] integerValue] ;
    
}

參考資料:
QianChia NSCalendar - 日歷

山有木枝壯 NSCalendar使用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市渠驼,隨后出現(xiàn)的幾起案子爽哎,更是在濱河造成了極大的恐慌渺贤,老刑警劉巖获印,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異兼丰,居然都是意外死亡玻孟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門艳丛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匣掸,“玉大人,你說我怎么就攤上這事氮双∨鲈停” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵戴差,是天一觀的道長送爸。 經(jīng)常有香客問我,道長暖释,這世上最難降的妖魔是什么袭厂? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮球匕,結(jié)果婚禮上纹磺,老公的妹妹穿的比我還像新娘。我一直安慰自己亮曹,他們只是感情好橄杨,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布秘症。 她就那樣靜靜地躺著,像睡著了一般讥珍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窄瘟,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天衷佃,我揣著相機與錄音,去河邊找鬼蹄葱。 笑死氏义,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的图云。 我是一名探鬼主播惯悠,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼竣况!你這毒婦竟也來了克婶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤丹泉,失蹤者是張志新(化名)和其女友劉穎情萤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摹恨,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡筋岛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了晒哄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片睁宰。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖寝凌,靈堂內(nèi)的尸體忽然破棺而出柒傻,到底是詐尸還是另有隱情,我是刑警寧澤较木,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布诅愚,位于F島的核電站,受9級特大地震影響劫映,放射性物質(zhì)發(fā)生泄漏违孝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一泳赋、第九天 我趴在偏房一處隱蔽的房頂上張望雌桑。 院中可真熱鬧,春花似錦祖今、人聲如沸校坑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耍目。三九已至膏斤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邪驮,已是汗流浹背莫辨。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毅访,地道東北人沮榜。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像喻粹,于是被迫代替她去往敵國和親蟆融。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354