2020-4-10
经测试,直接使用comps.day = 1
会出现其他bug,修改方案只能通过将NSDataFormatter
的timeZone
修改为Calendar
对应的timeZone
即可
原因:直接将day month year
赋值给comps
但未更新准确的comps.weekday
,导致当前月的1号所在的周几数据错误,日历表中的显示出错
comps.year = year;
comps.month = month;
comps.day = 1;
comps.weekday = ?;
2020-4-9
1. 要兼容所有时区的日历,在NSDate
、NSTimeInterval
、NSTimeInterval
进行相互之间转换和使用时,尽量避免使用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对象也会与时区挂钩,可指定calendar
的timeZone
,在后续使用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;
}