STM32平台下Keil MDK 5.18中UNIX时间戳与日历转换问题及解决方案
硬件平台STM32,软件平台Keil MDK 5.18

项目中需要进行 UNIX 时间戳与日历的相互转换,所以想到 C 库函数中存在现成可用的函数。
直接使用 mktime 和 gmtime 这两个函数来进行时间戳转换。mktime 函数是将日历转为时间戳,而 gmtime 函数则是将时间戳转为日历。
但是运行程序后发现,gmtime 所获取到的日历数据呈现出乱码的状态。
经过调试才发现,这个函数返回值是NULL啊!!!
查看反汇编代码,简直惊呆,这是什么鬼操作?
然后直接返回 0 。
看到这一幕,气炸,搞了个假的库函数给我啊。
于是立刻更换为另一个时间戳转转函数 localtime ,经过测试后发现这个函数运行得很良好。
gmtime 所返回的是 GMT 标准时间,localtime 所返回的是本地时间,这就是 gmtime 和 localtime 的区别。
本地时间是什么呢?它是带有时区转换的时间。例如,北京时间属于东 8 区,和 GMT 时间相差 8 小时。
MDK 库函数没有直接设置时区的相关函数,所以 locatime 所返回的依然是 GMT 时间。
在使用 localtime 的时候,需要先将时间戳加上 28800 秒(8 小时),然后再进行转换,这样就能得到北京时间。
最后附上日历和时间戳相互转换的代码:
日历转时间戳
日历转时间戳使用mktime函数,参考代码如下:
获取一个指向 struct date 结构体的指针 date 和一个指向 uint32_t 类型的指针 timestamp ,将 date 所指向的结构体中的日期信息转换为时间戳,并将结果存储到 timestamp 所指向的地址中 。
{
time_t times;
struct tm tm;
tm.tm_year 等于 date 指向的年份减去 1900;C 库函数的年份是以 1900 年为起始开始计算的
tm.tm_mon 等于 date 指向的结构体中的月份减去 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函数,参考代码如下:
将时间戳 timestamp 转换为日期并存储到结构体 date 中。
{
time_t times;
struct tm *tm;
times = timestamp + 28800;
tm = localtime(×);
将年份赋值给 date->year ,具体是将 tm 结构体中的 tm_year 加上 1900 后赋值给 date->year 。
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;
}
如果需要使用毫秒级的时间戳,那么可以直接将这个秒级的时间戳乘以 1000。反之,如果要将毫秒级的时间戳转换为秒级的时间戳,则需要将其除以 1000。