前言
写此文章是因为有的嵌入式设备编程时不支持<time.h>
,所以有些时间转换的函数必须自己实现。
关于<time.h>
的使用,可以参考我的另一篇博客C语言常用时间相关函数。
为了区别标准库函数,我们自定义的函数会加上self。
自定义的函数肯定会有人担心正确性,文末有验证测试代码。
在看代码之前,必须熟悉struct tm
结构体
struct tm
{
int tm_sec; /* 秒 – 取值区间为[0,59] */
int tm_min; /* 分 - 取值区间为[0,59] */
int tm_hour; /* 时 - 取值区间为[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
int tm_year; /* 年份,其值等于实际年份减去1900 */
int tm_wday; /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一 */
int tm_yday; /* 从每年1月1日开始的天数– 取值区间[0,365],其中0代表1月1日 */
int tm_isdst; /* 夏令时标识符,夏令时tm_isdst为正;不实行夏令时tm_isdst为0 */
};
self_mktime()
unsigned int self_mktime(struct tm tm_now)
{
const unsigned int year0 = tm_now.tm_year+1900;
const unsigned int mon0 = tm_now.tm_mon+1;
const unsigned int day = tm_now.tm_mday;
const unsigned int hour = tm_now.tm_hour;
const unsigned int min = tm_now.tm_min;
const unsigned int sec = tm_now.tm_sec;
unsigned int mon = mon0, year = year0;
/* 1..12 -> 11,12,1..10 */
if (0 >= (int) (mon -= 2)) {
mon += 12; /* Puts Feb last since it has leap day */
year -= 1;
}
return ((((unsigned int)
(year/4 - year/100 + year/400 + 367*mon/12 + day) +
year*365 - 719499
)*24 + hour /* now have hours */
)*60 + min /* now have minutes */
)*60 + sec; /* finally seconds */
}
self_gmtime()
void self_gmtime(struct tm *tm_time, unsigned int timestamp)
{
unsigned int four_year_num; // 有多少个四年
unsigned int one_year_hours; // 一年的小时数
const static unsigned char Days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const static unsigned int ONE_YEAR_HOURS = 8760; // 8760 = 365 * 24 (一年的小时数 非闰年)
const static unsigned int FOUR_YEAR_HOURS = 35064; // 35064 = (365 * 3 + 366) * 24 (四年的小时数)
if (timestamp > 0x7FFFFFFF)
{
return;
}
tm_time->tm_isdst = 0;
tm_time->tm_sec = (int)(timestamp % 60); // 计算秒
timestamp /= 60;
tm_time->tm_min = (int)(timestamp % 60); // 计算分
timestamp /= 60;
tm_time->tm_wday = (int)(timestamp/24 + 4) % 7; // 计算星期 1970年1月1日星期四
four_year_num = timestamp / FOUR_YEAR_HOURS;
tm_time->tm_year=(four_year_num << 2) + 70; // 计算年
timestamp %= FOUR_YEAR_HOURS; // 不足四年的小时数
while (1)
{
one_year_hours = ONE_YEAR_HOURS;
if ((tm_time->tm_year & 3) == 0) // 判断闰年
{
one_year_hours += 24;
}
if (timestamp < one_year_hours)
{
break;
}
tm_time->tm_year++;
timestamp -= one_year_hours;
}
tm_time->tm_hour=(int)(timestamp % 24); // 计算时
timestamp /= 24; // 一年中剩下的天数
timestamp++;
tm_time->tm_yday = timestamp-1; // 计算天
if ((tm_time->tm_year & 3) == 0) // 闰年处理
{
if (timestamp > 60)
{
timestamp--; // 因为有1月29日的存在
}
else if (timestamp == 60)
{
tm_time->tm_mon = 1; // 计算月
tm_time->tm_mday = 29; // 计算日
return;
}
}
// 计算日月
for (tm_time->tm_mon = 0; Days[tm_time->tm_mon] < timestamp; tm_time->tm_mon++)
{
timestamp -= Days[tm_time->tm_mon];
}
tm_time->tm_mday = (int)(timestamp);
}
测试代码
平台:Windows10
CPU:i5-7400
GCC: 8.1.0
耗时:246.441秒
结果:输出passed,通过!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main()
{
time_t i;
struct tm test_time1, *test_time2;
unsigned int test_timestamp;
for (i = 0; i <= 0x7FFFFFFF; i++)
{
self_gmtime(&test_time1, i);
test_time2 = gmtime(&i);
if (test_time1.tm_year != test_time2->tm_year ||\
test_time1.tm_mon != test_time2->tm_mon ||
test_time1.tm_mday != test_time2->tm_mday ||
test_time1.tm_hour != test_time2->tm_hour ||
test_time1.tm_min != test_time2->tm_min ||
test_time1.tm_sec != test_time2->tm_sec ||
test_time1.tm_wday != test_time2->tm_wday ||
test_time1.tm_yday != test_time2->tm_yday)
{
printf("gmtime not passed i = %ld\r\n", i);
break;
}
test_timestamp = self_mktime(test_time1);
if (test_timestamp != i)
{
printf("mktime not passed i = %ld\r\n", i);
break;
}
}
if (i > 0x7FFFFFFF)
{
printf("passed\r\n");
}
return 0;
}