iOS NSCalendar的使用,制作日历

作者: Double_Chen | 来源:发表于2018-06-07 17:31 被阅读1118次

    本文不讲UI,用打印台来输出日历。

    在显示日历的时候,我们只需要传入参数年月即可,加上日期可以定位到当天在日历上的显示。

    日历的显示排版一般是7x5或7x4,每一行从周日开始,周六结束,像这样:


    屏幕快照 2018-06-07 17.14.22.png

    当我们要显示某个月份的时候,我们必需获取到下面这些值:

    1.当月第一天是周几;
    2.当月总天数

    有了这两条数据我们就可以显示出一个粗糙的日历了,但是有一点,假如当月第一天不是周一,如上图,那么前面几天的日期如何显示呢?所以我们会需要多一条数据:上个月份的总天数,通过简单的加减就能显示了,下面开始通过代码了解如何制作一个日历。

    我直接贴上代码吧:

    //根据date获取日
    - (NSInteger)convertDateToDay:(NSDate *)date {
        NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitDay) fromDate:date];
        return [components day];
    }
    
    //根据date获取月
    - (NSInteger)convertDateToMonth:(NSDate *)date {
        NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitMonth) fromDate:date];
        return [components month];
    }
    
    //根据date获取年
    - (NSInteger)convertDateToYear:(NSDate *)date {
        NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitYear) fromDate:date];
        return [components year];
    }
    
    //根据date获取当月周几 (美国时间周日-周六为 1-7,改为0-6方便计算)
    - (NSInteger)convertDateToWeekDay:(NSDate *)date {
        NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond|NSCalendarUnitWeekday fromDate:date];
        NSInteger weekDay = [components weekday] - 1;
        weekDay = MAX(weekDay, 0);
        return weekDay;
    }
    
    //根据date获取当月周几
    - (NSInteger)convertDateToFirstWeekDay:(NSDate *)date {
        NSCalendar *calendar = [NSCalendar currentCalendar];
        [calendar setFirstWeekday:1];//1.Sun. 2.Mon. 3.Thes. 4.Wed. 5.Thur. 6.Fri. 7.Sat.
        NSDateComponents *comp = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:date];
        [comp setDay:1];
        NSDate *firstDayOfMonthDate = [calendar dateFromComponents:comp];
        NSUInteger firstWeekday = [calendar ordinalityOfUnit:NSCalendarUnitWeekday inUnit:NSCalendarUnitWeekOfMonth forDate:firstDayOfMonthDate];
        return firstWeekday - 1;  //美国时间周日为星期的第一天,所以周日-周六为1-7,改为0-6方便计算
    }
    
    //根据date获取当月总天数
    - (NSInteger)convertDateToTotalDays:(NSDate *)date {
        NSRange daysInOfMonth = [[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date];
        return daysInOfMonth.length;
    }
    

    在获取周几的时候要注意一点,美国时间是星期日作为一周的第一天,所以通过函数回调的值,周日-周六是为1-7的,为了方便计算,我进行了-1操作。

    接下来是获取上个月份的数据:

    //根据date获取偏移指定天数的date
    - (NSDate *)getDateFrom:(NSDate *)date offsetDays:(NSInteger)offsetDays {
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyyy-MM"];
        
        NSCalendar *calendar = [NSCalendar currentCalendar];
        NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
        [lastMonthComps setDay:offsetDays];  //year = 1表示1年后的时间 year = -1为1年前的日期,month day 类推
        NSDate *newdate = [calendar dateByAddingComponents:lastMonthComps toDate:date options:0];
        return newdate;
    }
    
    //根据date获取偏移指定月数的date
    - (NSDate *)getDateFrom:(NSDate *)date offsetMonths:(NSInteger)offsetMonths {
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyyy-MM"];
        
        NSCalendar *calendar = [NSCalendar currentCalendar];
        NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
        [lastMonthComps setMonth:offsetMonths];  //year = 1表示1年后的时间 year = -1为1年前的日期,month day 类推
        NSDate *newdate = [calendar dateByAddingComponents:lastMonthComps toDate:date options:0];
        return newdate;
    }
    
    //根据date获取偏移指定年数的date
    - (NSDate *)getDateFrom:(NSDate *)date offsetYears:(NSInteger)offsetYears {
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyyy"];
        
        NSCalendar *calendar = [NSCalendar currentCalendar];
        NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
        [lastMonthComps setYear:offsetYears];  //year = 1表示1年后的时间 year = -1为1年前的日期,month day 类推
        NSDate *newdate = [calendar dateByAddingComponents:lastMonthComps toDate:date options:0];
        return newdate;
    }
    

    有了这几个函数,就能具备制作一个日历的数据支持了,接下来的代码可以自行复制输出:

    - (void)test {
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"yyyy-MM-dd"];
        for (int i = 1; i <= 12; i++) {
            NSString *string = [NSString stringWithFormat:@"2018-%02d-01",i];
            NSDate *date = [dateFormatter dateFromString:string];
            [self logCalendarWith:date];
        }
    }
    
    - (void)logCalendarWith:(NSDate *)date {
        NSInteger year = [self convertDateToYear:date];
        NSInteger month = [self convertDateToMonth:date];
        NSInteger day = [self convertDateToDay:date];
        NSInteger firstWeekDay = [self convertDateToFirstWeekDay:date];
        NSInteger totalDays = [self convertDateToTotalDays:date];
        
        printf("第%ld月\n",month);
        
        NSInteger line = totalDays <= 28 ? 4 : 5;
        NSInteger column = 7;
        
        NSInteger available = 1;    //超过总天数后为下月
        NSInteger nextMonthDay = 1; //下月天数开始计数
        
        NSDate *lastMonthDate = [self getDateFrom:date offsetMonths:-1];    //上月月数
        NSInteger lastMonthTotalDays = [self convertDateToTotalDays:lastMonthDate]; //上月天数计数
        
        for (int i = 0; i < line; i++) {
            for (int j = 0; j < column; j++) {
                if (available > totalDays) {
                    printf("\t%ld ",nextMonthDay++);
                    continue;
                }
                
                if (i == 0 && j < firstWeekDay) {
                    NSInteger lastMonthDay = lastMonthTotalDays - firstWeekDay + j + 1; //j从0开始,所以这里+1
                    printf("\t%ld ",lastMonthDay);
                }else {
                    printf("\t%ld",available++);
                }
            }
            printf("\n");
        }
        printf("\n");
        printf("\n");
    }
    

    想要测试年份、月份、日的准确性的话,就在test函数里面自行修改就好了,如果没有问题,打印台就有下面的显示:

    屏幕快照 2018-09-26 17.15.03.png

    相关文章

      网友评论

      本文标题:iOS NSCalendar的使用,制作日历

      本文链接:https://www.haomeiwen.com/subject/npggsftx.html