1.什么是内部时钟

     在我们做iOS开发的过程中,我们经常要与时间打交道,[NSDate date]是我们常用的取时间的一种方式,但是[NSDate date]

[NSDate date]取出来的值,还是我们想要的吗???在一些应用的开发中,我们在没有网络的状态下,不能取网络时间,依靠系统时间,是可以篡改的。所以这个时候,我们要自己要在程序的内部定制一个自己的内部时钟。

 

2.实现内部时钟的思路

    1.要有一个时间作为基本的参照点(一般应用都会与服务器打交道,所以发请求给服务器,取服务器的时间是比较合适的)

    2.要有一个标记点(一般取待机时长)

    3.在每次进入程序的时候,或者登录的时候,取服务器的时间存起来,然后再取当前的待机时间存起来,每次要获取当前时间的时候,再取待机时长跟之前的存储的待机时长比较,获得差值。将存储的服务器时间加上差值,就获得想要的当前时间。

 

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这种方法?

答案 :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"];