解析时间戳

最近在学习用esp-idf给ESP32写代码。打算写一个NTP授时功能的时候发现要自己解析时间戳。在网上搜了一下,发现大佬们都是按照每四年一闰年的方法来判断是否是闰年。但是这个方法并不准确。

四年一闰,百年不闰,四百年再闰。例如:2000年是闰年,2100年则是平年。——摘自百度百科

考虑到这个问题,所以自己重新写了一个算法(就是不知道有没有大佬也写个这个算法hhh),通过循环来判断是否为闰年。虽然在速度上稍微慢一点但至少会更严谨一些。

#include <stdio.h>
#include <time.h>
#include <stdbool.h>
#include <windows.h>
const long DAY_SEC = 86400;//一天中的秒数

#define my_timezone 8
#define start_year 2021
#define isLeap false
#define start_day 5
const long TO2021_SEC = 1609459200;//1970-1-1到2021-1-1的秒数

int nor_month[] = {31,28,31,30,31,30,31,31,30,31,30,31};
int leap_month[] = {31,29,31,30,31,30,31,31,30,31,30,31};

struct {
    int year;
    int month;
    int date;
    int hour;
    int min;
    int sec;
    int day;
    bool isLeapYear;
}my_time;

void getTime(unsigned long timestamp);
bool isLeapYear(int year);

int main() {
    while(1){
        unsigned long timestamp = time(NULL);
        //scanf("%ul",&timestamp);
        printf("时间戳是:%u\n",timestamp);
        getTime(timestamp);
        printf("%d-%d-%d %02d:%02d:%02d %d %d \n",
               my_time.year,
               my_time.month,
               my_time.date,
               my_time.hour,
               my_time.min,
               my_time.sec,
               my_time.isLeapYear,
               my_time.day);
        Sleep(1000);
    }
}

bool isLeapYear(int year)
{
    if(year%400 == 0)
        return true;
    else if(year%4 == 0 && year%100 !=0)
        return true;
    return false;
}

void getTime(unsigned long timestamp)
{
    timestamp += my_timezone * 3600;//时区偏移
    timestamp -= TO2021_SEC;//预处理
    //时分秒
    my_time.sec = timestamp % 60;//算出没凑够一分钟的秒数
    my_time.min = timestamp % 3600 / 60;//算出没凑够一小时的秒数再除以一分钟的秒数
    my_time.hour = timestamp % DAY_SEC / 3600;//算出没凑够一天的秒数再除以一小时的秒数
    //
    my_time.year  =  start_year;
    my_time.isLeapYear  =  isLeap;
    my_time.month = 1;//一开始是1月
    //
    long nDays = timestamp / DAY_SEC ;
    int tem = nDays % 7;//没凑够一周的天数
    my_time.day = start_day + tem;//当时是星期五
    if(my_time.day > 7)
        my_time.day -= 7;
    //
    while(nDays > 365)//经过多少年就减去对应的天数
    {
        my_time.year++;
        if(isLeapYear(my_time.year))
        {
            nDays -= 366;
            my_time.isLeapYear = true;
        }
        else
        {
            nDays -= 365;
            my_time.isLeapYear = false;
        }
    }
    int *month;//根据闰年选择是有29的还是普通月份
    if(my_time.isLeapYear)
    {
        month = leap_month;
    }
    else
    {
        month = nor_month;
    }
    for(int i = 0;i < 12; i++)
    {
        if(nDays > month[i])//如果剩余的天数比该月份的上限天数要大
        {
            my_time.month++;//说明至少月份是下一个月的
            nDays -= month[i];
        }
        else//否则就是该月份的
        {
            break;
        }
    }
    my_time.date = nDays + 1;//剩余的天数就是经过多少天,一开始是1要加上
}

为了减少循环的次数我直接从2021-1-1开始计算,所以直接减去了从1970-1-1到2021-1-1的秒数。所以说循环次可能也不会很多,如果感觉年份靠后了的话也可以改一开始的几个定义,把时间往后推。

代码在Clion上运行过是没有问题的,但就是不知道有没有特定的时间点会出错。如果代码有BUG 的话欢迎各位大佬指出。如果觉得我代码不规范的也可以吐槽一下我不听

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值