前一篇文章《聊聊時間(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 0typedef 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);#
