1.什么是内部时钟
在我们做iOS开发的过程中,我们经常要与时间打交道, [NSDate date] 是我们常用的取时间的一种方式,但是 [NSDate date] 这种方式只能取系统的当前时间。也就是说:当前我们手机的时间是什么时间,取出来的值,就是多少。
如果用户把系统的时间改了呢?那么 [NSDate date] 取出来的值,还是我们想要的吗???在一些应用的开发中,我们在没有网络的状态下,不能取网络时间,依靠系统时间,是可以篡改的。所以这个时候,我们要自己要在程序的内部定制一个自己的内部时钟。
2.实现内部时钟的思路
1.要有一个时间作为基本的参照点(一般应用都会与服务器打交道,所以发请求给服务器,取服务器的时间是比较合适的)
2.要有一个标记点(一般取待机时长)
3.在每次进入程序的时候,或者登录的时候,取服务器的时间存起来,然后再取当前的待机时间存起来,每次要获取当前时间的时候,再取待机时长跟之前的存储的待机时长比较,获得差值。将存储的服务器时间加上差值,就获得想要的当前时间。
0.用到的宏:
//开机时间 #define SWStartTime @"startTime" //服务器时间 #define SWServerTime @"serverTime" //登录时的待机时长 #define SWSinceNow @"sinceNow"
1.获取待机时长
/** * 待机时间(从系统启动的那一刻开始获取的时间间隔) */ + (time_t)uptime { struct timeval boottime; int mib[2] = {CTL_KERN, KERN_BOOTTIME}; size_t size = sizeof(boottime); time_t now; time_t uptime = -1; (void)time(&now); if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) { uptime = now - boottime.tv_sec; } return uptime; }
2.存储服务器时间及待机时长
/** * 存储服务器时间及待机时长 * * @param serverTime 服务器时间 */ + (void)firstTimeWithLogin:(NSString *)serverTime { NSTimeInterval timer = (NSTimeInterval)[self uptime]; NSString *sinceNow = [NSString stringWithFormat:@"%f",timer]; NSUserDefaults *UserDefaults = [NSUserDefaults standardUserDefaults]; //存储登录时获取的服务器时间 [UserDefaults setObject:serverTime forKey:SWServerTime]; //存储登录时获取的待机时长 [UserDefaults setObject:sinceNow forKey:SWSinceNow]; }
3.获得当前的时间(以服务器时间为基准)
+ (NSDate *)dateOfNow { NSDateFormatter *formatter = [[NSDateFormatter alloc]init]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSUserDefaults *UserDefaults = [NSUserDefaults standardUserDefaults]; //取出登录时获取的服务器时间 NSString * serverText = [UserDefaults objectForKey:SWServerTime]; NSDate *FirstServer = [formatter dateFromString:serverText]; NSString *firstText = [UserDefaults objectForKey:SWSinceNow]; CGFloat first = firstText.floatValue; NSTimeInterval timer = (NSTimeInterval)[self uptime]; CGFloat second = (CGFloat)timer; //差值 CGFloat finaly = second - first; NSTimeInterval interval = (NSTimeInterval)finaly; //最后的时间 NSDate *finalyDate = [FirstServer dateByAddingTimeInterval:interval]; return finalyDate; }
4.深度探讨
答案 :SystemUptime这种获取待机时间的方式在我们设备深度睡眠的时候,获取的值会有误差,而上面我所用的方法不会。亲测!!!
答案 :
/** * 获得开机时间 */ + (NSString *)getUpTime{ NSString * proc_useTiem; int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, 0}; size_t miblen = 4; size_t size; //返回0,成功;返回-1,失败 int st = sysctl(mib, miblen, NULL, &size, NULL, 0); struct kinfo_proc * process = NULL; struct kinfo_proc * newprocess = NULL; do { size += size / 10; newprocess = realloc(process, size); if (!newprocess) { if (process) { free(process); process = NULL; } return nil; } process = newprocess; st = sysctl(mib, miblen, process, &size, NULL, 0); } while (st == -1 && errno == ENOMEM); if (st == 0) { if (size % sizeof(struct kinfo_proc) == 0) { int nprocess = size / sizeof(struct kinfo_proc); if (nprocess) { for (int i = nprocess - 1; i >= 0; i--) { @autoreleasepool{ //进程的时间 double t = process->kp_proc.p_un.__p_starttime.tv_sec; double s = process->kp_proc.p_un.__p_starttime.tv_usec; double finaly = t + s *0.000001; //将其转为具体时间 proc_useTiem = [self timeWithBoot:finaly]; } } free(process); process = NULL; return proc_useTiem; } } } return nil; }
/** * 转为具体时间 */ + (NSString *)timeWithBoot:(double)interval { NSDateFormatter *format = [[NSDateFormatter alloc]init]; format.timeZone = [NSTimeZone timeZoneWithName:@"shanghai"]; [format setDateStyle:NSDateFormatterMediumStyle]; [format setTimeStyle:NSDateFormatterShortStyle]; //注意先后顺序 [format setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; NSDate *date = [NSDate dateWithTimeIntervalSince1970:interval]; NSString *bootTime = [format stringFromDate:date]; return bootTime; }
PS:如有问题请留言或关注我的新浪微博 http://weibo.com/3216725234 私信我!!!!