#include "calendar.h"
#include
#define GET_DAYOFWEEK_FAILED 0xff
#define LUNAR_CALENDAR_TABLE_SIZE (MAX_YEAR - MIN_YEAR + 1)
#define MONTH_TABLE_SIZE 12
#define GET_SPRING_FESTIVAL_DAY(n) (BYTE)((DWORD)(n) & 0x0000001f)
#define GET_SPRING_FESTIVAL_MONTH(n) (BYTE)(((DWORD)(n) & 0x00000060) >> 5)
#define GET_LUNAR_MONTH_BITS(n) (WORD)(((DWORD)(n) & 0x000fff80) >> 7)
#define GET_LUNAR_LEAP_MONTH(n) (BYTE)(((DWORD)(n) & 0x00f00000) >> 20)
#define LUNAR_FIRST_MONTH_OFFSET 12
#define MAX_LUNAR_MONTH 13 //阴历最多月份数
#define LUNAR_LITTLE_MONTH_DAYS 29 //阴历小月的天数
#define LEAP_MONTH_DAYS 29 //阳历闰月的天数
#define IS_LEAP_YEAR(year) ((((WORD)(year) % 4 == 0) && ((WORD)(year) % 100 != 0)) || ((WORD)(year) % 400 == 0))
//每月1号距离元旦的天数,不考虑闰年
code const WORD g_wDaysToNewYearDayTable[MONTH_TABLE_SIZE] =
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
//每月的天数,不考虑闰年
code const BYTE g_MonthDaysTable[MONTH_TABLE_SIZE] =
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/***********************************************************************************************
100年农历公历对应数表
格式: b23-b20 表示闰月月份,无闰月用0表示
b19-b7 表示农历第1 - 13月的大小,其中1表示大月(对应30天),0表示小月(对应29天)
b6-b5表示当年春节对应公历月份,其中1表示1月,2表示2月
b4-b0表示当年春节对应公历当月的日期
**********************************************************************************************/
code const DWORD g_dwLunarCalendarTable[LUNAR_CALENDAR_TABLE_SIZE] =
{
0x0C9645, 0x4D4AB8, 0x0D4A4C, 0x0DA541, 0x25AAB6, 0x056A49, 0x7AADBD, 0x025D52, 0x092D47, 0x5C95BA, //2000-2009
0x0A954E, 0x0B4A43, 0x4B5537, 0x0AD54A, 0x955ABF, 0x04BA53, 0x0A5B48, 0x652BBC, 0x052B50, 0x0A9345, //2010-2019
0x474AB9, 0x06AA4C, 0x0AD541, 0x24DAB6, 0x04B64A, 0x69573D, 0x0A4E51, 0x0D2646, 0x5E933A, 0x0D534D, //2020-2029
0x05AA43, 0x36B537, 0x096D4B, 0xB4AEBF, 0x04AD53, 0x0A4D48, 0x6D25BC, 0x0D254F, 0x0D5244, 0x5DAA38, //2030-2039
0x0B5A4C, 0x056D41, 0x24ADB6, 0x049B4A, 0x7A4BBE, 0x0A4B51, 0x0AA546, 0x5B52BA, 0x06D24E, 0x0ADA42, //2040-2049
/*
0x355B37, 0x09374B, 0x8497C1, 0x049753, 0x064B48, 0x66A53C, 0x0EA54F, 0x06B244, 0x4AB638, 0x0AAE4C, //2050-2059
0x092E42, 0x3C9735, 0x0C9649, 0x7D4ABD, 0x0D4A51, 0x0DA545, 0x55AABA, 0x056A4E, 0x0A6D43, 0x452EB7, //2060-2069
0x052D4B, 0x8A95BF, 0x0A9553, 0x0B4A47, 0x6B553B, 0x0AD54F, 0x055A45, 0x4A5D38, 0x0A5B4C, 0x052B42, //2070-2079
0x3A93B6, 0x069349, 0x7729BD, 0x06AA51, 0x0AD546, 0x54DABA, 0x04B64E, 0x0A5743, 0x452738, 0x0D264A, //2080-2089
0x8E933E, 0x0D5252, 0x0DAA47, 0x66B53B, 0x056D4F, 0x04AE45, 0x4A4EB9, 0x0A4D4C, 0x0D1541, 0x2D92B5, //2090-2099
*/
};
static BOOL IsDateValid(const DATE* pDate)
{
if(pDate == NULL)
return FALSE;
if(pDate->wYear < MIN_YEAR || pDate->wYear > MAX_YEAR)
return FALSE;
if(pDate->Month == 0 || pDate->Month > 12)
return FALSE;
if(pDate->Day == 0 || pDate->Day > g_MonthDaysTable[pDate->Month - 1])
{
if(IS_LEAP_YEAR(pDate->wYear) && pDate->Month == 2 && pDate->Day == LEAP_MONTH_DAYS)
{
return TRUE;
}
return FALSE;
}
return TRUE;
}
//计算所求日期是本年中的第几天
static WORD GetDayOfYear(const DATE* pDate)
{
WORD wDayOfYear = g_wDaysToNewYearDayTable[pDate->Month - 1] + pDate->Day;
if(pDate->Month > 2 && IS_LEAP_YEAR(pDate->wYear))
{
return wDayOfYear + 1; //闰年多加一天
}
return wDayOfYear;
}
/*
W = [Y-1] + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + D
Y是年份数,D是这一天在这一年中的累积天数,也就是这一天在这一年中是第几天
*/
BYTE GetDayOfWeek(const DATE* pDate)
{
WORD wTempYear = 0;
BYTE nDayOfWeek = 0;
if(pDate == NULL)
return GET_DAYOFWEEK_FAILED;
if(!IsDateValid(pDate))
return GET_DAYOFWEEK_FAILED;
wTempYear = pDate->wYear - 1;
return ((pDate->wYear - 1) + (pDate->wYear - 1) / 4
- (pDate->wYear - 1) / 100 + (pDate->wYear - 1) / 400 + GetDayOfYear(pDate)) % 7;
// nDayOfWeek = (wTempYear + wTempYear / 4 - wTempYear / 100 + wTempYear / 400 + GetDayOfYear(pDate)) % 7;
// return nDayOfWeek ? nDayOfWeek : 7;
}
BOOL GetLunarDate(const DATE* pDate, DATE* pLunarDate)
{
idata DWORD dwLunarCalendar = 0;
idata WORD wSpringFestivalOfYear = 0;
idata WORD wDayOfYear = 0;
BYTE LunarLeapMonth = 0;
WORD wLunarMonthBits = 0;
BYTE i = 0 ;
BYTE j = 0;
WORD wTempDays = 0;
WORD wDaysToSpringFestival = 0; //距春节的天数,或在春节前或在春节后
idata DATE tempDate;
if(pDate == NULL || pLunarDate == NULL)
return FALSE;
dwLunarCalendar = g_dwLunarCalendarTable[pDate->wYear - MIN_YEAR];
tempDate.wYear = pDate->wYear;
tempDate.Month = GET_SPRING_FESTIVAL_MONTH(dwLunarCalendar);
tempDate.Day = GET_SPRING_FESTIVAL_DAY(dwLunarCalendar);
wSpringFestivalOfYear = GetDayOfYear(&tempDate);
wDayOfYear = GetDayOfYear(pDate);
LunarLeapMonth = GET_LUNAR_LEAP_MONTH(dwLunarCalendar);
wLunarMonthBits = GET_LUNAR_MONTH_BITS(dwLunarCalendar);
if(!IsDateValid(pDate))
return FALSE;
if(wDayOfYear >= wSpringFestivalOfYear) //所求的日期在春节后面或当天
{
wDaysToSpringFestival = wDayOfYear - wSpringFestivalOfYear;
for (i = 0; i < MAX_LUNAR_MONTH; i++)
{
j = (BYTE)TEST_BIT(wLunarMonthBits, LUNAR_FIRST_MONTH_OFFSET - i);
wTempDays += (LUNAR_LITTLE_MONTH_DAYS + j);
//若已经超出相距天数则说明所求日期就在农历当月
if (wTempDays > wDaysToSpringFestival)
{
pLunarDate->Day = (LUNAR_LITTLE_MONTH_DAYS + j) - (wTempDays - wDaysToSpringFestival) + 1;
//若是在闰月或是在闰月之后则调整月份
if (LunarLeapMonth != 0 && i >= LunarLeapMonth)
{
pLunarDate->Month = i;
}
else
{
pLunarDate->Month = i + 1;
}
pLunarDate->wYear = pDate->wYear;
break;
}
}
}
/**********************************************************
在MIN_YEAR ~ MAX_YEAR内,没有闰腊月
***********************************************************/
if(wDayOfYear < wSpringFestivalOfYear) //所求的日期在春节前面
{
pLunarDate->wYear = pDate->wYear - 1;
wDaysToSpringFestival = wSpringFestivalOfYear - wDayOfYear;
if (LunarLeapMonth == 0) //若无闰月,将农历月份信息向右移动一位,使第一位是腊月
{
wLunarMonthBits >>= 1;
}
i = (BYTE)(wLunarMonthBits & 0x0001); //腊月是否是大月
j = (BYTE)((wLunarMonthBits & 0x0002) >> 1); //11月是否是大月
if (wDaysToSpringFestival Month = 12;
pLunarDate->Day = (LUNAR_LITTLE_MONTH_DAYS + i) - wDaysToSpringFestival + 1;
}
else
{
pLunarDate->Month = 11;
pLunarDate->Day = (LUNAR_LITTLE_MONTH_DAYS + j) - (wDaysToSpringFestival - (LUNAR_LITTLE_MONTH_DAYS + i)) + 1;
}
}
return TRUE;
}
复制代码