前一篇文章《聊聊时间(2)UNIX时间戳转UTC时间》中,我们详细地解释了如何将一个32位无符号的UNIX时间戳利用软件算法转换成我们可以看得懂的UTC时间。我们说,在STM32F10x系列无万年历功能的RTC系统中,如果要将RTC中的计数值显示出来,那么需要利用UNIX时间戳转UTC时间算法。但是如果需要设置一个时钟的时间,那还需要先将当前时区的时间转换成UTC时间,再将UTC时间转换成UNIX时间戳写入RTC的32位寄存器中。今天的文章,我们就来聊聊如何将UTC时间转换成UNIX时间戳。
UTC时间转换成UNIX时间戳
UTC时间转换成UNIX时间戳的方法其实很简单,因为此条件下输入的年月日是固定的。因此对于这个问题,我们可以直接按照年月日时分的形式进行计算,统计每它们的秒数之和。最后加入最后的秒数就可以得到当前的UNIX时间戳了。我们知道闰年的秒数为31622400s,平年的秒数为31536000s。
程序的设计思路为:
(1)统计从1970年至今一共过了多少平年,多少闰年,统计完成之后,根据闰年和平年的秒数计算出从1970年1月1日至今年一共经过了多少秒。这一部分的代码如图1所示。
图1 闰年和平年秒数转换
(2)计算出当前年份是平年还是闰年,以此推算出从年初到上个月过去了多少天。计算完成之后,可以将本月的到昨天的天数一起统计进来,最终可以将年月日三个单位的秒数一起统计出来。具体代码如图2所示。
图2 月和日转换成UNIX时间戳秒数
(3)将剩余的时分秒利用同样的方式进行累加,最终得出当前的UNIX时间戳。其最终的代码如图3所示。
图3 最终完成的代码。
我们可以简单做个测试,将日期设置成2021年2月5日8时6分7秒,运行程序计算出当前的UNIX时间戳为1612512367s,再将1612512367s时间戳输入到我们上一篇文章中UNIX时间戳转UTC时间的代码里,看看最终结果,如图4所示。
图4 UNIX时间戳和UTC时间互相转换
由图4可知,我们的测试结果完全正确。当然对于这种计算比较繁琐的程序,可以使用单元测试全部测试一遍,以排除深层的BUG。
本文全部代码:
1.timex_test.c
time_tt stCurrentTime;
int main(void)
{
stCurrentTime.year = 2021;
stCurrentTime.month = 2;
stCurrentTime.date = 5;
stCurrentTime.hour = 8;
stCurrentTime.minute = 6;
stCurrentTime.second = 7;
printf("%ds", UTCToUnixTimeStamp(&stCurrentTime));
return 0;
}
UnixTimeStamp_t UTCToUnixTimeStamp(time_tt *time)
{
int FlatYearMonthDay[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int LeapYearMonthDay[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
time_tt *tempTime; //定义临时变量存储时间
int i;
tempTime = time; //指向传入参数
int LeapYearNumber; //平年
int FlatYearNumber; //闰年
int ThisYear;
int LastMonDays = 0;
UnixTimeStamp_t TimeStamp = 0;
/*step1: 统计从1970年至今年,一共包含多少平年和闰年,并且计算其总秒数*/
for ( i = UNIX_TIME_STAMP_YEAR; i < tempTime->year; i ++ )
{
if((((i % 4) == 0) && ((i % 100) != 0)) || ((i % 400) == 0))
{
LeapYearNumber ++;
}
else
{
FlatYearNumber ++;
}
}
TimeStamp = LeapYearNumber * 31622400 + FlatYearNumber * 31536000;
/*step2: 判断今年是平年还是闰年*/
if((((tempTime->year % 4) == 0) && ((tempTime->year % 100) != 0)) || ((tempTime->year % 400) == 0))
{
ThisYear = LEAP_YEAR;
}
else
{
ThisYear = FLAT_YEAR;
}
for ( i = 1; i < tempTime->month; i ++)
{
if(ThisYear == LEAP_YEAR)
{
LastMonDays += LeapYearMonthDay[i];
}
else if(ThisYear == FLAT_YEAR)
{
LastMonDays += FlatYearMonthDay[i];
}
}
LastMonDays = LastMonDays + tempTime->date - 1; //统计当月到昨天为止的天数
TimeStamp += LastMonDays * 86400;
/*step3. 计算出剩余的时分秒*/
TimeStamp += tempTime->hour * 3600;
TimeStamp += tempTime->minute * 60;
TimeStamp += tempTime->second;
return TimeStamp;
}
2.timex_test.h
#ifndef __TIMEX_TEST1_H_
#define __TIMEX_TEST1_H_
#define UNIX_TIME_STAMP_YEAR 1970
#define LEAP_YEAR 1
#define FLAT_YEAR 0
typedef struct
{
int year;
int month;
int date;
int hour;
int minute;
int second;
} time_tt;
typedef unsigned int UnixTimeStamp_t;
UnixTimeStamp_t UTCToUnixTimeStamp(time_tt *time);
#