118 lines
3.8 KiB
C
118 lines
3.8 KiB
C
|
#include "unix_timestamp.h"
|
||
|
|
||
|
#define LOG_TAG "[Unix-time]"
|
||
|
#define LOG_ERROR_ENABLE
|
||
|
#define LOG_DEBUG_ENABLE
|
||
|
/* #define LOG_INFO_ENABLE */
|
||
|
/* #define LOG_DUMP_ENABLE */
|
||
|
#define LOG_CLI_ENABLE
|
||
|
#include "debug.h"
|
||
|
|
||
|
#define SECOND 1UL
|
||
|
#define MINU_SECONDS (60 * SECOND)
|
||
|
#define HOUR_SECONDS (60 * MINU_SECONDS)
|
||
|
#define DAY_SECONDS (24 * HOUR_SECONDS)
|
||
|
#define HOUR_MINUTES 60
|
||
|
#define TIME_UNIT 60
|
||
|
#define UTC_BEIJING_OFFSET_SECONDS (8 * HOUR_SECONDS)
|
||
|
|
||
|
#define UNIX_EPOCH_YEAR 1970
|
||
|
#define CLOSEST_FAKE_LEAP_YEAR 2102 // 2100 is nonleap year
|
||
|
#define UNIX_EPOCH_YEAR_WEEKDAY 4 // Thursday
|
||
|
|
||
|
#define NONLEAP_YEAR_DAYS 365
|
||
|
#define LEAP_YEAR_DAYS 366
|
||
|
#define EVERY_4YEARS_DAYS (NONLEAP_YEAR_DAYS * 3 + LEAP_YEAR_DAYS)
|
||
|
#define DAYS_OF_WEEK 7
|
||
|
|
||
|
static bool get_is_leap_year(u16 year)
|
||
|
{
|
||
|
if (((year % 4) == 0) && ((year % 100) != 0)) {
|
||
|
return 1;
|
||
|
} else if ((year % 400) == 0) {
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
struct UTC_TIME unix32_to_UTC(u32 unix_time)
|
||
|
{
|
||
|
log_info("unix_time=%u", unix_time);
|
||
|
|
||
|
u8 days_per_month[12] = {
|
||
|
/*
|
||
|
1 2 3 4 5 6 7 8 9 10 11 12
|
||
|
*/
|
||
|
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||
|
};
|
||
|
struct UTC_TIME utc = {0};
|
||
|
u32 pass_days, pass_days_cnt, pass_days_cnt_next;
|
||
|
u8 pass_4years_cnt;
|
||
|
u16 basic_4multiple_year;
|
||
|
u16 CurrentYear_PassDays, CurrentDay_PassMinutes;
|
||
|
u32 CurrentDay_PassSeconds;
|
||
|
|
||
|
pass_days = unix_time / DAY_SECONDS; // passed days since UNIX_EPOCH_YEAR
|
||
|
pass_4years_cnt = pass_days / EVERY_4YEARS_DAYS; // passed how many 4 years
|
||
|
basic_4multiple_year = (pass_4years_cnt * 4) + UNIX_EPOCH_YEAR; // next 4 year basic, base on UNIX_EPOCH_YEAR
|
||
|
pass_days_cnt = pass_4years_cnt * EVERY_4YEARS_DAYS; // passed day of pass_4years_cnt
|
||
|
if (basic_4multiple_year >= CLOSEST_FAKE_LEAP_YEAR) {
|
||
|
pass_days_cnt--;
|
||
|
}
|
||
|
log_info("basic_4multiple_year=%d", basic_4multiple_year);
|
||
|
|
||
|
//< get year
|
||
|
for (u16 i = basic_4multiple_year; ; i++) {
|
||
|
pass_days_cnt_next = get_is_leap_year(i) ? \
|
||
|
(pass_days_cnt + LEAP_YEAR_DAYS) : (pass_days_cnt + NONLEAP_YEAR_DAYS);
|
||
|
if (pass_days_cnt_next > pass_days) {
|
||
|
utc.year = i;
|
||
|
break;
|
||
|
}
|
||
|
pass_days_cnt = pass_days_cnt_next;
|
||
|
}
|
||
|
|
||
|
//< get month
|
||
|
CurrentYear_PassDays = pass_days - pass_days_cnt;
|
||
|
pass_days_cnt = pass_days_cnt_next = 0;
|
||
|
log_info("CurrentYear_PassDays=%d", CurrentYear_PassDays);
|
||
|
if (get_is_leap_year(utc.year)) {
|
||
|
days_per_month[1]++; // leap month of February is 29 days
|
||
|
}
|
||
|
for (u8 i = 0; i < ARRAY_SIZE(days_per_month); i++) {
|
||
|
pass_days_cnt_next += days_per_month[i];
|
||
|
if (pass_days_cnt_next > CurrentYear_PassDays) {
|
||
|
utc.month = i + 1;
|
||
|
break;
|
||
|
}
|
||
|
pass_days_cnt = pass_days_cnt_next;
|
||
|
}
|
||
|
|
||
|
//< get day
|
||
|
utc.day = CurrentYear_PassDays - pass_days_cnt + 1;
|
||
|
|
||
|
//< get hour:minute:second
|
||
|
CurrentDay_PassSeconds = unix_time - (pass_days * DAY_SECONDS);
|
||
|
CurrentDay_PassMinutes = CurrentDay_PassSeconds / MINU_SECONDS;
|
||
|
utc.hour = CurrentDay_PassMinutes / HOUR_MINUTES;
|
||
|
utc.minute = CurrentDay_PassMinutes % TIME_UNIT;
|
||
|
utc.second = CurrentDay_PassSeconds % TIME_UNIT;
|
||
|
|
||
|
//< get weekday
|
||
|
utc.weekday = (pass_days + UNIX_EPOCH_YEAR_WEEKDAY) % DAYS_OF_WEEK;
|
||
|
|
||
|
log_info("unix32_to_UTC: %d/%d/%d %02d:%02d:%02d, weekday %d",
|
||
|
utc.year, utc.month, utc.day,
|
||
|
utc.hour, utc.minute, utc.second,
|
||
|
utc.weekday);
|
||
|
|
||
|
return utc;
|
||
|
}
|
||
|
|
||
|
struct UTC_TIME unix32_to_UTC_beijing(u32 unix_time)
|
||
|
{
|
||
|
return unix32_to_UTC(unix_time + UTC_BEIJING_OFFSET_SECONDS);
|
||
|
}
|
||
|
|