日历页面无法适配其他时区的问题

419 阅读2分钟

2020-4-10

经测试,直接使用comps.day = 1会出现其他bug,修改方案只能通过将NSDataFormattertimeZone修改为Calendar对应的timeZone即可

原因:直接将day month year赋值给comps但未更新准确的comps.weekday,导致当前月的1号所在的周几数据错误,日历表中的显示出错

comps.year = year;
comps.month = month;
comps.day = 1;
comps.weekday = ?;

2020-4-9

1. 要兼容所有时区的日历,在NSDateNSTimeIntervalNSTimeInterval进行相互之间转换和使用时,尽量避免使用NSDateFormatter进行转换

    NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
    inputFormatter.timeZone = [NSTimeZone systemTimeZone];
    [inputFormatter setDateFormat:@"yyyyMMdd"];
    NSDate* inputDate = [inputFormatter dateFromString:string];

在代码中使用了timeZone,便与当地时区进行挂钩,会自动对NSDateFormatter进行时差的计算,如想要获取20200401,很有可能就变成timeZone,在日历中进行使用,造成数据混乱。

2. 除NSDateFormatter外,NSCalendar对象也会与时区挂钩,可指定calendartimeZone,在后续使用NSDateFormatter时,timeZone也应使用calendar指定的timeZone,保持一致

- (NSCalendar *)gregorianCalendar {
    static NSCalendar *calendar;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
        calendar.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:8 * 3600];
    });
    
    return calendar;
}

3. 如果想要获取当月第一天的NSDateComponents,可以直接只用comps.day = 1;进行赋值。不必通过NSDateFormatter进行转换

心得总结完毕,代码修改记录:

代码修改前:

+(NSDateComponents *)getCellMonthDate1:(NSInteger)deviation
{
    NSDateComponents *comps = [DateTools getCurrentDate];
    NSInteger month = [comps month];
    NSInteger year = [comps year];
    NSInteger yearDeviation;
    NSInteger monthDeviation;
    
    if (deviation>0) {
        yearDeviation = deviation/12;
        monthDeviation = deviation%12;
        if (monthDeviation+month >12 ) {
            month = monthDeviation + month - 12;
            yearDeviation++;
        }
        else{
            month = month + monthDeviation;
        }
    }
    else
    {
        yearDeviation = deviation/12;
        monthDeviation = deviation%12;
        if (monthDeviation+month < 0) {
            month = month - monthDeviation -12;
            yearDeviation--;
        }
        else{
            month = month + monthDeviation;
        }
    }
    year = year+yearDeviation;
    NSString* string;
    if(month<10)
    {
        string = [NSString stringWithFormat:@"%ld0%ld01",(long)year,(long)month];
    }
    else
    {
        string = [NSString stringWithFormat:@"%ld%ld01",(long)year,(long)month];
    }
    NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
    inputFormatter.timeZone = [NSTimeZone systemTimeZone];
    [inputFormatter setDateFormat:@"yyyyMMdd"];
    NSDate* inputDate = [inputFormatter dateFromString:string];
    
    NSCalendar *calendar = [GTCalendarConfig sharedInstance].gregorianCalendar;
    NSDateComponents *components = [[NSDateComponents alloc] init];
    NSInteger unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekday;
    components = [calendar components:unitFlags fromDate:inputDate];
    return components;
}

问题在于:使用NSDateFormatter时,timeZone使用了[NSTimeZone systemTimeZone],时区未与calendar保持一致,可修改为inputFormatter.timeZone = [GTCalendarConfig sharedInstance].gregorianCalendar.timeZone,或者不使用NSDateFormatter

代码修改后:

+ (NSDateComponents *)getCellMonthDate:(NSInteger)deviation {
    // 获取当天的年月日
    NSDateComponents *comps = [DateTools getCurrentDate];
    
    NSInteger month = [comps month];
    NSInteger year = [comps year];
    NSInteger yearDeviation;
    NSInteger monthDeviation;
    if (deviation>0) {
        yearDeviation = deviation/12;
        monthDeviation = deviation%12;
        if (monthDeviation+month >12 ) {
            month = monthDeviation + month - 12;
            yearDeviation++;
        }
        else{
            month = month + monthDeviation;
        }
    }
    else
    {
        yearDeviation = deviation/12;
        monthDeviation = deviation%12;
        if (monthDeviation+month < 0) {
            month = month - monthDeviation -12;
            yearDeviation--;
        }
        else{
            month = month + monthDeviation;
        }
    }
    year = year+yearDeviation;
    // 将偏移后的年月直接更新到comps中,首日直接赋值1
    comps.year = year;
    comps.month = month;
    comps.day = 1;
    return comps;
}