Skip to content

Commit

Permalink
fix #308 修复自定义时区问题
Browse files Browse the repository at this point in the history
  • Loading branch information
agiapp committed May 27, 2024
1 parent c410f08 commit 8213aa6
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 93 deletions.
5 changes: 2 additions & 3 deletions BRPickerView/DatePickerView/BRDatePickerView+BR.m
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ - (NSDate *)handlerSelectDate:(NSDate *)selectDate dateFormat:(NSString *)dateFo
date = [self br_dateFromString:self.selectValue dateFormat:dateFormat];
if (!date) {
BRErrorLog(@"参数异常!字符串 selectValue 的正确格式是:%@", dateFormat);
NSAssert(date, @"参数异常!请检查字符串 selectValue 的格式");
date = [NSDate date]; // 默认值参数格式错误时,重置/忽略默认值,防止在 Release 环境下崩溃!
}
if (self.pickerMode == BRDatePickerModeMDHM) {
Expand Down Expand Up @@ -152,12 +151,12 @@ - (NSDate *)handlerSelectDate:(NSDate *)selectDate dateFormat:(NSString *)dateFo

#pragma mark - NSDate 转 NSString
- (NSString *)br_stringFromDate:(NSDate *)date dateFormat:(NSString *)dateFormat {
return [NSDate br_stringFromDate:date dateFormat:dateFormat timeZone:self.timeZone language:self.pickerStyle.language];
return [NSDate br_stringFromDate:date dateFormat:dateFormat language:self.pickerStyle.language];
}

#pragma mark - NSString 转 NSDate
- (NSDate *)br_dateFromString:(NSString *)dateString dateFormat:(NSString *)dateFormat {
return [NSDate br_dateFromString:dateString dateFormat:dateFormat timeZone:self.timeZone language:self.pickerStyle.language];
return [NSDate br_dateFromString:dateString dateFormat:dateFormat language:self.pickerStyle.language];
}

#pragma mark - 比较两个日期大小(可以指定比较级数,即按指定格式进行比较)
Expand Down
18 changes: 11 additions & 7 deletions BRPickerView/DatePickerView/BRDatePickerView.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,12 @@ typedef void (^BRDateResultRangeBlock)(NSDate * _Nullable selectStartDate, NSDat
/** 是否添加【至今】,默认为 NO */
@property (nonatomic, assign, getter=isAddToNow) BOOL addToNow;

/** 首行添加自定义字符串,配合 selectValue 可设置默认选中 */
/** 首行添加 自定义字符串,配合 selectValue 可设置默认选中 */
@property (nullable, nonatomic, copy) NSString *firstRowContent;

/** 末行添加自定义字符串,配合 selectValue 可设置默认选中 */
/** 末行添加 自定义字符串(如:至今),配合 selectValue 可设置默认选中 */
@property (nullable, nonatomic, copy) NSString *lastRowContent;

/** 最后一行,添加【自定义字符串】 */
@property (nullable, nonatomic, copy) NSString *addCustomString DEPRECATED_MSG_ATTRIBUTE("Use 'lastRowContent' instead");

/** 滚轮上日期数据排序是否降序,默认为 NO(升序)*/
@property (nonatomic, assign, getter=isDescending) BOOL descending;

Expand Down Expand Up @@ -168,8 +165,15 @@ typedef void (^BRDateResultRangeBlock)(NSDate * _Nullable selectStartDate, NSDat
/** 设置时区,默认为当前时区 */
@property (nullable, nonatomic, copy) NSTimeZone *timeZone;

/** default is [NSCalendar currentCalendar]. setting nil returns to default. for `UIDatePicker` */
@property (nonatomic, copy) NSCalendar *calendar;
/**
* 日历对象:默认是 [NSCalendar currentCalendar]. setting nil returns to default. for `UIDatePicker`
*
* // 创建日历对象,可以指定日历的算法(公历/阳历)
* calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
* // 设置农历日期. for `UIDatePicker`, ignored otherwise.
* calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierChinese];
*/
@property (nullable, nonatomic, copy) NSCalendar *calendar;

/** 指定不允许选择的日期 */
@property (nullable, nonatomic, copy) NSArray <NSDate *> *nonSelectableDates;
Expand Down
10 changes: 5 additions & 5 deletions BRPickerView/DatePickerView/BRDatePickerView.m
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ - (void)handlerPickerData {
self.maxDate = [self handlerMaxDate:self.maxDate];

BOOL minMoreThanMax = [self br_compareDate:self.minDate targetDate:self.maxDate dateFormat:self.dateFormatter] == NSOrderedDescending;
NSAssert(!minMoreThanMax, @"最小日期不能大于最大日期!");
if (minMoreThanMax) {
BRErrorLog(@"最小日期不能大于最大日期!");
// 如果最小日期大于了最大日期,就忽略两个值
self.minDate = [NSDate distantPast]; // 0000-12-30 00:00:00 +0000
self.maxDate = [NSDate distantFuture]; // 4001-01-01 00:00:00 +0000
Expand Down Expand Up @@ -1640,8 +1640,6 @@ - (void)reloadData {
}

self.datePicker.calendar = self.calendar;
// 设置农历日期
//self.datePicker.calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierChinese];

if (self.minDate) {
self.datePicker.minimumDate = self.minDate;
Expand Down Expand Up @@ -1803,8 +1801,10 @@ - (void)setSelectValue:(NSString *)selectValue {
}
}

- (void)setAddCustomString:(NSString *)addCustomString {
self.lastRowContent = addCustomString;
- (void)setTimeZone:(NSTimeZone *)timeZone {
_timeZone = timeZone;
// 同步时区设置
[NSDate br_setTimeZone:timeZone];
}

#pragma mark - getter 方法
Expand Down
43 changes: 18 additions & 25 deletions BRPickerView/DatePickerView/NSDate+BRPickerView.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,19 @@
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSDate (BRPickerView)

/// ---------------- 设置【日历对象】和【时区】 ----------------
/** 设置日历对象 */
+ (void)br_setCalendar:(NSCalendar *)calendar;
/** 获取日历对象 */
+ (NSCalendar *)br_getCalendar;

/** 设置时区 */
+ (void)br_setTimeZone:(NSTimeZone *)timeZone;
/** 获取当前时区 */
+ (NSTimeZone *)br_getTimeZone;

/// 获取指定date的详细信息
@property (readonly) NSInteger br_year; //
@property (readonly) NSInteger br_month; //
Expand All @@ -27,14 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
/** 获取中文星期字符串 */
@property (nullable, nonatomic, readonly, copy) NSString *br_weekdayString;

/** 获取日历单例对象 */
+ (NSCalendar *)br_calendar;


/// ---------------- 创建 date ----------------
/** 通过 NSDateComponents对象 来创建 NSDate对象(可以设置时区) */
+ (nullable NSDate *)br_setDateFromComponents:(NSDateComponents *)components timeZone:(NSTimeZone *)timeZone;

/** yyyy */
+ (nullable NSDate *)br_setYear:(NSInteger)year;

Expand Down Expand Up @@ -98,30 +102,19 @@ NS_ASSUME_NONNULL_BEGIN
/** 获取 日期加上/减去某个月数后的新日期 */
- (nullable NSDate *)br_getNewDateToMonths:(NSTimeInterval)months;

/** NSDate 转 NSString */
/** NSDate 转 NSString(使用系统默认 时区 和 语言)*/
+ (nullable NSString *)br_stringFromDate:(NSDate *)date dateFormat:(NSString *)dateFormat;
/** NSDate 转 NSString */
+ (nullable NSString *)br_stringFromDate:(NSDate *)date
dateFormat:(NSString *)dateFormat
timeZone:(nullable NSTimeZone *)timeZone
language:(nullable NSString *)language;

dateFormat:(NSString *)dateFormat
language:(nullable NSString *)language;

/** NSString 转 NSDate */
/** NSString 转 NSDate(使用系统默认 时区 和 语言)*/
+ (nullable NSDate *)br_dateFromString:(NSString *)dateString dateFormat:(NSString *)dateFormat;
/** NSString 转 NSDate */
+ (nullable NSDate *)br_dateFromString:(NSString *)dateString
dateFormat:(NSString *)dateFormat
timeZone:(nullable NSTimeZone *)timeZone
language:(nullable NSString *)language;


/** NSDate 转 NSString(已弃用) */
+ (nullable NSString *)br_getDateString:(NSDate *)date format:(NSString *)format DEPRECATED_MSG_ATTRIBUTE("Use 'br_stringFromDate:dateFormat:' instead");

/** NSString 转 NSDate(已弃用) */
+ (nullable NSDate *)br_getDate:(NSString *)dateString format:(NSString *)format DEPRECATED_MSG_ATTRIBUTE("Use 'br_dateFromString:dateFormat:' instead");

dateFormat:(NSString *)dateFormat
language:(nullable NSString *)language;

@end

Expand Down
97 changes: 44 additions & 53 deletions BRPickerView/DatePickerView/NSDate+BRPickerView.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,60 @@

@implementation NSDate (BRPickerView)

#pragma mark - 获取日历单例对象
+ (NSCalendar *)br_calendar {
static NSCalendar *sharedCalendar = nil;
if (!sharedCalendar) {
/// 日历对象
static NSCalendar *_sharedCalendar = nil;
/// 时区
static NSTimeZone *_timeZone = nil;

/// ---------------- 设置【日历对象】和【时区】 ----------------
#pragma mark - 设置日历对象
+ (void)br_setCalendar:(NSCalendar *)calendar {
_sharedCalendar = calendar;
}

#pragma mark - 获取日历对象
+ (NSCalendar *)br_getCalendar {
if (!_sharedCalendar) {
// 创建日历对象,指定日历的算法(公历/阳历)
sharedCalendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
_sharedCalendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
// NSCalendar 设置时区
//sharedCalendar.timeZone = [NSTimeZone timeZoneWithName:@"America/Chicago"];
//_sharedCalendar.timeZone = [NSTimeZone timeZoneWithName:@"America/New_York"];
}
return _sharedCalendar;
}

#pragma mark - 设置时区
+ (void)br_setTimeZone:(NSTimeZone *)timeZone {
_timeZone = timeZone;
_sharedCalendar.timeZone = timeZone;
}

#pragma mark - 获取当前时区
+ (NSTimeZone *)br_getTimeZone {
if (!_timeZone) {
// 当前时区(不使用夏时制)
NSTimeZone *localTimeZone = [NSTimeZone localTimeZone];
// 当前时区相对于GMT(零时区)的偏移秒数
NSInteger interval = [localTimeZone secondsFromGMTForDate:[NSDate date]];
// 当前时区(不使用夏时制):由偏移量获得对应的NSTimeZone对象
// 注意:一些夏令时时间 NSString 转 NSDate 时,默认会导致 NSDateFormatter 格式化失败,返回 null
_timeZone = [NSTimeZone timeZoneForSecondsFromGMT:interval];
}
return sharedCalendar;
return _timeZone;
}

#pragma mark - NSDate 转 NSDateComponents
+ (NSDateComponents *)br_componentsFromDate:(NSDate *)date {
// 通过日历类 NSCalendar 进行转换
NSCalendar *calendar = [self br_calendar];
NSCalendar *calendar = [self br_getCalendar];
// NSDateComponents 可以获得日期的详细信息,即日期的组成
return [calendar components:unitFlags fromDate:date];
}

#pragma mark - NSDateComponents 转 NSDate
+ (NSDate *)br_dateFromComponents:(NSDateComponents *)components {
// 通过日历类 NSCalendar 进行转换
NSCalendar *calendar = [self br_calendar];
NSCalendar *calendar = [self br_getCalendar];
return [calendar dateFromComponents:components];
}

Expand Down Expand Up @@ -147,17 +177,6 @@ - (NSString *)br_weekdayString {
}

/// ---------------- 创建 date ----------------
#pragma mark - 通过 NSDateComponents对象 来创建 NSDate对象(可以设置时区)
+ (nullable NSDate *)br_setDateFromComponents:(NSDateComponents *)components timeZone:(NSTimeZone *)timeZone {
// 创建日历对象,指定日历的算法(公历/阳历)
NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
if (timeZone) {
// NSCalendar 设置时区
calendar.timeZone = timeZone;
}
return [calendar dateFromComponents:components];
}

#pragma mark - 创建date(通过 NSCalendar 类来创建日期)
+ (NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)second {
return [self br_setYear:year month:month day:day hour:hour minute:minute second:second weekOfMonth:0 weekOfYear:0 quarter:0];
Expand Down Expand Up @@ -334,20 +353,17 @@ - (nullable NSDate *)br_getNewDateToMonths:(NSTimeInterval)months {

#pragma mark - NSDate 转 NSString
+ (NSString *)br_stringFromDate:(NSDate *)date dateFormat:(NSString *)dateFormat {
return [self br_stringFromDate:date dateFormat:dateFormat timeZone:nil language:nil];
return [self br_stringFromDate:date dateFormat:dateFormat language:nil];
}
#pragma mark - NSDate 转 NSString
+ (NSString *)br_stringFromDate:(NSDate *)date
dateFormat:(NSString *)dateFormat
timeZone:(NSTimeZone *)timeZone
language:(NSString *)language {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
// 设置日期格式
dateFormatter.dateFormat = dateFormat;
// NSDateFormatter 设置时区 ,不设置默认为系统时区
if (timeZone) {
dateFormatter.timeZone = timeZone;
}
dateFormatter.timeZone = [self br_getTimeZone];
if (!language) {
language = [NSLocale preferredLanguages].firstObject;
}
Expand All @@ -359,50 +375,25 @@ + (NSString *)br_stringFromDate:(NSDate *)date

#pragma mark - NSString 转 NSDate
+ (NSDate *)br_dateFromString:(NSString *)dateString dateFormat:(NSString *)dateFormat {
return [self br_dateFromString:dateString dateFormat:dateFormat timeZone:nil language:nil];
return [self br_dateFromString:dateString dateFormat:dateFormat language:nil];
}
#pragma mark - NSString 转 NSDate
+ (NSDate *)br_dateFromString:(NSString *)dateString
dateFormat:(NSString *)dateFormat
timeZone:(NSTimeZone *)timeZone
language:(NSString *)language {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
// 设置日期格式
dateFormatter.dateFormat = dateFormat;
// 设置时区
if (!timeZone) {
timeZone = [self currentTimeZone];
}
if (!language) {
language = [NSLocale preferredLanguages].firstObject;
}
dateFormatter.timeZone = timeZone;
// 设置时区
dateFormatter.timeZone = [self br_getTimeZone];
dateFormatter.locale = [[NSLocale alloc]initWithLocaleIdentifier:language];
// 如果当前时间不存在,就获取距离最近的整点时间
dateFormatter.lenient = YES;

return [dateFormatter dateFromString:dateString];
}

#pragma mark - 获取当前时区(不使用夏时制)
+ (NSTimeZone *)currentTimeZone {
// 当前时区
NSTimeZone *localTimeZone = [NSTimeZone localTimeZone];
// 当前时区相对于GMT(零时区)的偏移秒数
NSInteger interval = [localTimeZone secondsFromGMTForDate:[NSDate date]];
// 当前时区(不使用夏时制):由偏移量获得对应的NSTimeZone对象
// 注意:一些夏令时时间 NSString 转 NSDate 时,默认会导致 NSDateFormatter 格式化失败,返回 null
return [NSTimeZone timeZoneForSecondsFromGMT:interval];
}

#pragma mark - NSDate 转 NSString(已弃用)
+ (NSString *)br_getDateString:(NSDate *)date format:(NSString *)format {
return [self br_stringFromDate:date dateFormat:format];
}

#pragma mark - NSString 转 NSDate(已弃用)
+ (NSDate *)br_getDate:(NSString *)dateString format:(NSString *)format {
return [self br_dateFromString:dateString dateFormat:format];
}

@end

0 comments on commit 8213aa6

Please sign in to comment.