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

[复制链接]
672|3
 楼主| xiyaoko2365 发表于 2023-1-18 16:35 | 显示全部楼层 |阅读模式
STM32F103 RTC计数器值 (时间戳) 与常用时间格式 (年月日时分秒) 互相转换算法

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



常用时间格式转时间戳
  1. uint32_t mktime (unsigned int year, unsigned int mon,
  2.                                         unsigned int day, unsigned int hour,
  3.                                         unsigned int min, unsigned int sec)     
  4. {
  5.     if (0 >= (int) (mon -= 2)){    /**//* 1..12 -> 11,12,1..10 */
  6.          mon += 12;      /**//* Puts Feb last since it has leap day */
  7.          year -= 1;
  8.     }

  9.     return (((
  10.              (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
  11.              year*365 - 719499
  12.           )*24 + hour /**//* now have hours */
  13.        )*60 + min /**//* now have minutes */
  14.     )*60 + sec; /**//* finally seconds */
  15. }



 楼主| xiyaoko2365 发表于 2023-1-18 16:36 | 显示全部楼层
时间戳转常用时间格式
  1. /**
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]  时间戳转换为普通时间
  3. * @note
  4. * @param  None
  5. * @retval None
  6. * [url=home.php?mod=space&uid=187600]@author[/url] PWH
  7. * [url=home.php?mod=space&uid=72445]@[/url] CSDN Tyrion.Mon
  8. */
  9. void TimestampToNormalTime(struct RTC_DateTimeTypeDef *time, uint32_t Timestamp)
  10. {

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

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

  46. /**
  47.   * @brief  判断闰年平年
  48.   * @note
  49.   * @param  None
  50.   * @retval None
  51.   * @author PWH
  52.   * @date
  53.   */
  54. uint8_t IsLeapYear(uint16_t year)
  55. {
  56.     if (((year) % 4 == 0 && (year) % 100 != 0) || (year) % 400 == 0)
  57.         return 1; //是闰年
  58.     return 0;   //是平年
  59. }

  60. /*
  61. *  函数功能:根据具体日期得到星期
  62. *  吉姆拉尔森公式  week=(date+2*month+3*(month+1)/5+year+year/4-y/100+y/400)%7
  63. *  注 : 把一月 二月看成是上一年的13 14月    ,    得到结果 0 -- 6
  64. * @ CSDN Tyrion.Mon
  65. */
  66. void getWEEK(struct RTC_DateTimeTypeDef *time)
  67. {
  68.     u16 YY = 0;
  69.     u8 MM = 0;
  70.     if (time->month == 1 || time->month == 2)
  71.     {
  72.         MM = time->month + 12;
  73.         YY = time->year - 1;
  74.     }
  75.     else
  76.     {
  77.         MM = time->month;
  78.         YY = time->year;
  79.     }
  80.     time->week = ( (time->date + 2 * MM + 3 * (MM + 1) / 5 + YY + YY / 4 - YY / 100 + YY / 400) % 7 ) + 1;
  81. }                     //(29 + 16 + 5 + 2018 +2018/4 - 2018/100 + 2018/400)%7
  82. //(29 + 16 + 5 + 18 +18/4 - 18/100 + 18/400)%7


 楼主| xiyaoko2365 发表于 2023-1-18 16:48 | 显示全部楼层
UTC转北京时间
  1. /**
  2. * @brief  UTC、GMT时间转换为北京时间
  3. * @note
  4. * @param  None
  5. * @retval None
  6. * @author PWH
  7. * @date   CSDN Tyrion.Mon
  8. */
  9. void GMTtoBeijingTime(struct RTC_DateTimeTypeDef *GMTtime, struct RTC_DateTimeTypeDef *Beijingtime)
  10. {
  11.     Beijingtime->year  =  GMTtime->year;
  12.     Beijingtime->month =  GMTtime->month;
  13.     Beijingtime->date  =  GMTtime->date;
  14.     Beijingtime->hour   = GMTtime->hour;
  15.     Beijingtime->minute = GMTtime->minute;
  16.     Beijingtime->second = GMTtime->second;

  17.     if (GMTtime->hour + 8 > 23) //东八区已是第二天
  18.     {
  19.         Beijingtime->hour = GMTtime->hour + 8 - 24;  //东八区真实时间(小时)
  20.         //大月
  21.         if ((GMTtime->month == 1) || (GMTtime->month == 3) || (GMTtime->month == 5) || (GMTtime->month == 7) || (GMTtime->month == 8) || (GMTtime->month == 10) || (GMTtime->month == 12))
  22.         {
  23.             if (GMTtime->date == 31) //如果此时UTC时是大月最后一天,则东八区当前时为下一月1号
  24.             {
  25.                 Beijingtime->date = 1;
  26.                 Beijingtime->month++;
  27.                 if (Beijingtime->month > 12) 如果此时UTC时是12月最后一天,则东八区当前时则为下一年1月1日
  28.                 {
  29.                     Beijingtime->month = 1;
  30.                     Beijingtime->year++;
  31.                 }
  32.             }
  33.             else                     //如果此时UTC时不是大月最后一天
  34.             {
  35.                 Beijingtime->date++;
  36.             }
  37.         }
  38.         //二月
  39.         else if (GMTtime->month == 2)
  40.         {
  41.             if ((IsLeapYear(GMTtime->year) == 1 && GMTtime->date == 28) || (GMTtime->date < 28)) //如果UTC时是闰年,且UTC时为28号,则东八区现在为29号 或者 小于28号,则加一
  42.             {
  43.                 Beijingtime->date++;
  44.             }
  45.             else if ((IsLeapYear(GMTtime->year) == 0 && Beijingtime->date == 28) || (Beijingtime->date == 29)) //如果UTC时是平年且UTC时为28号 或者 为29号,则东八区现在为3月1日
  46.             {
  47.                 Beijingtime->date = 1;
  48.                 Beijingtime->month++;
  49.             }
  50.         }
  51.         //小月
  52.         else
  53.         {
  54.             if (GMTtime->date == 30) //如果此时UTC时是小月最后一天,则东八区当前时则为下一月1号
  55.             {
  56.                 Beijingtime->date = 1;
  57.                 Beijingtime->month++;
  58.             }
  59.             else                     //如果此时UTC时不是小月最后一天
  60.             {
  61.                 Beijingtime->date++;
  62.             }
  63.         }
  64.     }
  65.     else              //如果此时UTC时与东八区时同一天
  66.     {
  67.         Beijingtime->hour = GMTtime->hour + 8;
  68.     }

  69.     getWEEK(Beijingtime);
  70. }
 楼主| xiyaoko2365 发表于 2023-1-18 16:49 | 显示全部楼层
自动校时(GPS、WiFi)时,获得UTC时间,可直接转为北京时间存储(DS1302)。或UTC转时间戳存储(STM32F1),读出时间戳后加上 8*3600秒后转为常用时间格式。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

36

主题

511

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部