深度揭秘(unix時間戳轉(zhuǎn)換成時間命令)unix時間戳轉(zhuǎn)換成時間指令,聊聊時間(2)硬核算法篇——UNIX時間戳轉(zhuǎn)UTC時間,巧連神數(shù),
目錄:
1.unix時間戳轉(zhuǎn)換成時間指令
2.unix時間戳轉(zhuǎn)換工具
3.unix時間轉(zhuǎn)換器
4.unix時間戳格式
5.unix時間換算
6.unix時間戳 時區(qū)
7.unix時間戳當(dāng)前時間
8.unix時間轉(zhuǎn)換為時間戳
9.unix時間戳轉(zhuǎn)換成時間公式
10.unix時間戳轉(zhuǎn)換公式
1.unix時間戳轉(zhuǎn)換成時間指令
文/Edward前一篇文章《聊聊時間(1)UNIX時間戳和UTC時間》中,我們講述了計算機中UNIX時間戳和UTC時間的基本概念,以及簡要地闡述了諸如STM32F103之類芯片簡單功能RTC的時間轉(zhuǎn)換問題,這篇文章將會夾帶慢慢的干貨,詳細地討論UTC時間和Linux時間戳轉(zhuǎn)換的算法,這個經(jīng)典的算法必將愛戀下載使你有一天會受用。
2.unix時間戳轉(zhuǎn)換工具
1 32位的UNIX時間戳我們之前的文章有介紹過UNIX操作系統(tǒng)是伴隨著C語言一起誕生的,其誕生的時間大致是在20世紀(jì)70年代左右,當(dāng)時的計算機都是以8位,16位的數(shù)據(jù)寬度去處理數(shù)據(jù)的,因此在當(dāng)時那個年代,找一個32位的寄存器來存儲時間,是一件比較奢侈的事情。
3.unix時間轉(zhuǎn)換器
最早的UNIX時間戳就只是用一個32位的寄存器來存儲的而UNIX時間戳規(guī)定,UTC/GMT的1970年1月1日0時0分0秒為UNIX時間戳的起始計數(shù)時刻,即UNIX時間戳從這個時間點開始技術(shù)由于使用的變量是一個32位的二進制數(shù),因此這個計數(shù)器的最大計數(shù)長度為2^32=4,愛戀下載294,967,296s,所以在UNIX時間戳的誕生之初,它最大時間只能累積計數(shù)到2038年左右。
4.unix時間戳格式
但是,這是不是說到了2038年這個計數(shù)器溢出之后會發(fā)生類似“千年蟲”之類的危機呢?這個問題,大家無需杞人憂天,因為現(xiàn)在的桌面和移動處理器早已經(jīng)跨入64位CPU時代了,這個UNIX時間戳計數(shù)器的長度也早已經(jīng)被擴充到64位。
5.unix時間換算
而我們今天使用32位的UNIX時間戳計數(shù)器,完全是為了類似STM32這種處理器來講述的
6.unix時間戳 時區(qū)
圖1 溢出 2 UNIX時間戳轉(zhuǎn)UTC時間2.1 時分秒的轉(zhuǎn)換前面我們已經(jīng)說過,UNIX時間戳是以UTC/GMT時間的1970愛戀下載年1月1日0時0分0秒為起始時刻進行計數(shù)的考慮到這個UNIX時間戳的計數(shù)器的數(shù)據(jù)長度為32位,我們不妨先將這個UNIX時間戳計數(shù)器定義為一個變量,其名稱為“u32UnixTimeStamp”。
7.unix時間戳當(dāng)前時間
首先,基于上述的闡述,我們思考下,當(dāng)這個1970年1月1日0時0分0秒時刻過了1s,那么“u32UnixTimeStamp”變量的值也會自加1,變成1隨著時間的流逝,“u32UnixTimeStamp”的值不斷地自加,當(dāng)“u32UnixTimeStamp”變成60的時候,我們回過頭來再看看UTC時間,由于此時已經(jīng)過了60s,因此UTC時間的秒數(shù)值將會溢出被清掉,分?jǐn)?shù)值將會被置1。愛戀下載
8.unix時間轉(zhuǎn)換為時間戳
這個時候UTC的時間變成了1970年1月1日0時1分0秒.再隨著時間的流逝,當(dāng)“u32UnixTimeStamp”的值變成3600的時候,此時1個小時已經(jīng)悄然流逝,這個時候UTC的時間變成了1970年1月1日1時0分0秒。
9.unix時間戳轉(zhuǎn)換成時間公式
86400秒流逝之后,“u32UnixTimeStamp”的值變成86400,此時正好24個小時過去,此時UTC時間變成了1970年1月2日0時0分0秒其實,當(dāng)UNIX時間戳的計數(shù)值小于86400的時候,我們很容易就能寫出轉(zhuǎn)換成UTC時間的程序,因為小時數(shù)就是“u32UnixTimeStamp”對3200取模,分?jǐn)?shù)就愛戀下載是將不能湊滿小時的“u32UnixTimeStamp”對60取模,剩余不能湊滿分?jǐn)?shù)的“u32UnixTimeStamp”即為當(dāng)前時間的秒數(shù),具體代碼如圖2所示。
10.unix時間戳轉(zhuǎn)換公式
圖2 計算一天之內(nèi)時分秒的代碼#include#include"timex_test1.h"utc_t UtcTime;intmain(void){int retVal;int u32UnixTimeStamp =
0;int hour, minute, sec;printf("input the UNIX time stamp:");scanf("%d", &u32UnixTimeStamp);if(u32U愛戀下載nixTimeStamp >=
86400) {printf("input out of range!\n"); retVal = 1; }else { hour = u32UnixTimeStamp / 3600
; //計算小時 minute = (u32UnixTimeStamp - hour * 3600) / 60; //計算分 sec = (u32UnixTimeStamp - hour *
3600 - minute * 60); //計算秒 UtcTime.year = 1970; UtcTime.month = 1; UtcTime.date = 1; UtcTime.hour =愛戀下載
0 + hour; UtcTime.minute = 0 + minute; UtcTime.second = 0 + sec;printf("\nUTC time is : %dy - %dm - %dd\n"
, UtcTime.year, UtcTime.month, UtcTime.date);printf("\nUTC time is : %dh - %dm : %ds\n", UtcTime.hour, UtcTime.minute, UtcTime.second);
retVal = 0; }return retVal;}#ifndef __TIMEX_H_#define __TIM愛戀下載EX_H_/*定義UTC時間結(jié)構(gòu)體類型*/typedefstruct{int
year;int month;int date;int hour;int minute;int second;} utc_t;#endif?以上的代碼是計算“u32UnixTimeStamp”小于86400時當(dāng)前UTC時間的時分秒代碼。
其實,細心的讀者可能會發(fā)現(xiàn),這個86400數(shù)值代表的即是一天之內(nèi)的UTC時分秒,那么如果當(dāng)前的“u32UnixTimeStamp”計數(shù)值大于86400,我們該怎么處理呢?我們先來從最簡單的情況來推導(dǎo)如果一個“u32UnixTimeStamp”為86401,那么此時我們可以知道,這個UNI愛戀下載X時間戳其實就是86400 + 1,已知當(dāng)“u32UnixTimeStamp”為86400時,UTC時間將會變成1970年1月2日0時0分0秒,那么此時86401即為1970年1月2日0時0分0秒 + 1秒,即1970年1月2日0時0分1秒。
由這個簡單的推導(dǎo),我們又可以將大于86400的數(shù)值拉到0~86400的范圍之內(nèi)了,同時,還可以得到一個和日期相關(guān)的“原子”單位,即“日”2.2 年月日的轉(zhuǎn)換接下來,我們將要再對“日”的上一層單位進行討論,即“月”數(shù)值,這也將是這個程序最為復(fù)雜的一部分內(nèi)容。
這個復(fù)雜點主要體現(xiàn)在兩個方面: (1)每個月的天數(shù)不等眾所周知,一年中每個月的天數(shù)都是不愛戀下載同的,1,3,5,7,8,10,12為大月,一個月有31天;4,6,9,11為小月,一個月有30天 (2)閏年平年的影響。
由于公歷的偏差,導(dǎo)致了一年中最為特殊的一個月份2月,當(dāng)此年為閏年時,2月份有29天,此年為平年時,2月份有28天上面兩個原因,導(dǎo)致了年月日計算的復(fù)雜性但是,困難只是表面上的,我們仔細思考下,就很容易得出規(guī)律。
這個規(guī)律的突破口即為閏年出現(xiàn)的時間,因為閏年每四年出現(xiàn)一次,那么我們可以列出從1970年開始的幾個年份如圖3所示
圖3 1970年開始的年份閏年平年分布由于閏年每四年出現(xiàn)一次,因此我們由圖3中可以得出一個簡單方法,即可以從1790年開始,每四年組成一個集合,愛戀下載每一個集合的都是由1年閏年加上3年平年組成的,它們的時間都是相等的,即126230400秒。
因此這個月數(shù)的求解步驟就可以變成: (1)計算從1970年開始到當(dāng)前的UNIX時間戳為止,一共過了多少個“集合年(平年+閏年)”; (2)計算出當(dāng)前的UNIX時間戳位于本“集合年“的哪一年,這樣就可以判斷當(dāng)年年份是平年還是閏年;
(3)判斷了當(dāng)前年份是平年還是閏年之后,就可以推算出2月份有多少天,然后可以根據(jù)上述的遞歸法,求解出當(dāng)前位于某一月,某一天。首先,我們先來寫代碼,求出當(dāng)前的年份。如圖4所示。
圖4 計算當(dāng)前年份代碼得出當(dāng)前年份之后,我們就可以很容易使用“能被4整除且不能愛戀下載被100整除,或者能被400整除的年份是閏年”這一條規(guī)則算出當(dāng)年年份是閏年還是平年接著,我們可以直接將當(dāng)前年份剩余的時間戳結(jié)合平年還是閏年,查表計算出當(dāng)前的月份。
最后代碼如圖5所示。
圖5 UNIX時間戳轉(zhuǎn)UTC時間代碼#include#include"timex_test2.h"utc_t UtcTime;intmain(void){int retVal;int u32UnixTimeStamp =
0;int hour, minute, sec;int flat_year_month_day[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 3愛戀下載0,
31};int leap_year_month_day[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int year_temp =
0;int day_temp = 0;unsignedint cnt_temp = 0;int is_leap_or_flat_year;int i;printf("input the UNIX time stamp:"
);scanf("%d", &u32UnixTimeStamp); cnt_temp = u32UnixTimeStamp;/*判斷當(dāng)前UNIX時間戳經(jīng)過了多少個4年*/wh愛戀下載ile(cnt_temp >=
126230400) { year_temp ++; cnt_temp = cnt_temp - 126230400; }/*計算出當(dāng)前的4年周期起始年份*/ UtcTime.year = UNIX_TIME_YEAR + (
4 * year_temp); /*計算出當(dāng)前的年份*//*這部分代碼可使用循環(huán)做精簡,為了直觀,我將其寫開*/if(cnt_temp >= 31536000) { UtcTime.year ++;
cnt_temp -= 31536000;/*Flat year*/if(cnt_temp >= 31536000) { UtcTime.year愛戀下載 ++; cnt_temp -=
31536000;/*Leap year*/if(cnt_temp >= 31622400) { UtcTime.year ++; cnt_temp -= 31622400
;/*Flat year*/if(cnt_temp >= 31536000) { UtcTime.year ++; cnt_temp -= 31536000
; } } } }/*計算當(dāng)前年份是平年還是閏年*/if((((UtcTime.year % 4) == 0) && ((UtcTime.year % 100) !=
0)) || ((UtcTime.year % 400) == 0)) {愛戀下載 is_leap_or_flat_year = LEAP_YEAR; }else { is_leap_or_flat_year = FLAT_YEAR;
} /*計算出不足一年剩余的天數(shù)*/ day_temp = cnt_temp / 86400;/*剩余不足86400s的時間戳,計算出時間*/ UtcTime.hour = (cnt_temp - day_temp *
86400) / 3600; //Calculate hours UtcTime.minute = (cnt_temp - day_temp * 86400 - UtcTime.hour *
3600) / 60; //Calcul愛戀下載ate minutes UtcTime.second = cnt_temp % 60; /*將天數(shù)結(jié)合平年還是閏年查表計算出當(dāng)前的月份*/ UtcTime.month =
1;for(i = 0; i = flat_year_month_day[i +
1]) { UtcTime.month ++; day_temp -= flat_year_month_day[i + 1]; } } elseif
(is_leap_or_flat_year == LEAP_YEAR) {if(day_temp >= leap_year_month_day[i + 1]) { UtcTime.month ++;
da愛戀下載y_temp -= leap_year_month_day[i + 1]; } } }/*由于天數(shù)從1開始,因此需要加1*/ UtcTime.date = day_temp +
1;printf("\nTime transform successfully\n");printf("++++++++++++++++++++++++++++++++++\n");printf("\nUTC time is : %dy - %dm - %dd\n"
, UtcTime.year, UtcTime.month, UtcTime.date);printf("\nUTC time is : %dh - %dm 愛戀下載: %ds\n", UtcTime.hour, UtcTime.minute, UtcTime.second);
printf("++++++++++++++++++++++++++++++++++\n");printf("\n");printf("\n");return0;}#ifndef __TIMEX_H_#
define __TIMEX_H_/*定義UTC時間結(jié)構(gòu)體類型*/typedefstruct{int year;int month;int date;int hour;int minute;int second;
} utc_t;/*定義UNIX時間戳的起始UNIX時間*/#define愛戀下載 UNIX_TIME_YEAR 1970#define UNIX_TIME_MONTH 1#define UNIX_TIME_DATE 1
#define UNIX_TIME_HOUR 0#define UNIX_TIME_MINIUTE 0#define UNIX_TIME_SECOND 0#define LEAP_YEAR 1
#define FLAT_YEAR 0#endif最后,我們可以使用在線工具來驗證轉(zhuǎn)換結(jié)果是否正確,可以參考下列鏈接的UNIX時間戳在線轉(zhuǎn)換工具,鏈接:https://tool.lu/timestamp/
假設(shè)我們同時輸入UNIX時間戳1615906780,可以得出轉(zhuǎn)換的愛戀下載北京時間為2021-03-16 22:59:40,而我們程序轉(zhuǎn)換得出的時間為2021-03-16 14:59:40,這兩個結(jié)果看似有出入,其實是一致的,我們知道北京時間是東8區(qū)的時間,而UTC時間是0時區(qū)的時間,因此相差8小時。
如圖6所示
圖6 轉(zhuǎn)換結(jié)果下一期,我們將會講述UTC時間如何轉(zhuǎn)換成UNIX時間戳,以及如何進行時區(qū)轉(zhuǎn)換。