参考其他博主代码,优化月份处理,支持正负数处理。
#define _DAY_SEC (24 * 60 * 60) /* secs in a day */
#define _YEAR_SEC (365 * _DAY_SEC) /* secs in a year */
#define _FOUR_YEAR_SEC (1461 * _DAY_SEC) /* secs in a 4 year interval */
#define _BASE_DOW 4 /* 01-01-70 was a Thursday */
#define _LEAP_YEAR_ADJUST 17 /* Leap years 1900 - 1970 */
#define _MAX_YEAR 138 /* 2038 is the max year */
/*
* Macro to determine if a given year, expressed as the number of years since
* 1900, is a leap year.
*/
#define _IS_LEAP_YEAR(y) (((y % 4 == 0) && (y % 100 != 0)) || ((y + 1900) % 400 == 0))
/*
* Number of leap years from 1970 up to, but not including, the specified year
* (expressed as the number of years since 1900).
*/
#define _ELAPSED_LEAP_YEARS(y) (((y - 1)/4) - ((y - 1)/100) + ((y + 299)/400) - _LEAP_YEAR_ADJUST)
typedef struct {
int sec; // 0-59
int min; // 0-59
int hour; // 0-23
int mday; // 1-31
int wday; // 0-6
int yday; // 0-365
int mon; // 0-11
int year; // year-1900
} utc_time_t;
int utc_tm_to_sec(const utc_time_t utm)
{
int mon = utm.mon;
int year = utm.year + 1900;
if(utm.mon >= 12)
{
year += mon / 12;
mon = mon % 12;
}
else if(utm.mon < 0)
{
mon = 0 - mon;
year = year - (mon / 12) - 1;
mon = 12 - (mon % 12);
}
mon++;
/* 1..12 -> 11,12,1..10 */
if (0 >= (mon -= 2))
{
mon += 12; /* Puts Feb last since it has leap day */
year -= 1;
}
return ((((int)
(year/4 - year/100 + year/400 + 367*mon/12 + utm.mday) +
year*365 - 719499
)*24 + utm.hour /* now have hours */
)*60 + utm.min /* now have minutes */
)*60 + utm.sec; /* finally seconds */
}
int utc_sec_to_tm(const int tim, utc_time_t *ptm)
{
int _lpdays[] = {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
int _days[] = {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364};
utc_time_t utm;
int caltim = tim; /* calendar time to convert */
int tmptim = 0;
int islpyr = 0; /* is-current-year-a-leap-year flag */
int *mdays; /* pointer to days or lpdays */
int yday = 0; /* 目前结构没有使用 */
memset(&utm, 0x00, sizeof(utm));
if(ptm == NULL) return -1; /* 指针为空 */
memset(ptm, 0x00, sizeof(utc_time_t));
if((tim < 0) || (tim > 0x7fffd27f)) return -2; /* 时间范围超限 */
/* Determine the years since 1900. Start by ignoring leap years. */
tmptim = (caltim / _YEAR_SEC) + 70;
caltim -= (tmptim - 70) * _YEAR_SEC;
/* Correct for elapsed leap years */
caltim -= (_ELAPSED_LEAP_YEARS(tmptim) * _DAY_SEC);
/*
* If we have underflowed the __time64_t range (i.e., if caltim < 0),
* back up one year, adjusting the correction if necessary.
*/
if (caltim < 0)
{
caltim += _YEAR_SEC;
tmptim--;
if (_IS_LEAP_YEAR(tmptim))
{
caltim += _DAY_SEC;
islpyr++;
}
printf("-3--caltim: %d\n", caltim);
}
else
{
if (_IS_LEAP_YEAR(tmptim))
islpyr++;
}
/*
* tmptim now holds the value for tm_year. caltim now holds the
* number of elapsed seconds since the beginning of that year.
*/
utm.year = tmptim;
/*
* Determine days since January 1 (0 - 365). This is the tm_yday value.
* Leave caltim with number of elapsed seconds in that day.
*/
utm.yday = caltim / _DAY_SEC;
caltim -= utm.yday * _DAY_SEC;
/* Determine months since January (0 - 11) and day of month (1 - 31) */
if (islpyr)
mdays = _lpdays;
else
mdays = _days;
for (tmptim = 1; mdays[tmptim] < utm.yday; tmptim++);
utm.mon = --tmptim;
utm.mday = utm.yday - mdays[tmptim];
/* Determine days since Sunday (0 - 6) */
utm.wday = ((tim / _DAY_SEC) + _BASE_DOW) % 7;
utm.hour = caltim / 3600;
caltim -= utm.hour * 3600;
utm.min = caltim / 60;
utm.sec = caltim - (utm.min) * 60;
memcpy(ptm, &utm, sizeof(utm));
return 0;
}