【本文发布于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 */
}
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
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);
}
自动校时(GPS、WiFi)时,获得UTC时间,可直接转为北京时间存储(DS1302)。或UTC转时间戳存储(STM32F1),读出时间戳后加上 8*3600秒后转为常用时间格式。