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
#include
#include // struct tm, mktime
#include // 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算法的解释)