Files
EPD-nRF5/GUI/Lunar.c
2025-10-16 11:03:59 +08:00

551 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Lunar.h"
const char Lunar_MonthString[13][7] = {
"----",
"正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月",
"冬月", "腊月"};
const char Lunar_MonthLeapString[2][4] = {
" ",
""};
const char Lunar_DateString[31][7] = {
"----",
"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
"十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
"廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"};
const char Lunar_DayString[7][4] = {
"",
"", "", "", "", "", ""};
const char Lunar_ZodiacString[12][4] = {
"", "", "", "", "", "", "", "", "", "", "", ""};
const char Lunar_StemStrig[10][4] = {
"", "", "", "", "", "", "", "", "", ""};
const char Lunar_BranchStrig[12][4] = {
"", "", "", "", "", "", "", "", "", "", "", ""};
/* 2000 ~ 2199 */
const uint32_t lunar_month_days[] = {
1997,
0x0000B26D, 0x0000125C, 0x0000192C, 0x00009A95, 0x00001A94, 0x00001B4A, 0x00004B55, 0x00000AD4, 0x0000F55B,
0x000004BA, 0x0000125A, 0x0000B92B, 0x0000152A, 0x00001694, 0x000096AA, 0x000015AA, 0x00012AB5, 0x00000974,
0x000014B6, 0x0000CA57, 0x00000A56, 0x00001526, 0x00008E95, 0x00000D54, 0x000015AA, 0x000049B5, 0x0000096C,
0x0000D4AE, 0x0000149C, 0x00001A4C, 0x0000BD26, 0x00001AA6, 0x00000B54, 0x00006D6A, 0x000012DA, 0x0001695D,
0x0000095A, 0x0000149A, 0x0000DA4B, 0x00001A4A, 0x00001AA4, 0x0000BB54, 0x000016B4, 0x00000ADA, 0x0000495B,
0x00000936, 0x0000F497, 0x00001496, 0x0000154A, 0x0000B6A5, 0x00000DA4, 0x000015B4, 0x00006AB6, 0x0000126E,
/*0x0001092F, 0x0000092E, 0x00000C96, 0x0000CD4A, 0x00001D4A, 0x00000D64, 0x0000956C, 0x0000155C, 0x0000125C,
0x0000792E, 0x0000192C, 0x0000FA95, 0x00001A94, 0x00001B4A, 0x0000AB55, 0x00000AD4, 0x000014DA, 0x00008A5D,
0x00000A5A, 0x0001152B, 0x0000152A, 0x00001694, 0x0000D6AA, 0x000015AA, 0x00000AB4, 0x000094BA, 0x000014B6,
0x00000A56, 0x00007527, 0x00000D26, 0x0000EE53, 0x00000D54, 0x000015AA, 0x0000A9B5, 0x0000096C, 0x000014AE,
0x00008A4E, 0x00001A4C, 0x00011D26, 0x00001AA4, 0x00001B54, 0x0000CD6A, 0x00000ADA, 0x0000095C, 0x0000949D,
0x0000149A, 0x00001A2A, 0x00005B25, 0x00001AA4, 0x0000FB52, 0x000016B4, 0x00000ABA, 0x0000A95B, 0x00000936,
0x00001496, 0x00009A4B, 0x0000154A, 0x000136A5, 0x00000DA4, 0x000015AC, 0x0000CAB6, 0x0000126E, 0x0000092E,
0x00008C97, 0x00000A96, 0x00000D4A, 0x00006DA5, 0x00000D54, 0x0000F56A, 0x0000155A, 0x00000A5C, 0x0000B92E,
0x0000152C, 0x00001A94, 0x00009D4A, 0x00001B2A, 0x00016B55, 0x00000AD4, 0x000014DA, 0x0000CA5D, 0x00000A5A,
0x0000151A, 0x0000BA95, 0x00001654, 0x000016AA, 0x00004AD5, 0x00000AB4, 0x0000F4BA, 0x000014B6, 0x00000A56,
0x0000B517, 0x00000D16, 0x00000E52, 0x000096AA, 0x00000D6A, 0x000165B5, 0x0000096C, 0x000014AE, 0x0000CA2E,
0x00001A2C, 0x00001D16, 0x0000AD52, 0x00001B52, 0x00000B6A, 0x0000656D, 0x0000055C, 0x0000F45D, 0x0000145A,
0x00001A2A, 0x0000DA95, 0x000016A4, 0x00001AD2, 0x00008B5A, 0x00000AB6, 0x0001455B, 0x000008B6, 0x00001456,
0x0000D52B, 0x0000152A, 0x00001694, 0x0000B6AA, 0x000015AA, 0x00000AB6, 0x000064B7, 0x000008AE, 0x0000EC57,
0x00000A56, 0x00000D2A, 0x0000CD95, 0x00000B54, 0x0000156A, 0x00008A6D, 0x0000095C, 0x000014AE, 0x00004A56,
0x00001A54, 0x0000DD2A, 0x00001AAA, 0x00000B54, 0x0000B56A, 0x000014DA, 0x0000095C, 0x000074AB, 0x0000149A,
0x0000FA4B, 0x00001652, 0x000016AA, 0x0000CAD5, 0x000005B4*/};
/* 2000 ~ 2199 */
const uint32_t solar_1_1[] = {
1997,
0x000F9C3C, 0x000F9E50, 0x000FA045, 0x000FA238, 0x000FA44C, 0x000FA641, 0x000FA836, 0x000FAA49, 0x000FAC3D,
0x000FAE52, 0x000FB047, 0x000FB23A, 0x000FB44E, 0x000FB643, 0x000FB837, 0x000FBA4A, 0x000FBC3F, 0x000FBE53,
0x000FC048, 0x000FC23C, 0x000FC450, 0x000FC645, 0x000FC839, 0x000FCA4C, 0x000FCC41, 0x000FCE36, 0x000FD04A,
0x000FD23D, 0x000FD451, 0x000FD646, 0x000FD83A, 0x000FDA4D, 0x000FDC43, 0x000FDE37, 0x000FE04B, 0x000FE23F,
0x000FE453, 0x000FE648, 0x000FE83C, 0x000FEA4F, 0x000FEC44, 0x000FEE38, 0x000FF04C, 0x000FF241, 0x000FF436,
0x000FF64A, 0x000FF83E, 0x000FFA51, 0x000FFC46, 0x000FFE3A, 0x0010004E, 0x00100242, 0x00100437, 0x0010064B,
/*0x00100841, 0x00100A53, 0x00100C48, 0x00100E3C, 0x0010104F, 0x00101244, 0x00101438, 0x0010164C, 0x00101842,
0x00101A35, 0x00101C49, 0x00101E3D, 0x00102051, 0x00102245, 0x0010243A, 0x0010264E, 0x00102843, 0x00102A37,
0x00102C4B, 0x00102E3F, 0x00103053, 0x00103247, 0x0010343B, 0x0010364F, 0x00103845, 0x00103A38, 0x00103C4C,
0x00103E42, 0x00104036, 0x00104249, 0x0010443D, 0x00104651, 0x00104846, 0x00104A3A, 0x00104C4E, 0x00104E43,
0x00105038, 0x0010524A, 0x0010543E, 0x00105652, 0x00105847, 0x00105A3B, 0x00105C4F, 0x00105E45, 0x00106039,
0x0010624C, 0x00106441, 0x00106635, 0x00106849, 0x00106A3D, 0x00106C51, 0x00106E47, 0x0010703C, 0x0010724F,
0x00107444, 0x00107638, 0x0010784C, 0x00107A3F, 0x00107C53, 0x00107E48, 0x0010803D, 0x00108250, 0x00108446,
0x0010863A, 0x0010884E, 0x00108A42, 0x00108C36, 0x00108E4A, 0x0010903E, 0x00109251, 0x00109447, 0x0010963B,
0x0010984F, 0x00109A43, 0x00109C37, 0x00109E4B, 0x0010A041, 0x0010A253, 0x0010A448, 0x0010A63D, 0x0010A851,
0x0010AA45, 0x0010AC39, 0x0010AE4D, 0x0010B042, 0x0010B236, 0x0010B44A, 0x0010B63E, 0x0010B852, 0x0010BA47,
0x0010BC3B, 0x0010BE4F, 0x0010C044, 0x0010C237, 0x0010C44B, 0x0010C641, 0x0010C854, 0x0010CA48, 0x0010CC3D,
0x0010CE50, 0x0010D045, 0x0010D239, 0x0010D44C, 0x0010D642, 0x0010D837, 0x0010DA4A, 0x0010DC3E, 0x0010DE52,
0x0010E047, 0x0010E23A, 0x0010E44E, 0x0010E643, 0x0010E838, 0x0010EA4B, 0x0010EC41, 0x0010EE54, 0x0010F049,
0x0010F23C, 0x0010F450, 0x0010F645, 0x0010F839, 0x0010FA4C, 0x0010FC42, 0x0010FE37, 0x0011004B, 0x0011023E,
0x00110452, 0x00110647, 0x0011083B, 0x00110A4E, 0x00110C43, 0x00110E38, 0x0011104C, 0x0011123F, 0x00111435,
0x00111648, 0x0011183C, 0x00111A4F, 0x00111C45, 0x00111E39, 0x0011204D, 0x00112242, 0x00112436, 0x0011264A,
0x0011283E, 0x00112A51, 0x00112C46, 0x00112E3B, 0x0011304F*/};
static uint32_t GetBitInt(uint32_t data, uint8_t length, uint8_t shift)
{
return (data & (((1 << length) - 1) << shift)) >> shift;
}
// WARNING: Dates before Oct. 1582 are inaccurate
static uint16_t SolarToInt(uint16_t y, uint8_t m, uint8_t d)
{
m = (m + 9) % 12;
y = y - m / 10;
return 365 * y + y / 4 - y / 100 + y / 400 + (m * 306 + 5) / 10 + (d - 1);
}
void LUNAR_SolarToLunar(struct Lunar_Date *lunar, uint16_t solar_year, uint8_t solar_month, uint8_t solar_date)
{
uint8_t i, lunarM, m, d, leap, dm;
uint16_t year_index, lunarY, y, offset;
uint32_t solar_data, solar11, days;
if (solar_month < 1 || solar_month > 12 || solar_date < 1 || solar_date > 31 ||
(solar_year - solar_1_1[0] < 3) || ((solar_year - solar_1_1[0]) > (sizeof(solar_1_1) / sizeof(uint32_t) - 2)))
{
lunar->Year = 0;
lunar->Month = 0;
lunar->Date = 0;
lunar->IsLeap = 0;
return;
}
year_index = solar_year - solar_1_1[0];
solar_data = ((uint32_t)solar_year << 9) | ((uint32_t)solar_month << 5) | ((uint32_t)solar_date);
if (solar_1_1[year_index] > solar_data)
{
year_index -= 1;
}
solar11 = solar_1_1[year_index];
y = GetBitInt(solar11, 12, 9);
m = GetBitInt(solar11, 4, 5);
d = GetBitInt(solar11, 5, 0);
offset = SolarToInt(solar_year, solar_month, solar_date) - SolarToInt(y, m, d);
days = lunar_month_days[year_index];
leap = GetBitInt(days, 4, 13);
lunarY = year_index + solar_1_1[0];
lunarM = 1;
offset += 1;
for (i = 0; i < 13; i++)
{
if (GetBitInt(days, 1, 12 - i) == 1)
{
dm = 30;
}
else
{
dm = 29;
}
if (offset > dm)
{
lunarM += 1;
offset -= dm;
}
else
{
break;
}
}
lunar->IsLeap = 0;
if (leap != 0 && lunarM > leap)
{
if (lunarM == leap + 1)
{
lunar->IsLeap = 1;
}
lunarM -= 1;
}
lunar->Month = lunarM;
lunar->Date = offset;
lunar->Year = lunarY;
}
uint8_t LUNAR_GetZodiac(const struct Lunar_Date *lunar)
{
return lunar->Year % 12;
}
uint8_t LUNAR_GetStem(const struct Lunar_Date *lunar)
{
return lunar->Year % 10;
}
uint8_t LUNAR_GetBranch(const struct Lunar_Date *lunar)
{
return lunar->Year % 12;
}
/*********************************************************************************************************
** 以下为24节气计算相关程序
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
/*
每年24节气标志表
有兴趣的朋友可按照上面给的原理添加其它年份的表格
不是很清楚的朋友可给我发EMAIL
*/
static const uint8_t YearMonthBit[160] =
{
0x4E, 0xA6, 0x99, // 2000
0x9C, 0xA2, 0x98, // 2001
0x80, 0x00, 0x18, // 2002
0x00, 0x10, 0x24, // 2003
0x4E, 0xA6, 0x99, // 2004
0x9C, 0xA2, 0x98, // 2005
0x80, 0x82, 0x18, // 2006
0x00, 0x10, 0x24, // 2007
0x4E, 0xA6, 0xD9, // 2008
0x9E, 0xA2, 0x98, // 2009
0x80, 0x82, 0x18, // 2010
0x00, 0x10, 0x04, // 2011
0x4E, 0xE6, 0xD9, // 2012
0x9E, 0xA6, 0xA8, // 2013
0x80, 0x82, 0x18, // 2014
0x00, 0x10, 0x00, // 2015
0x0F, 0xE6, 0xD9, // 2016
0xBE, 0xA6, 0x98, // 2017
0x88, 0x82, 0x18, // 2018
0x80, 0x00, 0x00, // 2019
0x0F, 0xEF, 0xD9, // 2020
0xBE, 0xA6, 0x99, // 2021
0x8C, 0x82, 0x98, // 2022
0x80, 0x00, 0x00, // 2023
0x0F, 0xEF, 0xDB, // 2024
0xBE, 0xA6, 0x99, // 2025
0x9C, 0xA2, 0x98, // 2026
0x80, 0x00, 0x18, // 2027
0x0F, 0xEF, 0xDB, // 2028
0xBE, 0xA6, 0x99, // 2029
0x9C, 0xA2, 0x98, // 2030
0x80, 0x00, 0x18, // 2031
0x0F, 0xEF, 0xDB, // 2032
0xBE, 0xA2, 0x99, // 2033
0x8C, 0xA0, 0x98, // 2034
0x80, 0x82, 0x18, // 2035
0x0B, 0xEF, 0xDB, // 2036
0xBE, 0xA6, 0x99, // 2037
0x8C, 0xA2, 0x98, // 2038
0x80, 0x82, 0x18, // 2039
0x0F, 0xEF, 0xDB, // 2040
0xBE, 0xE6, 0xD9, // 2041
0x9E, 0xA2, 0x98, // 2042
0x80, 0x82, 0x18, // 2043
0x0F, 0xEF, 0xFB, // 2044
0xBF, 0xE6, 0xD9, // 2045
0x9E, 0xA6, 0x98, // 2046
0x80, 0x82, 0x18, // 2047
0x0F, 0xFF, 0xFF, // 2048
0xFC, 0xEF, 0xD9, // 2049
0xBE, 0xA6, 0x18, // 2050
};
static const uint8_t days[24] =
{
6, 20, 4, 19, 6, 21, // 一月到三月 的节气基本日期
5, 20, 6, 21, 6, 21, // 四月到六月 的节气基本日期
7, 23, 8, 23, 8, 23, // 七月到九月 的节气基本日期
8, 24, 8, 22, 7, 22, // 十月到十二月的节气基本日期
};
/*立春、雨水、惊蛰、春分、清明、谷雨、立夏、小满、芒种、夏至、小暑、大暑、立秋、处暑、白露、秋分、寒露、霜降、立冬、小雪、大雪、冬至、小寒、大寒
*
*/
const char JieQiStr[24][7] = {
"小寒",
"大寒",
"立春",
"雨水",
"惊蛰",
"春分",
"清明",
"谷雨",
"立夏",
"小满",
"芒种",
"夏至",
"小暑",
"大暑",
"立秋",
"处暑",
"白露",
"秋分",
"寒露",
"霜降",
"立冬",
"小雪",
"大雪",
"冬至",
};
const uint8_t MonthDayMax[12] = {
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
};
/*********************************************************************************************************
** 函数名称:GetJieQi
** 功能描述:输入公历日期得到本月24节气日期 day<15返回上半月节气,反之返回下半月
** 如:GetJieQiStr(2007,02,08,str) 返回str[0]=4
** 输 入: year 公历年
** month 公历月
** day 公历日
** str 储存对应本月节气日期地址 1Byte
** 输 出: 1 成功
** 0 失败
** 作 者: 赖皮 ★〓个人原创〓★
** 日 期: 2007年02月08日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint8_t GetJieQi(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *JQdate)
{
uint8_t bak1, value, JQ;
if ((myear < 2000) || (myear > 2050))
return 0;
if ((mmonth == 0) || (mmonth > 12))
return 0;
JQ = (mmonth - 1) * 2; // 获得节气顺序标号(023
if (mday >= 15)
JQ++; // 判断是否是上半月
bak1 = YearMonthBit[(myear - 2000) * 3 + JQ / 8]; // 获得节气日期相对值所在字节
value = ((bak1 << (JQ % 8)) & 0x80); // 获得节气日期相对值状态
*JQdate = days[JQ];
if (value != 0)
{
// 判断年份,以决定节气相对值1代表1,还是1。
if ((JQ == 1 || JQ == 11 || JQ == 18 || JQ == 21) && myear < 2044)
(*JQdate)++;
else
(*JQdate)--;
}
return 1;
}
/*********************************************************************************************************
** 函数名称:GetJieQiStr位置
** 如:GetJieQiStr(2007,02,08,day) 返回str="离雨水还有11天" day式距离几天
** 输 入: year 公历年
** month 公历月
** day 公历日
** str 储存24节气字符串地址 15Byte
** 输 出: 1 成功
** 0xFF 失败
** 作 者: 赖皮 ★〓个人原创〓★
** 日 期: 2007年02月08日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint8_t GetJieQiStr(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *day)
{
uint8_t JQdate, JQ, MaxDay;
if (GetJieQi(myear, mmonth, mday, &JQdate) == 0)
return 0xFF;
JQ = (mmonth - 1) * 2; // 获得节气顺序标号(023
if (mday >= 15)
JQ++; // 判断是否是上半月
if (mday == JQdate) // 今天正是一个节气日
{
*day = 0;
return JQ;
}
// 今天不是一个节气日
// StrCopy(str, (uint8_t *)"离小寒还有??天", 15);
if (mday < JQdate) // 如果今天日期小于本月的节气日期
{
mday = JQdate - mday;
}
else // 如果今天日期大于本月的节气日期
{
JQ++;
if (mday < 15)
{
GetJieQi(myear, mmonth, 15, &JQdate);
mday = JQdate - mday;
}
else // 翻月
{
MaxDay = MonthDayMax[mmonth - 1];
if (mmonth == 2) // 润月问题
{
if ((myear % 4 == 0) && ((myear % 100 != 0) || (myear % 400 == 0)))
MaxDay++;
}
if (++mmonth == 13)
mmonth = 1;
GetJieQi(myear, mmonth, 1, &JQdate);
mday = MaxDay - mday + JQdate;
}
}
*day = mday;
return JQ;
}
uint32_t SEC_PER_YR[2] = {31536000, 31622400}; // 闰年和非闰年的秒数
uint32_t SEC_PER_MT[2][12] = {
{2678400, 2419200, 2678400, 2592000, 2678400, 2592000,
2678400, 2678400, 2592000, 2678400, 2592000, 2678400},
{2678400, 2505600, 2678400, 2592000, 2678400, 2592000,
2678400, 2678400, 2592000, 2678400, 2592000, 2678400},
};
#define SECOND_OF_DAY 86400 // 一天多少秒
/**
* @Name : static int is_leap(int yr)
* @Description: 判断是否为闰年
* "非整百年份能被4整除的是闰年。"
* "整百年份能被400整除的是闰年。"
* @In : 待机算的年份
* @Out : 1是闰年 0非闰年
* @Author : Denis
*/
int is_leap(int yr)
{
if (0 == (yr % 100))
return (yr % 400 == 0) ? 1 : 0;
else
return (yr % 4 == 0) ? 1 : 0;
}
/**
* @Name : static unsigned char day_of_week_get(unsigned char month, unsigned char day,
unsigned short year)
* @Description: 根据输入的年月日计算当天为星期几
* @In : 年、月、日
* @Out : 星期几
* @Author : Denis
*/
unsigned char day_of_week_get(unsigned char month, unsigned char day,
unsigned short year)
{
/* Month should be a number 0 to 11, Day should be a number 1 to 31 */
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
year -= (uint8_t)(month < 3);
return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7;
}
void transformTime(uint32_t unix_time, struct devtm *result)
{
int leapyr = 0;
uint32_t ltime = unix_time;
memset(result, 0, sizeof(struct devtm));
result->tm_year = EPOCH_YR;
while (1)
{
if (ltime < SEC_PER_YR[is_leap(result->tm_year)])
{
break;
}
ltime -= SEC_PER_YR[is_leap(result->tm_year)];
++(result->tm_year);
}
leapyr = is_leap(result->tm_year);
while (1)
{
if (ltime < SEC_PER_MT[leapyr][result->tm_mon])
break;
ltime -= SEC_PER_MT[leapyr][result->tm_mon];
++(result->tm_mon);
}
result->tm_mday = ltime / SEC_PER_DY;
++(result->tm_mday);
ltime = ltime % SEC_PER_DY;
result->tm_hour = ltime / SEC_PER_HR;
ltime = ltime % SEC_PER_HR;
result->tm_min = ltime / 60;
result->tm_sec = ltime % 60;
result->tm_wday =
day_of_week_get(result->tm_mon + 1, result->tm_mday,
result->tm_year);
/*
* The number of years since YEAR0"
*/
result->tm_year -= YEAR0;
}
uint8_t map[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/*
获取一个月最后一天值
*/
uint8_t get_last_day(uint16_t year, uint8_t month)
{
if (month % 12 == 1)
{
return map[month % 12] + is_leap(year);
}
return map[month % 12];
}
/*
获取一个月第一天星期值
*/
uint8_t get_first_day_week(uint16_t year, uint8_t month)
{
return day_of_week_get(month, 1, year);
}
// 时间结构体转时间戳
uint32_t transformTimeStruct(struct devtm *result)
{
uint32_t Cyear = 0;
for (uint16_t i = 1970; i < result->tm_year; i++)
{
if (is_leap(i) == 1)
Cyear++;
}
uint32_t CountDay = Cyear * (uint32_t)366 + (uint32_t)(result->tm_year - 1970 - Cyear) * (uint32_t)365 + result->tm_mday - 1;
for (uint8_t i = 0; i < result->tm_mon - 1; i++)
{
CountDay += get_last_day(result->tm_year, i);
}
return (CountDay * SECOND_OF_DAY + (uint32_t)result->tm_sec + (uint32_t)result->tm_min * 60 + (uint32_t)result->tm_hour * 3600);
}
uint8_t thisMonthMaxDays(uint8_t year, uint8_t month)
{
if (year % 4 == 0 && month == 2)
return MonthDayMax[month - 1] + 1;
else
return MonthDayMax[month - 1];
}