#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; // 获得节气顺序标号(0~23 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; // 获得节气顺序标号(0~23 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]; }