2012-08-26 wcdj
由UNIX时间戳转换为系统时间
date -d'1970-01-01 UTC 2147483647 seconds' +"%Y-%m-%d %T %z" 2038-01-19 11:14:07 +0800 date -d'1970-01-01 UTC 2147483648 seconds' +"%Y-%m-%d %T %z" date: invalid date "1970-01-01 UTC 2147483648 seconds" date -d'1970-01-01 UTC 0 seconds' +"%Y-%m-%d %T" 1970-01-01 08:00:00 +0800
显示当前的UNIX时间戳
date +%s
/* * 2012-08-26 wcdj * 使用Gauss算法解决UNIX时间问题 * 将UNIX时间2038-01-19 03:14:08 * 支持扩大到2106-02-07 06:28:16 */ #include <stdio.h> #include <string.h> #include <time.h> // struct tm, mktime #include <sys/time.h> // gettimeofday #define MAX_TIME_DIFF (24*60*60) #define SECS_PER_HOUR (60 * 60) #define SECS_PER_DAY (SECS_PER_HOUR * 24) // calc microseconds long long get_time_of_day() { struct timeval tv; if (gettimeofday(&tv, NULL) == 0) { return tv.tv_sec * 1000000ULL + tv.tv_usec; } else { return 0; } } static long _timezone = MAX_TIME_DIFF+1; /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. * * [For the Julian calendar (which was used in Russia before 1917, * Britain & colonies before 1752, anywhere else before 1582, * and is still in use by some communities) leave out the * -year/100+year/400 terms, and add 10.] * * This algorithm was first published by Gauss (I think). * * WARNING: this function will overflow on 2106-02-07 06:28:16 on * machines were long is 32-bit! (However, as time_t is signed, we * will already get problems at other places on 2038-01-19 03:14:08) */ static inline unsigned int my_mktime (unsigned int year, unsigned int mon, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec) { if(_timezone == MAX_TIME_DIFF+1) { // 表示_timezone没有初始化 struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); _timezone = tz.tz_minuteswest*60; } if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ mon += 12; /* Puts Feb last since it has leap day */ year -= 1; } /*START 防止"1970-01-01 00:00:00"到"1970-01-01 08:00:00"时间段的错误*/ unsigned int iRet = ((( (year/4 - year/100 + year/400 + 367*mon/12 + day) + year*365 - 719499 )*24 + hour /* now have hours */ )*60 + min /* now have minutes */ )*60 + sec /* finally seconds */ + _timezone; /* time_zone */ if(iRet < 0) { iRet = 0; } return iRet; /*END*/ } static long _timezone_ = MAX_TIME_DIFF+1; static const unsigned short int __mon_yday[2][13] = { /* Normal years. */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, /* Leap years. */ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; int my_localtime_r(unsigned int *timep, struct tm *result) { const unsigned short int *ip; if(_timezone_ == MAX_TIME_DIFF + 1) { struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); _timezone_ = tz.tz_minuteswest*60; } int days = (*timep) / SECS_PER_DAY; unsigned int rem = (*timep) % SECS_PER_DAY; rem -= _timezone_; while (rem < 0) { rem += SECS_PER_DAY; --days; } while (rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; ++days; } result->tm_hour = rem / SECS_PER_HOUR; rem %= SECS_PER_HOUR; result->tm_min = rem / 60; result->tm_sec = rem % 60; /* January 1, 1970 was a Thursday. */ result->tm_wday = (4 + days) % 7; if (result->tm_wday < 0) result->tm_wday += 7; int y = 1970; #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) #ifndef __isleap /* Nonzero if YEAR is a leap year (every 4 years, * * except every 100th isn't, and every 400th is). */ # define __isleap(year) \ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) #endif while (days < 0 || days >= (__isleap (y) ? 366 : 365)) { /* Guess a corrected year, assuming 365 days per year. */ long int yg = y + days / 365 - (days % 365 < 0); /* Adjust DAYS and Y to match the guessed year. */ days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) - LEAPS_THRU_END_OF (y - 1)); y = yg; } result->tm_year = y - 1900; if (result->tm_year != y - 1900) { /* The year cannot be represented due to overflow. */ return -1; } result->tm_yday = days; ip = __mon_yday[__isleap(y)]; for (y = 11; days < (long int) ip[y]; --y) continue; days -= ip[y]; result->tm_mon = y; result->tm_mday = days + 1; return 0; } // return readable format time size_t get_date_str(time_t tsrc, char *buffer, size_t len) { struct tm tm = {0}; /* * modify */ //localtime_r(&tsrc, &tm);// the reentrant version my_localtime_r((unsigned int *)&tsrc, &tm); int iMicrosec = get_time_of_day() % 1000000; return snprintf(buffer, len, "%04d-%02d-%02d %02d:%02d:%02d %d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, iMicrosec); } int main(int argc, char** argv) { unsigned int now = get_time_of_day()/1000000; printf("unixi timestamp: %u\n", now);// date +%s char szTime[128] = {0}; get_date_str(now, szTime, sizeof(szTime)); printf("current time: [%s]\n", szTime); #if 1 /* test for localtime_r*/ // [1] now = 0; memset(szTime, 0x0, sizeof(szTime)); get_date_str(now, szTime, sizeof(szTime)); printf("time: [%s]\n", szTime); // [2] now = 4294967295U;// max of unsigned int memset(szTime, 0x0, sizeof(szTime)); get_date_str(now, szTime, sizeof(szTime)); printf("time: [%s]\n", szTime); // [3] now = 2147483647;// max of int memset(szTime, 0x0, sizeof(szTime)); get_date_str(now, szTime, sizeof(szTime)); printf("time: [%s]\n", szTime); #endif /* test for mktime */ time_t rawtime; struct tm * timeinfo; int year, month, day; // prompt user for date printf("Enter year: ");scanf("%d", &year); printf("Enter month: ");scanf("%d", &month); printf("Enter day: ");scanf("%d", &day); // get current timeinfo and modify it to the user's choice time(&rawtime); timeinfo = localtime(&rawtime); timeinfo->tm_year = year - 1900; timeinfo->tm_mon = month -1; timeinfo->tm_mday = day; unsigned int rettime; /*if (-1 != (rettime = mktime(timeinfo))) { printf("mktime ret: %d\n", rettime); } else { printf("mktime err!\n"); }*/ if(timeinfo->tm_year + 1900 > 2106 || (timeinfo->tm_year + 1900 == 2106 && timeinfo->tm_mon + 1 > 2) || (timeinfo->tm_year + 1900 == 2106 && timeinfo->tm_mon + 1 == 2 && timeinfo->tm_mday > 6)) { printf("Error, overflow 4294967295!\n"); } else { rettime = my_mktime(year, month, day, 0, 0, 0); printf("mktime ret: %u\n", rettime); } return 0; } /* output: unixi timestamp: 1345548878 current time: [2012-08-21 19:34:38 737638] time: [1970-01-01 08:00:00 737648] time: [2106-02-07 14:28:15 737652] time: [2038-01-19 11:14:07 737655] */
参考
[1] Linux源码中的mktime算法解析 (关于Gauss算法的解释)