工作中用到了time库。记下一些问题和分析,供自己以后回忆也分享给大家。
这里用Arduino的time库做示例。
首先,几个容易搞混淆的概念。
时间库内几乎所有的数据都在以下两个数据类型之间相互转换。
1.时间类型time_t
时间类型time_t虽然只是一个32位无符号整数,但该类型的数据均代表从2000年1月1日0点0分起开始计时的秒数。(视情况而定。Unix时间是从1970年1月1日0点0分开始计数的有符号整数。这方面不同的库其实implement不同的实现,不需要多在意)
2.时间结构体tm
struct tm {
int8_t tm_sec; /**< seconds after the minute - [ 0 to 59 ] */
int8_t tm_min; /**< minutes after the hour - [ 0 to 59 ] */
int8_t tm_hour; /**< hours since midnight - [ 0 to 23 ] */
int8_t tm_mday; /**< day of the month - [ 1 to 31 ] */
int8_t tm_wday; /**< days since Sunday - [ 0 to 6 ] */
int8_t tm_mon; /**< months since January - [ 0 to 11 ] */
int16_t tm_year; /**< years since 1900 */
int16_t tm_yday; /**< days since January 1 - [ 0 to 365 ] */
int16_t tm_isdst; /**< Daylight Saving Time flag */
};
可以看到所有项均很好理解,除了tm_year。tm_year代表了从1900年开始计算的年数(即2018年时该项的值为2018-1900 = 118)。
虽然因为时区不同,夏令时不同等原因将导致各地日期时间均不相同,然而UTC(标准时间)所有人都一样。所以一切系统时间以UTC为准。再通过函数将系统时间转换为UTC时间结构体或本地时间结构体。
第一次使用time库需要做一些设置。
设置相关函数:
时区设置:
void set_zone(int32_t);
时区设置函数使用参数(ONE_HOUR*时区)。ONE_HOUR为一小时的秒数,所以直接用3600也可。
比如中国为+8区,则
set_zone(ONE_HOUR * 8);
时区设置将影响
struct tm *localtime(const time_t * timer);
所返回的tm结构体和其他将会被转换为本地时间结构体/解析本地时间结构体返回系统时间的函数。
夏令时设置:
void set_dst(int (*) (const time_t *, int32_t *));
夏令时可不设置。默认没有。
系统时间设置:
void set_system_time(time_t timestamp);
系统时间设置时参数为一个time_t(uint32_t)数。若写入当前时间的time_t值则系统时间将更新为当前时间。若该值来源不同(UNIX时间或其他不同格式)则加相应的OFFSET。
时间维护:
void system_tick(void);
这个函数非常重要。我之前因为没使用这个函数导致系统时间不走。这个函数需放入系统的一个1s的中断函数中,才能让系统时间开始工作。在windows或其他系统下,这个函数很可能已经被系统维护了,所以并不需要在意。但是自己开发的嵌入式系统/程序里则要记得自行维护这个函数。
剩下就是使用了。
time_t time(time_t *timer); //获取当前系统时间
time_t mktime(struct tm * timeptr); //将一个tm结构体转变成time_t。使用此函数时,被
//转换的源tm结构体被认为是本地时间。使用时只需填
//充基本时间(年月日时分秒)。填充其他项将被忽
//略,且会被改写为合适的值。
time_t mk_gmtime(const struct tm * timeptr); //与上一个类似,不同处在于源tm结构体
//被认为时UTC时间。且成功转换后不会改
//写其他项。
struct tm *gmtime(const time_t * timer); //将time_t转换为tm结构体。表达为UTC时间。
struct tm *localtime(const time_t * timer); //同上。表达为本地时间。
char *asctime(const struct tm * timeptr); //将tm结构体转换为ascii字符串。