前言:
公司的App有海外用户。这些海外用户他们手机的时间,可不一定都是北京时间,有在美国的,有在英国的,有在日本的。
因为用户所处时区不一样,所以,每个手机的时间各不相同。然而我们服务器下发的时间,是北京时间。
这就有一个潜在问题:服务器下发的时间是北京时间上午9:00整开始上课,美国那边的用户打开手机看到的时间可不是上午9:00点,除非他自己去看北京时钟。
需求:无论用户处在哪个时区,打开我们的App,我们App里的时间,是和北京时间同步的。
代码地址:https://github.com/gityuency/ObjectiveCTools
示例代码类名 【AboutTimeViewController】
直接上结论代码,Command + C,V
//不管你的手机当前在哪个时区,也不管从 NSDate 还是 NSCalendar 里去获取时间,我都要拿到正确的东八时间,和服务器(服务器就在北京,给出的时间就是东八时间)给的时间做比较,方便接下来的时间逻辑。
- (void)viewDidLoad {
[super viewDidLoad];
NSString *timestring = @"2020-06-28 10:30";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:8]];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm"];
NSDate *dateServer = [formatter dateFromString:timestring];
NSLog(@"服务器时间(转东八): %@", dateServer);
NSDate *datePhone = [NSDate date];
NSTimeZone *GMT8Zone = [NSTimeZone timeZoneWithAbbreviation:@"GMT+0800"];
NSInteger interval = [GMT8Zone secondsFromGMTForDate:datePhone];
NSDate *localGTM8Date = [datePhone dateByAddingTimeInterval: interval];
NSLog(@"手机当前时间(转东八): %@",localGTM8Date);
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:8]];
NSUInteger unitFlags = NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute;
NSDateComponents *com1 = [calendar components:unitFlags fromDate:dateServer];
NSString *calendarServertime = [NSString stringWithFormat:@"今日%ld月%ld日 %ld时%ld分",(long)com1.month,(long)com1.day,(long)com1.hour,(long)com1.minute];
NSLog(@"服务器日历时间(转东八): %@", calendarServertime);
//NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT+0800"]];
//NSUInteger unitFlags = NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute;
NSDateComponents *com2 = [calendar components:unitFlags fromDate:datePhone];
NSString *calendarPhonetime = [NSString stringWithFormat:@"今日%ld月%ld日 %ld时%ld分",(long)com2.month,(long)com2.day,(long)com2.hour,(long)com2.minute];
NSLog(@"手机当前日历时间(转东八): %@", calendarPhonetime);
}
输出
ObjectiveCTools[1475:816321] 服务器时间(转东八): 2020-06-28 10:30:00 +0000
ObjectiveCTools[1475:816321] 手机当前时间(转东八): 2020-06-28 10:34:11 +0000
ObjectiveCTools[1475:816321] 服务器日历时间(转东八): 今日6月28日 10时30分
ObjectiveCTools[1475:816321] 手机当前日历时间(转东八): 今日6月28日 10时34分
以下是关于时间,日历,和格式化的尝试代码,不加修饰,有时候是搞出乱子的,还得是格式化,设置时区之后才好用
问题:1、如果单纯只拿时间,那么不会有错,如果加上中文,就有内鬼
可以看到差了8小时。然而写代码的时候,我并不希望出现这么个无聊的8小时问题啊。
- (void)viewDidLoad {
[super viewDidLoad];
[self demo0]; //当前时区在北京
}
- (void)demo0 {
NSDate *datePhone = [NSDate date];
NSLog(@"%@", datePhone);
NSLog(@"加上中文 %@", datePhone);
}
输出
ObjectiveCTools[1367:790862] Mon Jun 28 10:29:26 2020
ObjectiveCTools[1367:790862] 加上中文 2020-06-28 02:29:26 +0000
问题:2、如果从服务器拿到时间字符串,直接转换成SDadate,也还是有内鬼
同样是差了8小时,然而写代码的时候,我并不希望出现这么个无聊的8小时。
- (void)viewDidLoad {
[super viewDidLoad];
[self demo1];
}
- (void)demo1 {
//当前时间是 2020-06-28 10:30 (上午十点半)
NSDate *datePhone = [NSDate date];
NSLog(@"北京时区 手机时间: %@", datePhone);
NSString *timestring = @"2020-06-28 10:30";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm"];
NSDate *dateServer = [formatter dateFromString:timestring];
NSLog(@"北京时区 服务器时间: %@", dateServer);
}
输出
ObjectiveCTools[1371:792380] 北京时区 手机时间: 2020-06-28 02:33:46 +0000
ObjectiveCTools[1371:792380] 北京时区 服务器时间: 2020-06-28 02:30:00 +0000
解决 1、2、 给formatter加上时区就可以了。即便这时候你切换了手机的时区,从北京换到纽约,字符串的时间格式化结果仍然是正常的。
- (void)viewDidLoad {
[super viewDidLoad];
[self demo1];
}
- (void)demo1 {
//当前时间是 2020-06-28 10:30 (上午十点半)
NSDate *datePhone = [NSDate date];
NSLog(@"北京时区 手机时间: %@", datePhone);
NSString *timestring = @"2020-06-28 10:30";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
//给 formatter 加上时区
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:8]];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm"];
NSDate *dateServer = [formatter dateFromString:timestring];
NSLog(@"北京时区 服务器时间: %@", dateServer);
}
输出
ObjectiveCTools[1388:796545] 北京时区 手机时间: 2020-06-28 02:31:08 +0000
ObjectiveCTools[1388:796545] 北京时区 服务器时间: 2020-06-28 10:30:00 +0000
将NSDate设置时区东八。如果要使用当前的NSDate,并且不管手机设置为什么时区,都要取得当前的东八时间,和服务器做比较。
- (void)viewDidLoad {
[super viewDidLoad];
[self demo2];
}
- (void)demo2 {
//当前时间是 2020-06-28 10:30 (上午十点半)
NSDate *datePhone = [NSDate date];
NSLog(@"美国费城 原始 手机时间: %@", datePhone); //输出错误,费城此时应该是 6月27号
NSString *timestring = @"2020-06-28 10:30";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
//给 formatter 加上时区
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:8]];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm"];
NSDate *dateServer = [formatter dateFromString:timestring];
NSLog(@"北京 服务器时间: %@", dateServer);
//格式化本地时间,设置时区
NSTimeZone *GMT8Zone = [NSTimeZone timeZoneWithAbbreviation:@"GMT+0800"];
//NSTimeZone *GMT8Zone = [NSTimeZone timeZoneForSecondsFromGMT:8]; //不要用这句,有毒
NSInteger interval = [GMT8Zone secondsFromGMTForDate:datePhone];
NSDate *localGTM8Date = [datePhone dateByAddingTimeInterval: interval];
NSLog(@"美国费城 格式化 手机时间: %@",localGTM8Date);
}
输出
ObjectiveCTools[1414:803611] 美国费城 原始 手机时间: 2020-06-28 02:48:28 +0000
ObjectiveCTools[1414:803611] 北京 服务器时间: 2020-06-28 10:30:00 +0000
ObjectiveCTools[1414:803611] 美国费城 格式化 手机时间: 2020-06-28 10:48:28 +0000
使用到日历来获取时间的时候,也有需要格式化设定时区的场景。后面不写了,代码直接抄就行。
结语
就这么一个小小的时间。
网友评论