unix时间戳转化为时间格式(C代码实现:2种方式)

18 篇文章 1 订阅

方法一:在网络上很多人用这种4年为一周期,有点刻意而为之(另:好多人贴的代码闰年都理解错了!!!),而且只适用2038之前,有点死板

方法二:方法虽然有点笨,但是很准确啦,就是从1970年试了,逼近法。无外乎时间比第一种理论上多了那么一点,但这种时间差距应该很小,可以忽略

大家可以多多测试一下,奇数年,偶数年,平年,闰年,闰月等等,亲测准确。

方法一:代码示例  

此代码之前的错误版本还在网上大面积存留。请谨慎!!!

我就是用的那个错误的,测试发现问题后找到如下正确版本 

/******************************************************************
//版本记录:
// v1.初始化版本。                          --19.05.23
// v2.1.经网友报错,改正一处逻辑错误。         --20.11.08
******************************************************************/
#include <stdio.h>
#include <string.h>
#include "stdint.h"
 
 
#define FOURYEARDAY (365+365+365+366)  //4年一个周期内的总天数(1970~2038不存在2100这类年份,故暂不优化)
#define TIMEZONE    (8)                //北京时区调整 
 
typedef struct rtc_time_struct
{
    uint16_t ui8Year;       // 1970~2038
    uint8_t ui8Month;       // 1~12
    uint8_t ui8DayOfMonth;  // 1~31
    uint8_t ui8Week;
    uint8_t ui8Hour;        // 0~23
    uint8_t ui8Minute;      // 0~59
    uint8_t ui8Second;      // 0~59
   
}rtc_time_t;
 
