目录
Unix时间戳介绍
UTC/GMT
时间与秒计数器转换代码
time.h库函数
Unix时间戳介绍
Unix 时间戳(Unix Timestamp)定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数,不考虑闰秒
时间戳存储在一个秒计数器中,秒计数器为32位/64位的整型变量
世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间
UTC/GMT
GMT(Greenwich Mean Time)格林尼治标准时间是一种以地球自转为基础的时间计量系统。它将地球自转一周的时间间隔等分为24小时,以此确定计时标准
UTC(Universal Time Coordinated)协调世界时是一种以原子钟为基础的时间计量系统。它规定铯133原子基态的两个超精细能级间在零磁场下跃迁辐射9,192,631,770周所持续的时间为1秒。当原子钟计时一天的时间与地球自转一周的时间相差超过0.9秒时,UTC会执行闰秒来保证其计时与地球自转的协调一致
时间与秒计数器转换代码
代码演示结果
#include "stdio.h"
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
//时间结构体
typedef struct
{
uint8_t hour;
uint8_t min;
uint8_t sec;
//公历日月年周
uint16_t w_year;
uint8_t w_month;
uint8_t w_date;
uint8_t week;
}_calendar_obj;
_calendar_obj calendar;//时钟结构体
uint8_t Judge_Leapyear(uint16_t year);
uint8_t Time_ConvertSec(uint16_t year,uint8_t mon,uint8_t day,uint8_t hour,uint8_t min,uint8_t sec);
uint8_t RTC_GetTime(uint32_t time_cnt);
uint8_t RTC_GetWeek(uint16_t i,uint8_t month,uint8_t day);
//存储每个月第一天相对于某个基准日(如1900年1月1日是星期一)的天数差。
//例如:2月1日星期四,偏差3
const uint8_t table_week[12]={0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
enum week { Sunday = 0, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};
//平年的月份日期表
const uint8_t mon_table[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
//判断是否是闰年的函数
//输入:年份
//输出:该年份是不是闰年.1,是.0,不是
uint8_t Judge_Leapyear(uint16_t year)
{
if(year % 4 == 0)
{
if(year % 100 == 0)
{
if(year % 400 == 0) return 1;
else return 0;
}else return 1;
}
else return 0;
}
//把输入的时间转换为UTC/GMT从1970年1月1日0时0分0秒开始所经过的秒数
//1970~2099年为合法年份
//返回值:0,成功;1,年份非法
uint32_t Sec;
uint8_t Time_ConvertSec(uint16_t year,uint8_t mon,uint8_t day,uint8_t hour,uint8_t min,uint8_t sec)
{
uint16_t t;
uint32_t sec_cnt = 0;
if(year < 1970 || year > 2099) return 1;
for(t = 1970; t < year; t++) //把前面完整年份的秒钟相加
{
if(Judge_Leapyear(t)) sec_cnt+=31622400;//闰年的秒钟数
else sec_cnt+=31536000; //平年的秒钟数
}
mon-=1;
for(t = 0;t < mon; t++) //把前面完整月份的秒钟数相加
{
sec_cnt+=(uint32_t)mon_table[t] * 86400;//月份秒钟数相加
if(Judge_Leapyear(year) && t == 1) sec_cnt+=86400;//闰年2月份增加一天的秒钟数
}
sec_cnt+=(uint32_t)(day-1) * 86400;//把前面完整日期的秒钟数相加
sec_cnt+=(uint32_t)hour * 3600;//小时秒钟数
sec_cnt+=(uint32_t)min * 60; //分钟秒钟数
sec_cnt+=sec;//最后的秒钟加上去
Sec = sec_cnt - 8 * 60 * 60;//因为我们输入的时间为东八区时间,减去偏移
return 0;
}
//获得现在是星期几
//功能描述:输入公历日期得到星期(只允许1901-2099年)
uint8_t RTC_GetWeek(uint16_t year,uint8_t month,uint8_t day)
{
uint16_t temp;
uint8_t yearH,yearL;
yearH = year / 100;
yearL = year % 100; //1~99
// 1900年不是闰年,所以对于2000年及以后的年份,年份数加100,以模拟从1900年开始的偏移
if (yearH > 19) yearL+=100;//1~199
// 所过闰年数只算1900年之后的
//364天是7的倍数,iL为365与364(先都按平年算)的偏移天数
//iL / 4是366与365(闰年相对平年的天数)的偏移天数
temp = yearL + yearL / 4;//A:1900年1月1日映射到i年1月1日的的偏移的星期总数
temp = temp % 7; //映射到0~6
temp = temp + day + table_week[month - 1];
//默认1900年1月1日是星期一+因年份天数不是7的倍数而多出的偏移星期数+同一个月内相对于1号的星期偏移+不同月份对于1月份偏移数
if (yearL % 4 == 0 && month < 3) temp--;//A语句已经把闰年多出的天数算了,减去已经算的1天,2月29日过完后偏移才加一1,
return(temp % 7);
}
//秒数转换为当前的时间
//返回值:0,成功
uint8_t RTC_GetTime(uint32_t time_cnt)
{
static uint16_t daycnt = 0;
uint32_t temp = 0;
uint16_t xtemp = 0;
temp = time_cnt / 86400; //秒钟数对应的天数
if(daycnt != temp)//超过一天了
{
daycnt = temp;
xtemp = 1970; //从1970年开始
while(temp >= 365)
{
if(Judge_Leapyear(xtemp))//是闰年
{
if(temp >= 366)temp-=366;//总天数减去闰年的天数
else {xtemp++;break;} //年份++
}
else temp-=365; //总天数减去平年的天数
xtemp++; //年份++
}
calendar.w_year = xtemp;//得到年份
xtemp = 0;//清0,作为新变量
while(temp >= 28)//超过了一个月
{
if(Judge_Leapyear(calendar.w_year) && xtemp == 1)//当年是闰年的2月份
{
if(temp >= 29)temp-=29;//闰年的天数
else break;
}
else //不是闰年的2月份
{
if(temp >= mon_table[xtemp])temp-=mon_table[xtemp];
else break;
}
xtemp++;
}
calendar.w_month = xtemp+1; //得到月份
calendar.w_date = temp+1; //得到日期
}
temp = time_cnt % 86400; //得到秒钟数
calendar.hour = temp / 3600; //小时
calendar.min = (temp % 3600) / 60; //分钟
calendar.sec = (temp % 3600) % 60; //秒钟
calendar.week = RTC_GetWeek(calendar.w_year, calendar.w_month, calendar.w_date);//获取星期
return 0;
}
void main(void)
{
while(1)
{
uint8_t year;
printf("输入年份判断是不是闰年:");
scanf("%d", &year);
if(Judge_Leapyear(year))
printf("\r\n是闰年\r\n");
else
printf("\r\n不是闰年\r\n");
printf("\r\n\r\n");
if(!Time_ConvertSec(2024, 9, 13, 15, 14, 55))
{
printf("%d\r\n",Sec);
};
Sec+=8 * 60 * 60;
if(!RTC_GetTime(Sec))
{
printf("%d-%d-%d %d:%d:%d %d\r\n\r\n",calendar.w_year, calendar.w_month, calendar.w_date, calendar.hour, calendar.min, calendar.sec, calendar.week);
}
}
}
time.h库函数
C语言的time.h模块提供了时间获取和时间戳转换的相关函数,可以方便地进行秒计数器、日期时间和字符串之间的转换
//time文件里的时间定义
struct tm {
int tm_sec; /* 秒,范围从 0 到 59 */
int tm_min; /* 分,范围从 0 到 59 */
int tm_hour; /* 小时,范围从 0 到 23 */
int tm_mday; /* 一月中的第几天,范围从 1 到 31 */
int tm_mon; /* 月,范围从 0 到 11 */
int tm_year; /* 自 1900 年起的年数 */
int tm_wday; /* 一周中的第几天,范围从 0 到 6 */
int tm_yday; /* 一年中的第几天,范围从 0 到 365 */
int tm_isdst; /* 夏令时 */
};
常用函数
注意:
嵌入式C语言中不能使用前两个。
单片机不知道当地是那个时区,获取当地时间函数都以0时区转换,自己加偏移即可。
我国时间以东八区为准
可用函数
应用案例:【STM32】BKP备份寄存器与RTC实时时钟_stm32 hal bkp-CSDN博客