STM32F103 RTC计数器值 (时间戳) 与常用时间格式 (年月日时分秒) 互相转换算法


【本文发布于https://blog.csdn.net/Stack_/article/details/105916302,未经许可不得转载,转载须注明出处】




1. 常用时间格式转时间戳

uint32_t mktime (unsigned int year, unsigned int mon,
					unsigned int day, unsigned int hour,
					unsigned int min, unsigned int sec)     
{
    if (0 >= (int) (mon -= 2)){    /**//* 1..12 -> 11,12,1..10 */
         mon += 12;      /**//* Puts Feb last since it has leap day */
         year -= 1;
    }
 
    return (((
             (unsigned long) (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 */
}

来源: 网络, Linux的源码



2.时间戳转常用时间格式

/**
 * @brief  时间戳转换为普通时间
 * @note
 * @param  None
 * @retval None
 * @author PWH
 * @ CSDN Tyrion.Mon
 */
void TimestampToNormalTime(struct RTC_DateTimeTypeDef *time, uint32_t Timestamp)
{

    uint16_t year = 1970;
    uint32_t Counter = 0, CounterTemp; //随着年份迭加,Counter记录从1970 年 1 月 1 日(00:00:00 GMT)到累加到的年份的最后一天的秒数
    uint8_t Month[12] = {31, 28, 31, 30, 31, 30,          31, 31, 30, 31, 30, 31};
    uint8_t i;

    while (Counter <= Timestamp)    //假设今天为2018年某一天,则时间戳应小于等于1970-1-1 0:0:0 到 2018-12-31 23:59:59的总秒数
    {
        CounterTemp = Counter;			 //CounterTemp记录完全1970-1-1 0:0:0 到 2017-12-31 23:59:59的总秒数后退出循环
        Counter += 31536000; //加上今年(平年)的秒数
        if (IsLeapYear(year))
        {
            Counter += 86400; //闰年多加一天
        }
        year++;
    }
    time->year = year - 1; //跳出循环即表示到达计数值当前年
    Month[1] = (IsLeapYear(time->year) ? 29 : 28);
    Counter = Timestamp - CounterTemp; //Counter = Timestamp - CounterTemp  记录2018年已走的总秒数
    CounterTemp = Counter / 86400;        //CounterTemp = Counter/(24*3600)  记录2018年已【过去】天数
    Counter -= CounterTemp * 86400;      //记录今天已走的总秒数
    time->hour = Counter / 3600; //时      				 得到今天的小时
    time->minute = Counter % 3600 / 60; //分
    time->second = Counter % 60; //秒
    for (i = 0; i < 12; i++)
    {
        if (CounterTemp < Month[i])    									//不能包含相等的情况,相等会导致最后一天切换到下一个月第一天时
        {
            //(即CounterTemp已走天数刚好为n个月完整天数相加时(31+28+31...)),
            time->month = i + 1;			  									// 月份不加1,日期溢出(如:出现32号)
            time->date = CounterTemp + 1; 								//应不作处理,CounterTemp = Month[i] = 31时,会继续循环,月份加一,
            break;																				//日期变为1,刚好符合实际日期
        }
        CounterTemp -= Month[i];
    }
    getWEEK(time);
}

/**
  * @brief  判断闰年平年
  * @note
  * @param  None
  * @retval None
  * @author PWH
  * @date
  */
uint8_t IsLeapYear(uint16_t year)
{
    if (((year) % 4 == 0 && (year) % 100 != 0) || (year) % 400 == 0)
        return 1; //是闰年
    return 0;   //是平年
}

/*
 *  函数功能:根据具体日期得到星期
 *  吉姆拉尔森公式  week=(date+2*month+3*(month+1)/5+year+year/4-y/100+y/400)%7
 *  注 : 把一月 二月看成是上一年的13 14月    ,    得到结果 0 -- 6
 * @ CSDN Tyrion.Mon
 */
void getWEEK(struct RTC_DateTimeTypeDef *time)
{
    u16 YY = 0;
    u8 MM = 0;
    if (time->month == 1 || time->month == 2)
    {
        MM = time->month + 12;
        YY = time->year - 1;
    }
    else
    {
        MM = time->month;
        YY = time->year;
    }
    time->week = ( (time->date + 2 * MM + 3 * (MM + 1) / 5 + YY + YY / 4 - YY / 100 + YY / 400) % 7 ) + 1;
}                     //(29 + 16 + 5 + 2018 +2018/4 - 2018/100 + 2018/400)%7
//(29 + 16 + 5 + 18 +18/4 - 18/100 + 18/400)%7


自己编写 暂未发现有bug


3.UTC转北京时间

/**
 * @brief  UTC、GMT时间转换为北京时间
 * @note
 * @param  None
 * @retval None
 * @author PWH
 * @date   CSDN Tyrion.Mon
 */
void GMTtoBeijingTime(struct RTC_DateTimeTypeDef *GMTtime, struct RTC_DateTimeTypeDef *Beijingtime)
{
    Beijingtime->year  =  GMTtime->year;
    Beijingtime->month =  GMTtime->month;
    Beijingtime->date  =  GMTtime->date;
    Beijingtime->hour   = GMTtime->hour;
    Beijingtime->minute = GMTtime->minute;
    Beijingtime->second = GMTtime->second;

    if (GMTtime->hour + 8 > 23) //东八区已是第二天
    {
        Beijingtime->hour = GMTtime->hour + 8 - 24;  //东八区真实时间(小时)
        //大月
        if ((GMTtime->month == 1) || (GMTtime->month == 3) || (GMTtime->month == 5) || (GMTtime->month == 7) || (GMTtime->month == 8) || (GMTtime->month == 10) || (GMTtime->month == 12))
        {
            if (GMTtime->date == 31) //如果此时UTC时是大月最后一天,则东八区当前时为下一月1号
            {
                Beijingtime->date = 1;
                Beijingtime->month++;
                if (Beijingtime->month > 12) 如果此时UTC时是12月最后一天,则东八区当前时则为下一年1月1日
                {
                    Beijingtime->month = 1;
                    Beijingtime->year++;
                }
            }
            else                     //如果此时UTC时不是大月最后一天
            {
                Beijingtime->date++;
            }
        }
        //二月
        else if (GMTtime->month == 2)
        {
            if ((IsLeapYear(GMTtime->year) == 1 && GMTtime->date == 28) || (GMTtime->date < 28)) //如果UTC时是闰年,且UTC时为28号,则东八区现在为29号 或者 小于28号,则加一
            {
                Beijingtime->date++;
            }
            else if ((IsLeapYear(GMTtime->year) == 0 && Beijingtime->date == 28) || (Beijingtime->date == 29)) //如果UTC时是平年且UTC时为28号 或者 为29号,则东八区现在为3月1日
            {
                Beijingtime->date = 1;
                Beijingtime->month++;
            }
        }
        //小月
        else
        {
            if (GMTtime->date == 30) //如果此时UTC时是小月最后一天,则东八区当前时则为下一月1号
            {
                Beijingtime->date = 1;
                Beijingtime->month++;
            }
            else                     //如果此时UTC时不是小月最后一天
            {
                Beijingtime->date++;
            }
        }
    }
    else              //如果此时UTC时与东八区时同一天
    {
        Beijingtime->hour = GMTtime->hour + 8;
    }

    getWEEK(Beijingtime);
}
自己编写 暂未发现有bug


自动校时(GPS、WiFi)时,获得UTC时间,可直接转为北京时间存储(DS1302)。或UTC转时间戳存储(STM32F1),读出时间戳后加上 8*3600秒后转为常用时间格式。


你可能感兴趣的:(MCU,算法)