在Keil MDK中无法使用gmtime函数进行时间戳转换

硬件平台STM32,软件平台Keil MDK 5.18

由于项目中需要用到UNIX时间戳和日历的来回转换,于是想到C库函数<time.h>里面有现成的函数可以使用。

于直接使用mktime和gmtime两个函数进行时间戳转换,前者把日历转为时间戳,后者把时间戳转为日历。


但是程序运行起来发现,gmtime得到的日历数据为乱码!!!

经过调试才发现,这个函数返回值是NULL啊!!!

查看反汇编代码,简直惊呆,这是什么鬼操作?

汇编代码没有函数跳转,取而代之的是MOVS R0, #0x00,直接返回0。

看到这一幕,气炸,搞了个假的库函数给我啊。

于是马上又换成另一个时间戳转转函数localtime,经测试发现这个函数工作得很好!


gmtime和localtime的区别就是,gmtime返回的是GMT标准时间,而localtime返回的是本地时间。

何为本地时间?那就是带时区转换的时间,比如北京时间是东8区,与GMT时间相差8小时。

然而MDK库函数并没有直接设置时区的函数,因此locatime返回的仍然是GMT时间。

所以在使时localtime的时候,要先把时间戳加上28800秒(8小时)再进行转换,就能得到北京时间。


最后附上日历和时间戳相互转换的代码:

日历转时间戳

日历转时间戳使用mktime函数,参考代码如下:

void date_to_timestamp(struct date *date, uint32_t *timestamp)
{
	time_t times;
	struct tm tm;
	tm.tm_year = date->year - 1900; //C库函数的年份是从1900开始计算
	tm.tm_mon  = date->month - 1;   //C库函数的月份是用0表示1月
	tm.tm_mday = date->day;
	tm.tm_hour = date->hour;
	tm.tm_min  = date->minute;
	tm.tm_sec  = date->second;
	times = mktime(&tm);
	*timestamp = times - 28800;    //北京时间:东8区偏移值
}

时间戳转日历

时间戳转日历使用localtime函数,参考代码如下:

void timestamp_to_date(uint32_t timestamp, struct date *date)
{
	time_t times;
	struct tm *tm;
	times = timestamp + 28800;
	tm = localtime(&times);
	date->year   = tm->tm_year + 1900;
	date->month  = tm->tm_mon + 1;
	date->day    = tm->tm_mday;
	date->hour   = tm->tm_hour;
	date->minute = tm->tm_min;
	date->second = tm->tm_sec;	
}

PS:如果需要使用毫秒级的时间戳,可以直接把这个秒级的时间戳乘以1000,倒过来则除以1000。