RTC 时间问题

2022-05-19  本文已影响0人  wjundong
/**
 * 思路是循环累加两个相差的年份, 然后再减去较小年份的日期走过多少天, 加上较大年份的日期走过多少天
 * 
 * 比如 2000/04/05-2002/05/02
 * 
 * |----------+---/--------------------------------------|----------+---/
 * 2000       4  5                                      2002       5  2
 * 
 * [----------------for 循环年得到的天数------------------]
 * [-减去走过的天数-]                                     [-加上走过的天数-]
 *                 [----------------------最终天数-----------------------] 
 *           
 */

#include <stdio.h>
#include <stdint.h>


static inline int is_leap_year(unsigned int year)
{
    return (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0));
}

typedef struct {
    uint16_t year;
    uint8_t month;
    uint8_t day;
    uint8_t weekday;
    uint8_t hours;
    uint8_t minutes;
    uint8_t seconds;
}rtc_time_t;


const static int month_days[2][13] = {
    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31}, /* 润年月 */
    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31}, /* 平年月 */
};

/* 计算两个日期相差多少天 */
int dday(rtc_time_t date1, rtc_time_t date2)
{
    rtc_time_t *dmax = date1.year > date2.year ? &date1 : &date2;
    rtc_time_t *dmin = date1.year > date2.year ? &date2 : &date1;

    int days = 0;

    for (int y = dmin->year; y < dmax->year; y++)
        days += is_leap_year(y) ? 366 : 365;

    /* 减去较小的日期走过多少天 */
    int leap = is_leap_year(dmin->year);
    for (int m = 1; m < dmin->month; m++)
        days -= month_days[leap][m - 1];

    /* 加上较大的日期走过多少天 */
    leap = is_leap_year(dmax->year);
    for (int m = 1; m < dmax->month; m++)
        days += month_days[leap][m - 1];

    days += dmax->day - dmin->day;

    return days < 0 ? -days : days;
}


/* rtc 时间转为秒, 即计算时间 t 相对 base_year 年1月1日 00:00:00 走过的秒数  */
uint32_t rtc2sec(int base_year, const rtc_time_t *t)
{
    int days = 0;

    /* 从基准年算起, 到 t - 1 年所累加的天数 */
    for (int y = base_year; y < t->year; y++)
        days += is_leap_year(y) ? 366 : 365;

    /* 再加上 t 这一年已经走过的整月的天数 */
    int leap = is_leap_year(t->year);
    for (int m = 1; m < t->month; m++)
        days += month_days[leap][m - 1];
    
    days += t->day - 1;

    return days*24*3600 + t->hours*3600 + t->minutes*60 + t->seconds;
}


/* 秒数转为 rtc 时间, 即计算 base_year 年1月1日 00:00:00 后经过 sec 秒的时间 t */
void sec2rtc(uint16_t base_year, uint32_t sec, rtc_time_t *t)
{
    /* 可分成多少整天 */
    int days = sec / (24*3600);
    /* 剩余不到 1 天的秒数 */
    int rem = sec % (24*3600);
    int tmp = 0;

    /* 从基准年开始, 所剩天数大于当前年的天数, 对年进行累加并减去天数 */
    for (t->year = base_year; ( tmp = (is_leap_year(t->year) ? 366 : 365) ) && days >= tmp; t->year++)
        days -= tmp;

    /* 从1月开始, 所剩天数大于当前月的天数, 对月进行累加并减去天数 */
    for (t->month = 1; ( tmp = month_days[is_leap_year(t->year)][t->month - 1] ) && days >= tmp; t->month++)
        days -= tmp;
    
    t->day = days + 1;
    t->hours =   rem / 3600 % 100;
    t->minutes = rem / 60 % 60;
    t->seconds = rem % 60;
}


/* 返回时间 t 相对时间 base 走过了多少秒 */
uint32_t rtc2sec_base(const rtc_time_t *base, rtc_time_t *t)
{
    return rtc2sec(base->year, t) - rtc2sec(base->year, base);
}

/* 返回在时间 base 的基础上加 sec 秒得到时间 t */
void sec2rtc_base(const rtc_time_t *base, uint32_t sec, rtc_time_t *t)
{
    sec2rtc(base->year, rtc2sec(base->year, base) + sec, t);
}

rtc_time_t base = {
    .year = 1970,
    .month = 1, 
    .day = 1,
    .hours = 8,
    .minutes = 0,
    .seconds = 0,
};

rtc_time_t d1 = {
    .year = 2022,
    .month = 12, 
    .day = 31,
    .hours = 23,
    .minutes = 59,
    .seconds = 31,
};


void time_print(rtc_time_t *t)
{
    printf("%04d-%02d-%02d %02d:%02d:%02d\n", t->year, t->month, t->day, t->hours, t->minutes, t->seconds);
}

void rtc_time_add(rtc_time_t *t, uint32_t sec)
{
    sec2rtc_base(t, sec, t);
    // sec2rtc(t->year, sec, t);
}

/* 测试 */
int main(int argc, char const *argv[])
{
    rtc_time_t d2;


    // scanf("%d %d %d %d %d %d", &d1.year, &d1.month, &d1.day, &d2.year, &d2.month, &d2.day);

    // int days = dday(d1, d2);

    // printf("%04d/%02d/%02d - %04d/%02d/%02d --> %d days\n", d1.year, d1.month, d1.day, d2.year, d2.month, d2.day, days);
    
    uint32_t sec = rtc2sec_base(&base, &d1);
    printf("sec %d\n", sec);
    
    sec2rtc_base(&base, sec, &d2);

    time_print(&d2);

    rtc_time_add(&d2, 59);

    time_print(&d2);

    return 0;
}

上一篇 下一篇

猜你喜欢

热点阅读