做一个数据统计功能,客户端需要上报信息中有“时间”字段,因为客户端的时间是不可靠的,所以需要与服务器的时间做同步,开始考虑是这样做的:
1、本地保存需要上报的信息,信息中时间字段是客户端的时间
2、在向服务器上报时候,同时上报客户端当前时间(clientTime)
3、服务器在读取到统计信息以及clientTime以后,根据服务器当前时间(serverTime)与clientTime之间做比较,得出两端时间的差值,然后再对统计信息做一下处理就行了。以上逻辑在用户不修改设备时间的情况下是没问题的,如果修改时间就不行了,然后考虑在修改时间以后看能不能获取到修改时间前后的差值,发现修改时间以后,系统会发送一个广播,但是这个广播中只携带了修改后的时间,而没有修改前的时间,所以前后的差值就得不到了。现在想法是只能自己维护一个“时钟程序”,每隔一分钟就记录一下当前的timestamp,也就是用记录的timestamp来作为时间改变前的时间,当然了,记录间隔越短时间,计算的改变前后的差值也就越精确。各位还有没有更好的办法?求教……服务器时间同步

解决方案 »

  1.   

    楼主是不是讲
    数据在收集的时候 存储数据信息时使用设备时间记录数据的Timestamp 
    等到合适的时候将数据传输到服务器上 然后服务器以自己的时间矫正Timestamp但是在数据收集的过程中 客户可能修改设备系统时间?我想知道的是 精度要求是多高呢?如果要求不高的话可以这样在程序启动的时候获取安卓系统启动到现在的时间 然后推算出系统启动的Timestamp并存储
    监听日期改变和时间改变的广播 收到广播后再次获取安卓系统启动到现在的时间 推算出在新时间下系统启动的Timestamp存储 并算出时间差 
    每次记录的时候顺便把时间差也记录下来
      

  2.   

    因为手机每次reboot之后elapsedTime都会清零,所以在收到时间改变的广播之后用记录的elapsedTime来做计算也是不准确的,不过这个问题可以通过在每次设备开机之后保存当前设备时间跟elapsedTime来解决,但是唯一不完美的地方是还需要加上接收开机启动广播的权限,因为在安装时候用户会疑惑,为什么这东西还需要开机启动?……
    鉴于很少有用户蛋疼的修改自己的时间(时间不准也基本都是在刚买回来用的时候,但也会马上就设置好),所以这个问题就不考虑了,服务器端在统计数据时候先过滤一遍垃圾数据,如果垃圾数据很多,再考虑是否添加“在用户修改时间以后对离线产生的数据做时间同步”的功能。
      

  3.   

    不是很明白,你反正最后都需要上报的,上报就需要联网,那为什么不能用服务器时间。
    对app使用情况做数据统计,开启时间、运行时长等这些数据都是需要记录时间的,app使用过程中不能保证设备的网络连接情况,所以记录中的时间字段都是用的clientTime。
      

  4.   

    因为手机每次reboot之后elapsedTime都会清零,所以在收到时间改变的广播之后用记录的elapsedTime来做计算也是不准确的,不过这个问题可以通过在每次设备开机之后保存当前设备时间跟elapsedTime来解决,但是唯一不完美的地方是还需要加上接收开机启动广播的权限,因为在安装时候用户会疑惑,为什么这东西还需要开机启动?……
    鉴于很少有用户蛋疼的修改自己的时间(时间不准也基本都是在刚买回来用的时候,但也会马上就设置好),所以这个问题就不考虑了,服务器端在统计数据时候先过滤一遍垃圾数据,如果垃圾数据很多,再考虑是否添加“在用户修改时间以后对离线产生的数据做时间同步”的功能。开机启动广播?没必要啊 
    没必要一开机就记录elapsedTime
    既然客户端的时间不准确 不采用
    这样就只需要客户端保证获取的数据的时间间隔是正确的就行了
    也就是说 在用户更改了系统日期时间后 只需要获取每次日期时间的变化值就好了例如 在系统开机1分钟整后用户开启了应用 此时系统时间是2013.04.27 21:00:00.000
    获得SystemClock.elapsedRealtime() = 60000 (1分钟)
    计算出本次开机系统的时间是 2013.04.27 20:59:00.000 (*) 记录这个timestamp 程序运行不知道多久后 收到日期时间改变广播
    获取当前 就也就是改变后的系统时间为 2013.04.27 22:00:00.000 
    获得SystemClock.elapsedRealtime() = 7260000 (2个小时加1分钟)
    计算出以改变后的系统时间的开机时间为 2013.04.27 19:59:00.000 
    和第一个系统时间的timestamp (*)相比较 早了一个小时 说明系统时间调早了一个小时 这样 以后每次用户获取数据的时候 获取的系统时间需要加上一个小时
      

  5.   

    因为手机每次reboot之后elapsedTime都会清零,所以在收到时间改变的广播之后用记录的elapsedTime来做计算也是不准确的,不过这个问题可以通过在每次设备开机之后保存当前设备时间跟elapsedTime来解决,但是唯一不完美的地方是还需要加上接收开机启动广播的权限,因为在安装时候用户会疑惑,为什么这东西还需要开机启动?……
    鉴于很少有用户蛋疼的修改自己的时间(时间不准也基本都是在刚买回来用的时候,但也会马上就设置好),所以这个问题就不考虑了,服务器端在统计数据时候先过滤一遍垃圾数据,如果垃圾数据很多,再考虑是否添加“在用户修改时间以后对离线产生的数据做时间同步”的功能。开机启动广播?没必要啊 
    没必要一开机就记录elapsedTime
    既然客户端的时间不准确 不采用
    这样就只需要客户端保证获取的数据的时间间隔是正确的就行了
    也就是说 在用户更改了系统日期时间后 只需要获取每次日期时间的变化值就好了例如 在系统开机1分钟整后用户开启了应用 此时系统时间是2013.04.27 21:00:00.000
    获得SystemClock.elapsedRealtime() = 60000 (1分钟)
    计算出本次开机系统的时间是 2013.04.27 20:59:00.000 (*) 记录这个timestamp 程序运行不知道多久后 收到日期时间改变广播
    获取当前 就也就是改变后的系统时间为 2013.04.27 22:00:00.000 
    获得SystemClock.elapsedRealtime() = 7260000 (2个小时加1分钟)
    计算出以改变后的系统时间的开机时间为 2013.04.27 19:59:00.000 
    和第一个系统时间的timestamp (*)相比较 早了一个小时 说明系统时间调早了一个小时 这样 以后每次用户获取数据的时候 获取的系统时间需要加上一个小时
    elapsedRealtime在每次设备reboot之后都会清零啊,所以它不是一个能作为参考的值,除非你在每次系统boot complete时候记录一下elapsedRealtime以及当前时间戳。如果我设备从来不断电,那可以,但设备室要重启的啊
      

  6.   

    因为手机每次reboot之后elapsedTime都会清零,所以在收到时间改变的广播之后用记录的elapsedTime来做计算也是不准确的,不过这个问题可以通过在每次设备开机之后保存当前设备时间跟elapsedTime来解决,但是唯一不完美的地方是还需要加上接收开机启动广播的权限,因为在安装时候用户会疑惑,为什么这东西还需要开机启动?……
    鉴于很少有用户蛋疼的修改自己的时间(时间不准也基本都是在刚买回来用的时候,但也会马上就设置好),所以这个问题就不考虑了,服务器端在统计数据时候先过滤一遍垃圾数据,如果垃圾数据很多,再考虑是否添加“在用户修改时间以后对离线产生的数据做时间同步”的功能。开机启动广播?没必要啊 
    没必要一开机就记录elapsedTime
    既然客户端的时间不准确 不采用
    这样就只需要客户端保证获取的数据的时间间隔是正确的就行了
    也就是说 在用户更改了系统日期时间后 只需要获取每次日期时间的变化值就好了例如 在系统开机1分钟整后用户开启了应用 此时系统时间是2013.04.27 21:00:00.000
    获得SystemClock.elapsedRealtime() = 60000 (1分钟)
    计算出本次开机系统的时间是 2013.04.27 20:59:00.000 (*) 记录这个timestamp 程序运行不知道多久后 收到日期时间改变广播
    获取当前 就也就是改变后的系统时间为 2013.04.27 22:00:00.000 
    获得SystemClock.elapsedRealtime() = 7260000 (2个小时加1分钟)
    计算出以改变后的系统时间的开机时间为 2013.04.27 19:59:00.000 
    和第一个系统时间的timestamp (*)相比较 早了一个小时 说明系统时间调早了一个小时 这样 以后每次用户获取数据的时候 获取的系统时间需要加上一个小时
    elapsedRealtime在每次设备reboot之后都会清零啊,所以它不是一个能作为参考的值,除非你在每次系统boot complete时候记录一下elapsedRealtime以及当前时间戳。如果我设备从来不断电,那可以,但设备室要重启的啊
    重启有也没关系啊...
    主要目的是收到时间日期改变广播后计算出时间的变更值啊... 
    elapsedRealtime只是个辅助工具而已啊
      

  7.   

    因为手机每次reboot之后elapsedTime都会清零,所以在收到时间改变的广播之后用记录的elapsedTime来做计算也是不准确的,不过这个问题可以通过在每次设备开机之后保存当前设备时间跟elapsedTime来解决,但是唯一不完美的地方是还需要加上接收开机启动广播的权限,因为在安装时候用户会疑惑,为什么这东西还需要开机启动?……
    鉴于很少有用户蛋疼的修改自己的时间(时间不准也基本都是在刚买回来用的时候,但也会马上就设置好),所以这个问题就不考虑了,服务器端在统计数据时候先过滤一遍垃圾数据,如果垃圾数据很多,再考虑是否添加“在用户修改时间以后对离线产生的数据做时间同步”的功能。开机启动广播?没必要啊 
    没必要一开机就记录elapsedTime
    既然客户端的时间不准确 不采用
    这样就只需要客户端保证获取的数据的时间间隔是正确的就行了
    也就是说 在用户更改了系统日期时间后 只需要获取每次日期时间的变化值就好了例如 在系统开机1分钟整后用户开启了应用 此时系统时间是2013.04.27 21:00:00.000
    获得SystemClock.elapsedRealtime() = 60000 (1分钟)
    计算出本次开机系统的时间是 2013.04.27 20:59:00.000 (*) 记录这个timestamp 程序运行不知道多久后 收到日期时间改变广播
    获取当前 就也就是改变后的系统时间为 2013.04.27 22:00:00.000 
    获得SystemClock.elapsedRealtime() = 7260000 (2个小时加1分钟)
    计算出以改变后的系统时间的开机时间为 2013.04.27 19:59:00.000 
    和第一个系统时间的timestamp (*)相比较 早了一个小时 说明系统时间调早了一个小时 这样 以后每次用户获取数据的时候 获取的系统时间需要加上一个小时
    elapsedRealtime在每次设备reboot之后都会清零啊,所以它不是一个能作为参考的值,除非你在每次系统boot complete时候记录一下elapsedRealtime以及当前时间戳。如果我设备从来不断电,那可以,但设备室要重启的啊
    重启有也没关系啊...
    主要目的是收到时间日期改变广播后计算出时间的变更值啊... 
    elapsedRealtime只是个辅助工具而已啊
    ……
    1、app启动,记录下了timestamp以及elapsedRealtime
    2、设备reboot
    3、用户修改设备时间
    ok,怎么计算
      

  8.   

    ……
    1、app启动,记录下了timestamp以及elapsedRealtime
    2、设备reboot
    3、用户修改设备时间
    ok,怎么计算
    在9楼已经说的很清楚了 换个说法再给你讲一遍
    启动记录的timestamp 和elapsedRealtime 分别记为T1 和t1 
    收到系统通知 再次获取timestamp和elapsedRealtime 分别记为T2 和t2
    T2自然是已经修改完毕的timestampapp启动和用户修改时间 两个事件实际的时间间隔应该为 dt = t2 - t1
    而系统时间显示的时间间隔为 dT = T2-T1
    因为用户修改过系统时间 这两个时间间隔明显不相等 如果 dT-dt > 0 说明用户把系统时间调快了
    反之 dT-dt < 0 说明用户把系统时间调慢了
    具体调快调慢多少 就是这个差值的绝对值 abs(dT-dt)
      

  9.   

    对于你说的在reboot后 app启动之前进行的重启
    对开机广播进行监听也无法解决这个问题
    只能从其他方面解决
    例如app启动的时候向服务器要一个时间之类
      

  10.   

    anyway, thanks so much for your attention