1、问题

2019年4月6号,由于GPS的周计数溢出,导致很多GPS模块的时间回到了99年,但是GPS模块由于价格便宜,甚至有的GPS模块连原厂都找不到了,这种情况下,那么多物联网的定位产品怎么办呢?

2、解决办法

由于GPS周计数变量采用的是10位的变量,那么也就是说在1024个星期之后,计数器就会从零重新开始计数。这样就导致年份直接倒退了20多年。那么怎么解决这个问题呢。我们在读到GPRMC的报文后,直接在时间的基础上加上一个1024周,相当于帮GPS做一个进位。那么这个问题就解决了。具体实施的时候,该怎么操作?

首先将年月日换算成秒,然后将1024个星期也换成秒,然后相加,然后再把总秒数反算成年月日。这个事情就了了。讲年份换算成秒和秒换算成年份的过程一定要考虑闰年,闰月等相关因素,要不算出来的也是有问题的。当然了,凡事要站在巨人的肩膀上,所以我们直接调用时间库的函数,也就是time.h。

# define _DLIB_TIME_USES_64 1
time_t t1;
struct tm tmin;  
struct tm tmout;
static int WeekOversizeDateChange(char *cDateIn,char *cDateOut)
{


 
  struct tm *tminp=&tmin;
  struct tm *tmoutp=&tmout;

  char tmp[8+1];
  memset(tmp,0,sizeof(tmp));
 // strptime(cDateIn,"%Y%m%d",tminp);

 
  tmin.tm_year = cDateIn[0];
  tmin.tm_mon = cDateIn[1] - 1;
  tmin.tm_mday = cDateIn[2];

/*    tmin.tm_year = 99;
  tmin.tm_mon = 7;
  tmin.tm_mday = 25;
*/  
  /*将tm结构数据转换成1970年1月1日开始计算的秒数*/
  t1=mktime(tminp);
  /*计算需要增加或者减少天数对应的秒数,结果是最终日期对应1970年1月1日开始计算的秒数*/
  t1+=1024*7*60*60*24;
/*将time_t的信息转化真实世界的时间日期表示,结果由结构tm返回*/
  tmoutp=localtime(&t1);

  /*tm类型的时间转换。将tm按照%Y%m%d格式转化赋值到输出中,最大长度8+1*/
  strftime(tmp,8+1,"%Y%m%d",tmoutp);
  strcpy(cDateOut,tmp);
  return 0;

}

有几个问题记录如下:

  1. 关于strptime函数
    IAR编译器里面的time.h里面居然没有这个函数,这还是蛮让人不爽的,这个函数主要是什么作用呢。本来cDateIn和cDateOut都是字符型的数据输入,通过这个函数可以直接把整个的字符型的年月日,换成成10进制的数值,并直接赋值给tm结构体的变量。然后全套调用库函数。但是由于IAR的time.h里面没有这个函数,只能自己把cDateIn编程十进制后,赋值给对应的结构体变量了,然后再进行下一步的操作。
  2. 关于月份
    进入tm结构体,我们可以看到,月份是从0-11表示1-12月份。所以对于常规显示的,我们要减1,然后再参与运算。否则算出来是有问题的。
  3. 关于tm结构体赋值的问题
    struct tm tmin; 这个结构体明显只是个局部变量,并且只在局部函数里面进行运算,按道理说,是不应该定义成全部变量的,但是奇葩的问题就是,如果我定义成局部变量的话,年份换算成秒的数值经常会自己变化。我把这个变量改成全局变量后,就好了。我写到这里的时候,其实我还是有点莫名其妙的。
    结果是这个结构体不能只对年月日进行初始化,还应该对时分秒全部进行初始化,因为在后面的计算秒数的函数里面,时分秒也是要参与运算的,如果不进行初始化的话,后面的值就会一直跳动。