static uint8_t month_day[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //平年 
static uint8_t Leap_month_day[12]={31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //闰年 
//const uint16_t dayPerYear[4] = {365, 365, 365, 366};
 
// 判断是否是闰年 
// year: 需要判断的年 
// return:1:闰年
//        0: 平年 
uint8_t isLeapYear(uint16_t year)
{
	uint8_t res=0;
	
	if(year%4 == 0) // 能够被4整除 
	{
		if((year%100 == 0) && (year%400 != 0))	//能够被100整除,但是不能够被400整除 
		{
			res = 0;
		}
		else
		{
			res =1;
		}
	}
	return res;
}
 
// 将Unix时间戳转换为北京时间
// unixTime: 需要判断的Unix时间戳 
// *tempBeijing:返回的北京时间
// return:none
// note:没对输入参数正确性做判断
void covUnixTimeStp2Beijing(uint32_t unixTime, rtc_time_t *tempBeijing)
{
    uint32_t totleDayNum=0, totleSecNum=0;
    uint16_t remainDayofYear=0, tempDay=0, tempYear=0;
    uint8_t *pr=NULL;
    
    totleDayNum = unixTime/(24*60*60); //总天数(注意加括号)
    totleSecNum = unixTime%(24*60*60); //当天剩余的秒速
 
    memset(tempBeijing, 0x00, sizeof(rtc_time_t));
    
    // 1.先计算时间 HH:MM:SS
    tempBeijing->ui8Hour = totleSecNum/3600;
    tempBeijing->ui8Minute = (totleSecNum%3600)/60; //error:变量搞错
    tempBeijing->ui8Second = (totleSecNum%3600)%60;
 
    // 2.对时间进行时区调整(注意:这里可能造成日期 +1)
    tempBeijing->ui8Hour +=TIMEZONE; 
    if(tempBeijing->ui8Hour>23){
        //printf("modify day..\n");
        tempBeijing->ui8Hour -= 24;
        remainDayofYear++;  // 日期+1
    }
 
    // 3.计算哪一年
    tempBeijing->ui8Year = 1970 + (totleDayNum / FOURYEARDAY) * 4;   // 4年为一个周期
    remainDayofYear += totleDayNum % FOURYEARDAY;
    
    //printf("year:%d, day:%d.\n", tempBeijing->ui8Year, remainDayofYear);
    tempYear = isLeapYear(tempBeijing->ui8Year)?366:365;
    while(remainDayofYear >= tempYear)  // 计算4年整数倍外的年。
    {
        tempBeijing->ui8Year++;
        remainDayofYear -= tempYear;
        tempYear = isLeapYear(tempBeijing->ui8Year)?366:365;
    }
    
    // 4.计算哪一月的哪一天
    pr = isLeapYear(tempBeijing->ui8Year)?Leap_month_day:month_day;
    remainDayofYear++;          // 这里开始计算具体日期。remainDayofYear为 0 时其实是 1 号,所以这里要 +1
    while(remainDayofYear > *(pr+tempBeijing->ui8Month))
    {
		remainDayofYear -= *(pr+tempBeijing->ui8Month);
        tempBeijing->ui8Month++;
    }
    //printf("year:%d, day:%d.\n", tempBeijing->ui8Year, remainDayofYear);
    tempBeijing->ui8Month++; //month
    tempBeijing->ui8DayOfMonth = remainDayofYear;  //day
    //printf("year:%d, day:%d.\n", tempBeijing->ui8Year, tempBeijing->ui8DayOfMonth);
}
 
// 将北京时间转换为Unix时间戳 
// year: 需要判断的年 
// return:Unix时间戳(从1970/1/1 00:00:00 到现在的秒数) 
// note:没对输入参数正确性做判断
uint32_t covBeijing2UnixTimeStp(rtc_time_t *beijingTime)
{
	uint32_t daynum=0, SecNum=0; //保存北京时间到起始时间的天数
	uint16_t tempYear=1970, tempMonth=0;
 
 
	//1.年的天数 
	while(tempYear < beijingTime->ui8Year) 
	{
		if(isLeapYear(tempYear)){
			daynum += 366;
		}
		else{
			daynum += 365;
		}
		tempYear++;
	}
	//2.月的天数
 	while(tempMonth < beijingTime->ui8Month-1) 
 	{
        if(isLeapYear(beijingTime->ui8Year)){ //闰年
            daynum += Leap_month_day[tempMonth];
        }
        else{
		    daynum += month_day[tempMonth];
        }
		tempMonth++;
	}
    //3.天数
	daynum += (beijingTime->ui8DayOfMonth-1);
 
    //4.时分秒
    SecNum = daynum*24*60*60; //s    
    SecNum += beijingTime->ui8Hour*60*60;    
    SecNum += beijingTime->ui8Minute*60;    
    SecNum += beijingTime->ui8Second;
 
    //5.时区调整
    SecNum -= TIMEZONE*60*60;
 
    return SecNum;
}
 
 
//测试主函数 
int main()
{
    rtc_time_t testTime;
    uint32_t UnixTimsStamp=0;
 

 
    covUnixTimeStp2Beijing(1613806557, &testTime);
    printf("%u convert is: %d/%02d/%02d-%02d:%02d:%02d\n", UnixTimsStamp, 
                    testTime.ui8Year, testTime.ui8Month, testTime.ui8DayOfMonth, \
                    testTime.ui8Hour, testTime.ui8Minute, testTime.ui8Second);
}

 

方法二:

/*************************************************************************************
**************************************************************************************
************************ unix timestamp to time string [begin] ***********************
**************************************************************************************
***************************************************************************************/
#include <stdio.h>
#define UTC_BASE_YEAR   1970
#define MONTH_PER_YEAR  12
#define DAY_PER_YEAR    365
#define SEC_PER_DAY     86400
#define SEC_PER_HOUR    3600
#define SEC_PER_MIN     60
typedef struct{
	int Year;
	char Month;
	char DayOfMonth;
	char Weekday;
	char Hour;
	char Minute;
	char Second;
}nwy_time_type_t;
/* 每个月的天数 */
const unsigned char g_day_per_mon[MONTH_PER_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/*
 * 功能:
 *     判断是否是闰年
 * 参数:
 *     year:需要判断的年份数
 *
 * 返回值:
 *     闰年返回1,否则返回0
 */
static unsigned char applib_dt_is_leap_year(unsigned short year)
{
    if ((year % 400) == 0) {
        return 1;
    } else if ((year % 100) == 0) {
        return 0;
    } else if ((year % 4) == 0) {
        return 1;
    } else {
        return 0;
    }
}

/*
 * 功能:
 *     得到每个月有多少天
 * 参数:
 *     month:需要得到天数的月份数
 *     year:该月所对应的年份数
 *
 * 返回值:
 *     该月有多少天
 *
 */
static unsigned char applib_dt_last_day_of_mon(unsigned char month, unsigned short year)
{
    if ((month == 0) || (month > 12)) {
        return g_day_per_mon[1] + applib_dt_is_leap_year(year);
    }

    if (month != 2) {
        return g_day_per_mon[month - 1];
    } else {
        return g_day_per_mon[1] + applib_dt_is_leap_year(year);
    }
}
static void nwy_cov_unixtimestp_2_utc(int ts, int timezone, 
                                              nwy_time_type_t *tempUTC)
{
    int year = 0;
    int month = 0;
    int day = 0;
    int hour = 0;
    int minute = 0;
    int second = 0;

	 ts += timezone*60*60;//时区调整

    //将时间戳值转化成天数。通过天数可以比较方便地算出年、月、日。
    int days = ts / SEC_PER_DAY;
    //1.计算哪一年
    int yearTmp = 0;
    int dayTmp = 0;
    //使用夹逼法计算 days 天中包含的年数。
    for (yearTmp = UTC_BASE_YEAR; days > 0; yearTmp++) {
        dayTmp = (DAY_PER_YEAR + applib_dt_is_leap_year(yearTmp)); //这一年有多少天?
        if (days >= dayTmp) //条件成立,则 yearTmp 即是这个时间戳值所代表的年数。
        {
           days -= dayTmp;
        }
        else
        {
           break;
        }
    }
    year = yearTmp;

    //2.计算哪一月的哪一天
    int monthTmp = 0;
    for (monthTmp = 1; monthTmp < MONTH_PER_YEAR; monthTmp++) {
       dayTmp = applib_dt_last_day_of_mon(monthTmp, year);
       if (days >= dayTmp) {
           days -= dayTmp;
       }
       else
       {
           break;
       }
    }
    month = monthTmp;
    day = days + 1;

    //转化成秒。
    int secs = ts % SEC_PER_DAY;
    //这个时间戳值的小时数。
    hour = secs / SEC_PER_HOUR;
    //这个时间戳值的分钟数。
    secs %= SEC_PER_HOUR;
    minute = secs / SEC_PER_MIN;
    //这个时间戳的秒钟数。
    second = secs % SEC_PER_MIN;

	tempUTC->Year = year;
	tempUTC->Month = month;
	tempUTC->DayOfMonth = day;
	tempUTC->Hour = hour;
	tempUTC->Minute = minute;
	tempUTC->Second = second;

    printf("time : %d \n",ts);
    printf("time_to : %d-%02d-%02d,%02d:%02d:%02d \n",tempUTC->Year,tempUTC->Month,tempUTC->DayOfMonth,
	tempUTC->Hour,
	tempUTC->Minute,
	tempUTC->Second);
}


void main()
{
    nwy_time_type_t tempUTC;
	nwy_cov_unixtimestp_2_utc(1582184157,8,&tempUTC);
}

/*************************************************************************************
**************************************************************************************
************************ unix timestamp to time string [ end ] ***********************
**************************************************************************************
***************************************************************************************/

 

https://blog.csdn.net/weixin_34161083/article/details/94602720?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&dist_request_id=c8a59b34-1645-416a-8d4c-b41919bef98b&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值