#ifndef RAY_CAL_H
#define RAY_CAL_H
#include <stdint.h>
#define RAY_DATE_EPOCH 2000
static const uint32_t MONTHDAYS[2][13] = {
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
};
static inline int date_leap_year(int year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
static inline int32_t date_years_by_days(int yy) {
return (int32_t)((int64_t)yy * 365 + yy / 4 - yy / 100 + yy / 400);
}
static inline void date_to_ymd(int32_t days, int* y, int* m, int* d) {
int32_t offset = days + date_years_by_days(RAY_DATE_EPOCH - 1);
double approx = (double)offset / 365.2425;
int32_t years = (int32_t)(approx >= 0.0 ? approx + 0.5 : approx - 0.5);
if (date_years_by_days(years) > offset)
years -= 1;
int32_t rem = offset - date_years_by_days(years);
int yy = years + 1;
int leap = date_leap_year(yy);
int mid = 0;
for (mid = 12; mid > 0; mid--)
if (MONTHDAYS[leap][mid] != 0 && rem / (int32_t)MONTHDAYS[leap][mid] != 0)
break;
if (mid == 12 || mid < 0)
mid = 0;
*y = yy;
*m = 1 + mid % 12;
*d = 1 + rem - (int32_t)MONTHDAYS[leap][mid];
}
static inline int32_t ymd_to_date(int year, int month, int day) {
int yy = (year > 0) ? year - 1 : 0;
int32_t ydays = date_years_by_days(yy);
int leap = date_leap_year(year);
int mm = (month > 0) ? month - 1 : 0;
int32_t mdays = (int32_t)MONTHDAYS[leap][mm];
return ydays - date_years_by_days(RAY_DATE_EPOCH - 1) + mdays + day - 1;
}
#endif