设计新闻发布网站模板/东莞网络推广
推荐一个不错的AI教程: https://www.captainbed.net/blog-vincent/
一、导读
0.千年虫
计算机2000年问题,又叫做“千年虫”、“电脑千禧年千年虫问题”或“千年危机”。在某些使用了计算机程序的智能系统(包括计算机系统、自动控制芯片等)中,由于其中的年份只使用两位十进制数来表示,因此当系统进行(或涉及到)跨世纪的日期处理运 算时(如多个日期之间的计算或比较等),就会出现错误的结果,进而引发各种各样的系统功能紊乱甚至崩溃。
1.GPS概述
Global Positioning System。简单地说,它是一个由覆盖全球的24颗卫星组成的卫星系统。这个系统可以保证在任意时刻,地球上任意一点都可以同时观测到4颗卫星,以保证卫星可以采集到该观测点的经纬度和高度,以便实现导航、定位、授时等功能。这项技术可以用来引导飞机、船舶、车辆以及个人,安全、准确地沿着选定的路线,准时到达目的地。
2.gps时间
gps时间 = 周数 + 秒数
1)“周数”:gps的导航电文中提供了当前时刻所在的“周数”,这个周数是从北斗或者GPS系统的起始时间()开始计数的。
2)“秒数”:通过调制在载波上的伪随机码的码片可以知道当前的周内秒。
二、“gps时间翻转”
“导读”过后,您是否也在纳闷,“千年虫事件”和“gps时间”之间,有什么瓜葛吗?当我尝试google了“gps时间翻转”这个key word后,一阵凉意掠过了我年少的心头……
从“导读”部分我们了解到,GPS的时间计数由周和秒组成,一周等于 604800 秒,也就是说每当秒数记录到 604800 就会归零,周计数会 +1 周。
周数同理,GPS 里周的计数只用了 10 位二进制数字来表达,也就是说上限只能计 2 的 10 次方 -- 即1024 周,当前GPS周期已于2019年4月6日回归到零上,上一次的时间翻转还是在1999年8月1日。
如果接收 GPS 授时设备的厂商没有提前做准备,那可能一个不留神设备的时间就滚回 19 年前了,要知道在例如航天、电力、金融、股票等对时间很敏感的领域里,时间错误就是灾难。。。
值得一提的是,我国的北斗系统(BDS)的周计数数据字段长度为13位,周计数翻转周期为8192周,约157年,其授时系统的周计数自2006年1月1日起计时,下一个北斗时间周计数翻转将在2163年发生。且在GPS现代化计划中,为了改善周数翻转的情况,消息类型(CNAV和MNAV)使用13比特字段来表示GPS周数,而使用该13比特字段的新GPS接收机在1024周时期内不会出现问题。
三、规避策略
1.场景:小编从事车联网行业,车端tbox、车载系统的时间都读取自gps,之后将读取到的时间,伴随着其他车况信息实时上报给云端系统,云端做数据存储。
2.规避方案:
1)车端程序处理,保证上传给云端时间是正确的
2)云端处理,车端透传。(借鉴高德地图的处理方案,在GPS周数翻转时刻,采用系统时间和GPS对比的方法,如果二者相差超过一年,则时分秒取GPS时间,年月日取系统时间,以解决周数翻转带来的时间跳变问题使开发者内部用错时间)
package com.amap.api.location;import java.util.Calendar;
import java.util.Date;public class DateUtil {private static final long DAY_IN_MILLIS = 24 * 60 * 60 * 1000;/*** 入口* 校正gps时间* @param gpsTime 原始的gps时间* @return*/public static long correctGpsTime(long gpsTime) {if(Math.abs(gpsTime - System.currentTimeMillis()) > 365 * 24 * 60 * 60 * 1000) {return getNewGpsTime(gpsTime);} else {return gpsTime;}}/*** 获取新的GPS时间* @param gpsTime 原始的gps时间* @return*/private static long getNewGpsTime(long gpsTime) {//系统时间当前时间戳long sysTime = System.currentTimeMillis();//从GPS时间戳中获取当前0点到现在的毫秒数long millisSecondOfDayInGps = getMillisSecondOfDay(gpsTime);//newTime = 系统时间到当天零点毫秒数 + gps 0点到现在的毫秒数long newTime = getDayInMillis(sysTime) + millisSecondOfDayInGps;//系统时间与计算出的gps时间差值long absTime = Math.abs(newTime - sysTime);Calendar calendar = Calendar.getInstance();calendar.setTime(new Date(newTime));int hour = calendar.get(Calendar.HOUR_OF_DAY);//差值阈值, 23小时long diffMillisThreshold = 23 * 60 * 60 * 1000;//解决跨0点问题, 0点收到昨天23点的数据if (hour == 23 && absTime >= diffMillisThreshold) {//减去一天时间newTime -= DAY_IN_MILLIS;}//解决跨0点问题, 23点收到明天0点的数据if (hour == 0 && absTime >= diffMillisThreshold) {//加上一天时间newTime += DAY_IN_MILLIS;}return newTime;}/*** 从时间戳中获取当天0点到现在的毫秒数(只取时分秒)* @param time* @return*/private static long getMillisSecondOfDay(long time){Calendar calendar = Calendar.getInstance();calendar.setTime(new Date(time));calendar.set(Calendar.HOUR_OF_DAY, 0);calendar.set(Calendar.MINUTE, 0);calendar.set(Calendar.SECOND, 0);calendar.set(Calendar.MILLISECOND, 0);long newTime = calendar.getTimeInMillis();return (time - newTime);}/*** 从时间戳中获取从1970.1.1号到当天0点的毫秒数(只取年月日)* @param time* @return*/private static long getDayInMillis(long time) {Calendar calendar = Calendar.getInstance();calendar.setTime(new Date(time));calendar.set(Calendar.HOUR_OF_DAY, 0);calendar.set(Calendar.MINUTE, 0);calendar.set(Calendar.SECOND, 0);calendar.set(Calendar.MILLISECOND, 0);long newTime = calendar.getTimeInMillis();return newTime;}}
四、写在最后
你要是觉得 GPS 老因为这个缺陷麻烦人很不爽的话,用北斗呀 ~ 我国的北斗系统现在非常成熟了,不少国内厂家都已经开始转北斗授时了 ~