您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“C語言Unix時間戳與本地時間的轉(zhuǎn)化”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“C語言Unix時間戳與本地時間的轉(zhuǎn)化”吧!
我們平常說時間都說的幾點幾分幾秒,星期幾,但是在計算機里面并不是直接使用我們所說的時間,而是使用Unix時間戳,這樣不管是哪個平臺,哪個系統(tǒng),都可以根據(jù)自己對時間的定義進行轉(zhuǎn)換,像Java,PHP等都提供了接口來進行轉(zhuǎn)化,C庫里面也有這樣的函數(shù),那具體是怎么實現(xiàn)的呢?要了解這個問題首先我們就必須要清楚什么是Unix時間戳,什么是我們平常使用的時間。
UNIX時間戳:Unix時間戳(英文為Unix epoch, Unix time, POSIX time 或 Unix timestamp)
是從1970年1月1日(UTC/GMT的午夜)開始所經(jīng)過的秒數(shù),不考慮閏秒。
UNIX時間戳的0按照ISO 8601規(guī)范為 :1970-01-01T00:00:00Z.
一個小時表示為UNIX時間戳格式為:3600秒;一天表示為UNIX時間戳為86400秒,閏秒不計算。
在大多數(shù)的UNIX系統(tǒng)中UNIX時間戳存儲為32位,這樣會引發(fā)2038年問題或Y2038。
對應(yīng)的時間和秒數(shù)如下
時間 | 秒 |
---|---|
1 分鐘 | 60 秒 |
1 小時 | 3600 秒 |
1 天 | 86400 秒 |
1 周 | 604800 秒 |
1 月 (30.44 天) | 2629743 秒 |
1 年 (365.24 天) | 31556926 秒 |
平常我們最常聽見的是陰歷和陽歷之分,陰歷是按照月亮的運行規(guī)律來計算日期的,那我們所說的陽歷又是什么呢?其實陽歷或者說叫西歷最早是叫做儒略歷,是由羅馬共和國獨裁官儒略·愷撒(即蓋烏斯·尤里烏斯·凱撒)采納數(shù)學(xué)家兼天文學(xué)家索西琴尼的計算后,于公元前45年1月1日起執(zhí)行的取代舊羅馬歷法的一種歷法,但令人遺憾的是,當(dāng)時那些頒發(fā)歷書的祭司們,卻不了解改歷的實質(zhì)。結(jié)果,可笑的是,當(dāng)時羅馬執(zhí)掌頒布歷書的祭司竟把原來歷法上規(guī)定的“每隔三年置閏”誤解為“每三年置一閏”。從公元前45年起,到公元前9年為止,這之間本應(yīng)設(shè)置10個閏年,他們卻設(shè)置了13個閏年。公元前9年,人們終于發(fā)現(xiàn)這一差錯,這時愷撒的外甥奧古斯都執(zhí)掌政權(quán),他糾正了這個錯誤,才停止了“三年一閏”。奧古斯都下令改正過來,改到次年(公元前8年)才置閏年。當(dāng)改正這種閏年的錯誤時已經(jīng)多閏了3年,為了去掉著多閏的3年,奧古斯都又下令停閏3年,即以公元前5年、公元前1年、公元前4年仍為平年,以后恢復(fù)了每4年一閏的規(guī)定了。奧古斯都為了宣揚這一功勞,仿效儒略·愷撒的做法,下令把自己出生的儒略歷中的8月改稱為奧古斯都月(這一名稱在西方沿用到今天)。8月后的大,小月份都翻轉(zhuǎn)過來了,9月為30天,10月為31天,11月為30天,12月為31天,這種置月方式一直沿用至今。如此一來,一年多出了一天,于是也從二月份29天里再減去一天,二月份只剩下28天了 1582年羅馬教皇格里高利對”儒略歷”又進行修改,規(guī)定被4整除的年為閏年,但逢百之年只有能被400除盡才能是閏年。這就是使用至今的“格里歷”。這樣做是為了使歷年與回歸年相接近?;貧w年的周期是365.2425天。儒略歷一年的平均長度為365.25日,比回歸年(365.2425天)長11分14秒,自公元325年(該年采用儒略歷作為宗教日歷)積累到十六世紀(jì)末,春分日由3月21日提早到3月11日。于是羅馬教皇格里高利十三世(Gregorius XⅢ)于1582年10月4日還下令將次日(即原10月5日)定為10月15日,把春分日又恢復(fù)為3月21日。這樣,1582年的10月5日-14日這十天就成了“不存在”的日子,變?yōu)闅v史的空白。1949年9月27日,經(jīng)過中國人民政治協(xié)商會議第一屆全體會議通過,中華人民共和國使用國際社會多數(shù)國家通用的西歷和西元作為歷法和紀(jì)年。
清楚了Unix時間戳和公歷的意義,怎么講秒數(shù)轉(zhuǎn)化成本地時間大家心里應(yīng)該有個大概了,既然本地時間知道了,那我們可不可以根據(jù)這個日期直接知道那一天是星期幾呢?數(shù)學(xué)家蔡勒(Zeller)推算出了這個公式,大家稱為蔡勒公式,使用這個公式隨便給出一個日期,就可以計算出是星期幾。
公式具體是這樣的
W = [C / 4] - 2C + y + [y / 4] + [13 * (M + 1) / 5] + d - 1
或者是:w = y + [y / 4] + [c / 4] - 2c + [26(m + 1) / 10] + d - 1
公式中的符號含義如下:
w:星期; w對7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
c:世紀(jì)-1(前兩位數(shù))
y:年(后兩位數(shù))
m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月來計算,比如2003年1月1日要看作2002年的13月1日來計算)
d:日 [ ]代表取整,即只要整數(shù)部分。
下面以中華人民共和國成立100周年紀(jì)念日那天(2049年10月1日)來計算是星期幾,過程如下:
w = y + [y / 4] + [c / 4] - 2c + [26(m + 1) / 10] + d - 1
= 49 + [49 / 4] + [20 / 4] - 2 × 20 + [26 × (10 + 1) / 10] + 1 - 1
= 49 + [12.25] + 5 - 40 + [28.6]
= 49 + 12 + 5 - 40 + 28
= 54 (除以7余5)
即2049年10月1日(100周年國慶)是星期五。
再比如計算2006年4月4日,過程如下:
w = y + [y / 4] + [c / 4] - 2c + [26(m + 1) / 10] + d - 1
= 6 + [6 / 4] + [20 / 4] - 2 * 20 + [26 * (4 + 1) / 10] + 4 - 1
= -12 (除以7余5,注意對負數(shù)的取模運算!實際上應(yīng)該是星期二而不是星期五)
不過要注意的是,蔡勒公式只適合于1582年(明朝萬歷十年)10月15日之后的情形。
清楚了上面這些內(nèi)容,我們來看一下用C怎么實現(xiàn)Unix時間戳和本地時間的相互轉(zhuǎn)化,并根據(jù)指定的時間算出對應(yīng)的日期
#include <stdio.h> #include <stdbool.h> #define UTC_BASE_YEAR 1970 #define MONTH_PER_YEAR 12 #define DAY_PER_YEAR 365 #define SEC_PER_DAY 86400 #define SEC_PER_HOUR 3600 #define SEC_PER_MIN 60 /* 每個月的天數(shù) */ const unsigned char g_day_per_mon[MONTH_PER_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* 自定義的時間結(jié)構(gòu)體 */ typedef struct { unsigned short nYear; unsigned char nMonth; unsigned char nDay; unsigned char nHour; unsigned char nMin; unsigned char nSec; unsigned char DayIndex; /* 0 = Sunday */ } mytime_struct; /* * 功能: * 判斷是否是閏年 * 參數(shù): * year:需要判斷的年份數(shù) * * 返回值: * 閏年返回1,否則返回0 */ unsigned char applib_dt_is_leap_year(unsigned short year) { /*----------------------------------------------------------------*/ /* Local Variables */ /*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/ /* Code Body */ /*----------------------------------------------------------------*/ if ((year % 400) == 0) { return 1; } else if ((year % 100) == 0) { return 0; } else if ((year % 4) == 0) { return 1; } else { return 0; } } /* * 功能: * 得到每個月有多少天 * 參數(shù): * month:需要得到天數(shù)的月份數(shù) * year:該月所對應(yīng)的年份數(shù) * * 返回值: * 該月有多少天 * */ unsigned char applib_dt_last_day_of_mon(unsigned char month, unsigned short year) { /*----------------------------------------------------------------*/ /* Local Variables */ /*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/ /* Code Body */ /*----------------------------------------------------------------*/ if ((month == 0) || (month > 12)) { return g_day_per_mon[1] + applib_dt_is_leap_year(year); } if (month != 2) { return g_day_per_mon[month - 1]; } else { return g_day_per_mon[1] + applib_dt_is_leap_year(year); } } /* * 功能: * 根據(jù)給定的日期得到對應(yīng)的星期 * 參數(shù): * year:給定的年份 * month:給定的月份 * day:給定的天數(shù) * * 返回值: * 對應(yīng)的星期數(shù),0 - 星期天 ... 6 - 星期六 */ unsigned char applib_dt_dayindex(unsigned short year, unsigned char month, unsigned char day) { char century_code, year_code, month_code, day_code; int week = 0; century_code = year_code = month_code = day_code = 0; if (month == 1 || month == 2) { century_code = (year - 1) / 100; year_code = (year - 1) % 100; month_code = month + 12; day_code = day; } else { century_code = year / 100; year_code = year % 100; month_code = month; day_code = day; } /* 根據(jù)蔡勒公式計算星期 */ week = year_code + year_code / 4 + century_code / 4 - 2 * century_code + 26 * ( month_code + 1 ) / 10 + day_code - 1; week = week > 0 ? (week % 7) : ((week % 7) + 7); return week; } /* * 功能: * 根據(jù)UTC時間戳得到對應(yīng)的日期 * 參數(shù): * utc_sec:給定的UTC時間戳 * result:計算出的結(jié)果 * daylightSaving:是否是夏令時 * * 返回值: * 無 */ void utc_sec_2_mytime(unsigned int utc_sec, mytime_struct *result, bool daylightSaving) { /*----------------------------------------------------------------*/ /* Local Variables */ /*----------------------------------------------------------------*/ int sec, day; unsigned short y; unsigned char m; unsigned short d; unsigned char dst; /*----------------------------------------------------------------*/ /* Code Body */ /*----------------------------------------------------------------*/ if (daylightSaving) { utc_sec += SEC_PER_HOUR; } /* hour, min, sec */ /* hour */ sec = utc_sec % SEC_PER_DAY; result->nHour = sec / SEC_PER_HOUR; /* min */ sec %= SEC_PER_HOUR; result->nMin = sec / SEC_PER_MIN; /* sec */ result->nSec = sec % SEC_PER_MIN; /* year, month, day */ /* year */ /* year */ day = utc_sec / SEC_PER_DAY; for (y = UTC_BASE_YEAR; day > 0; y++) { d = (DAY_PER_YEAR + applib_dt_is_leap_year(y)); if (day >= d) { day -= d; } else { break; } } result->nYear = y; for (m = 1; m < MONTH_PER_YEAR; m++) { d = applib_dt_last_day_of_mon(m, y); if (day >= d) { day -= d; } else { break; } } result->nMonth = m; result->nDay = (unsigned char) (day + 1); /* 根據(jù)給定的日期得到對應(yīng)的星期 */ result->DayIndex = applib_dt_dayindex(result->nYear, result->nMonth, result->nDay); } /* * 功能: * 根據(jù)時間計算出UTC時間戳 * 參數(shù): * currTime:給定的時間 * daylightSaving:是否是夏令時 * * 返回值: * UTC時間戳 */ unsigned int mytime_2_utc_sec(mytime_struct *currTime, bool daylightSaving) { /*----------------------------------------------------------------*/ /* Local Variables */ /*----------------------------------------------------------------*/ unsigned short i; unsigned int no_of_days = 0; int utc_time; unsigned char dst; /*----------------------------------------------------------------*/ /* Code Body */ /*----------------------------------------------------------------*/ if (currTime->nYear < UTC_BASE_YEAR) { return 0; } /* year */ for (i = UTC_BASE_YEAR; i < currTime->nYear; i++) { no_of_days += (DAY_PER_YEAR + applib_dt_is_leap_year(i)); } /* month */ for (i = 1; i < currTime->nMonth; i++) { no_of_days += applib_dt_last_day_of_mon((unsigned char) i, currTime->nYear); } /* day */ no_of_days += (currTime->nDay - 1); /* sec */ utc_time = (unsigned int) no_of_days * SEC_PER_DAY + (unsigned int) (currTime->nHour * SEC_PER_HOUR + currTime->nMin * SEC_PER_MIN + currTime->nSec); if (dst && daylightSaving) { utc_time -= SEC_PER_HOUR; } return utc_time; } int main(int argc, char *argv[]) { mytime_struct my_time; unsigned int sec; char *DayIndex[] = {"Sun.", "Mon.", "Tues.", "Wed.", "Thur.", "Fri.", "Sat."}; /* 這里根據(jù)UTC時間戳計算出來的時間是零時區(qū)的時間,所以如果要轉(zhuǎn)化成北京時間就需要多加8小時 */ utc_sec_2_mytime(1484537668 + 8 * SEC_PER_HOUR, &my_time, false); printf("%d-%d-%d %d:%d:%d %s\n", my_time.nYear, my_time.nMonth, my_time.nDay, my_time.nHour, my_time.nMin, my_time.nSec, DayIndex[my_time.DayIndex]); sec = mytime_2_utc_sec(&my_time, false); printf("sec = %d\n", sec); return 0; }
基本上的內(nèi)容就這些了,平常最好能夠直接使用系統(tǒng)提供的接口,如果不能使用的話就自己實現(xiàn),根據(jù)上面的代碼修改成自己需要的,如果有不對的地方,希望能夠批評指正
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。