世紀秒指自1970年1月1日0時0分0秒至某一日期時間經過的秒數。有些應用場景中,需要將日期時間轉換為世紀秒,或者將世紀秒轉換為日期時間。
c/c++庫中已經有相關的函數,由time.h中的mktime函數和函數分別實現上述兩個轉換。但time.h只能實現32位的世紀秒運算,最大支持到2038年;且mktime、默認的時間基準年份都是1970年1月1日,倘若需要獲得以任意年為基準的“世紀秒”,還需要考慮自己寫函數實現。
下面通過自己寫這兩個函數,相比于mktime、有以下兩個優點:
1.用64位大大擴大了時間戳,最長時間戳為,而時間戳為時就已經到3137年10月10日5:43:28了。彌補了時間戳最大截至到2038年的缺點;
2.可定義年為基準,不僅僅是1970.
我在以下函數中實現了兩種轉換,分別是和,用最簡單粗暴、容易理解的邏輯書寫,效率肯定比不上linux中的短小精悍的mktime函數,但是可以彌補以上兩個缺點。有興趣的可以去看一下理解一下Linux源碼中的mktime算法解析
需要注意的地方都以注釋說明。在main函數中進行了從1970年1月1日到2030年1月1日步進為1秒的函數正確性測試,分別驗證自己寫的函數是否和mktime、計算結果一至,結果表明沒有問題。
#include
#include
#define BASE_YEAR 70 //世紀秒的年份基準,BASE_YEAR = 基準年份 - 1900
#define BASE_MON 1 //世紀秒的月份基準,一般是1月
#define BASE_DAY 1 //世紀秒的日基準 ,一般是1日
//時分秒都默認是0
//初始時間
#define YEAR (1970 - 1900)
#define MON (1 - 1) //月[0,11],以適應time.h中的struct tm
#define DAY 1
#define HOUR 8
#define MIN 0
#define SEC 0
//是否是UTC時間,單片機中使用為1(因為沒有設置時區),電腦中使用需要為0(因為電腦調用time.h中的相關函數時,調用了系統時區)
#define USE_UTC 0
//月份天數表
unsigned char Montbl[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
//是否閏年
unsigned char IsLeap(int year)
{
unsigned char res = 0;
if( (year % 4 == 0) && (year % 4 != 100) )
{
res = 1;
}
return res;
}
//計算世紀秒 從BASE_YEAR-BASE_MON-BASE_DAY 0時0分0秒到某一時間經過的秒
//注意,tm_mon = [0,11]
//后期要對輸入的時間加合法判定
_int64 my_mktime(struct tm* p)
{
_int64 res = 0;
int year_s = BASE_YEAR, mon_s = 0;
unsigned char leap = 0;//最新年份是否閏年
if( IsLeap(p->tm_year + 1900))
{
leap = 1;
}
//按年累加
while(year_s < p->tm_year)
{
res += 365 * 24 * 3600;
if(IsLeap(year_s + 1900))
{
res += 24 * 3600;
}
year_s++;
}
//具體到月
while(mon_s < p->tm_mon)
{
//如果月份為2且是閏年
if(mon_s == 1 && leap)
{
res += (Montbl[mon_s] + 1) * 24 * 3600;
}
else
{
res += Montbl[mon_s] * 24 * 3600;
}
mon_s++;
}
//具體到日
res += (p->tm_mday - 1) * 24 * 3600;
//具體到時分秒

res += 3600 * p->tm_hour + 60 * p->tm_min + p->tm_sec;
//如果加上了本地時區(東八區)
if(!USE_UTC)
{
res -= 3600 * 8;
}
return res;
}
//世紀秒轉換成日期時間
void my_localtime(_int64 cs,struct tm *p)
{
int year_s = BASE_YEAR,mon_s = 0 ;
//如果加上了本地時區(東八區)
if(!USE_UTC)
{
cs += 3600 * 8;
}
//算年份
while(1)
{
if(IsLeap(year_s + 1900))
{
if((cs - 3600 * 24 * 366) >= 0)
{
cs -= 3600 * 24 * 366;
year_s++;
}
else
{
break;
}
}
else
{
if((cs - 3600 * 24 * 365) >= 0)
{
cs -= 3600 * 24 * 365;
year_s++;
}
else
{
break;
}
}
}
p->tm_year = year_s;
//算月份
while(1)
{
//如果到了2月,且是閏年
if(mon_s == 1 && IsLeap(year_s + 1900))
{
if(cs - (Montbl[mon_s] + 1)* 24 * 3600 >= 0)
{
cs -= (Montbl[mon_s] + 1)* 24 * 3600 ;
mon_s++;
}
else
{
break;
}
}
else
{
if(cs - Montbl[mon_s] * 24 * 3600 >= 0)
{
cs -= Montbl[mon_s] * 24 * 3600;
mon_s++;
}
else
{
break;
}
}
}
p->tm_mon = mon_s;
//算日期
p->tm_mday = cs / (3600 * 24) + 1;
//算時分秒
cs %= (3600 * 24);
p->tm_hour = cs / 3600;
cs %= 3600;
p->tm_min = cs / 60;
cs %= 60;
p->tm_sec = cs;
}

int main(void)
{
_int64 sys_tm,my_tm;//系統函數計算的世紀秒和我自己的函數計算的世紀秒
struct tm* psys = (struct tm*)malloc(sizeof(struct tm));//系統函數計算的日期時間
struct tm* pmy = (struct tm*)malloc(sizeof(struct tm));//我自己的函數計算的日期時間
int cnt = 0;//用于打印
memset(psys,0,sizeof(struct tm));
memset(pmy,0,sizeof(struct tm));
psys->tm_year = YEAR;
psys->tm_mon = MON;
psys->tm_mday = DAY;
psys->tm_hour = HOUR;
psys->tm_min = MIN;
psys->tm_sec = SEC;
psys->tm_isdst = -1;
//測試初始值2020-1-1 8:0:0
//迭代運算,與系統的mktime() localtime()做比較
//測試到2030-1-1 8:0:0
do
{
//由日期時間獲得世紀秒
sys_tm = mktime(psys);
my_tm = my_mktime(psys);
//判斷自己的函數和系統函數獲得的世紀秒是否相等
if(sys_tm != my_tm)
{
printf("err my_mktime when sys_tm is :%I64d\n",my_tm);
break;
}
//世界秒加一
sys_tm++;
//由世紀秒反推到日期時間
psys = localtime(&sys_tm);
my_localtime(sys_tm,pmy);
//判斷自己的函數和系統函數獲得的日期時間是否一樣
if(psys->tm_year != pmy->tm_year ||
psys->tm_mon != pmy->tm_mon ||
psys->tm_mday != pmy->tm_mday ||
psys->tm_hour != pmy->tm_hour ||
psys->tm_min != pmy->tm_min ||
psys->tm_sec != pmy->tm_sec)
{
printf("err my_localtime when sys_tm is :%d\n",sys_tm);
break;
}
//秒每走過一天打印一次進度
//防止printf過多耗費大量時間
if(cnt++ >= 3600 * 24)
{
cnt = 0;
//2030-1-1 8:0:0的世紀秒為1893456000 提前獲取這個值用于進度計算
printf(".2lf%%\t%d-d-d d:d:d\r",
(double)(sys_tm)* 100 / (1893456000.0) ,
psys->tm_year+1900,
psys->tm_mon + 1,
psys->tm_mday,
psys->tm_hour,
psys->tm_min,
psys->tm_sec);
}
}while(sys_tm <= 1893456000);
printf("Test End\n");
return 0;
}
*請認真填寫需求信息,我們會在24小時內與您取得聯系。