基于C语言实现localtime和mktime

参考其他博主代码,优化月份处理,支持正负数处理。

#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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值