cal

10 篇文章 0 订阅
#ifndef TERM_H
#define TERM_H
#include <string>
using namespace std;

#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
struct Term
{
    char month;    // 1-12
    char day;      // 1-31
    char h;        // 0-23
    char m;        // 0-59
    char s;        // 0-59
};
struct LunarSolarDate
{
    int  year;      // 公历年
    char month;     // 1-12
    char day;       // 1-31 公历日
    char week;      // 0-6
    int  lunarY;    // 农历年,首尾法
    char lunarM;    // 1-12
    char lunarD;    // 1-30
    bool isLeapM;   // 是否闰月
    
    long monCyl;    // 干支 月,首尾法,干支月和农历月完全吻合
    long dayCyl;    // 干支 日
    long cycTermM;  // 干支 月,以时令法,以节气开始至下个节气前一天为干支月
    long cycTermY;  // 干支 年,时令法
};

struct MyDate
{
    int     year;
    char    month;
    char    day;
    bool    isLeap;
    long    monCyl;
    long    dayCyl;
};
// 根据输入的公历年号和月份,返回该月的天数 
int MonthDays(int year, int month);
// 根据输入的公历日期,返回对应的星期
int WeekDay(int year, int month, int day);
// 传回农历 y年的总天数 
long LunarYearDays(long y);
// 传回农历 y年闰月的天数
long LunarLeapDays(long y);
// 传回农历 y年闰哪个月 1-12 , 没闰传回 0 
long LunarLeapMonth(long y);
// 传回农历 y年m月的总天数 
long LunarMonthDays(long y, long m);
// 传入 offset 传回干支, 0=甲子
void Cyclical(long offset, char GanZhi[5]);
// 根据公历年月日,返回农历信息 dateOut
void Lunar(int year, int month, int day, MyDate & dateOut);
// 返回农历日day的汉子表示, day 取值返回 1-30
string LunarDay(char day);
/*
 * 全局变量声明
 */
extern char solarTerm[][5];
extern int baseYear;
extern int TotalYear;
extern long lunarInfo[];
class CCalendar
{
public:
    CCalendar(int year, int month);
    // 公历的 y 年 m 月 d 日 是否为农历节气,如果是,则返回 0 - 23。否则返回 -1。
    int IsTerm(int y, int m, int d, Term & term);
    int GetTerm(int y, int n, Term & term);
    // 公历的 y 年 m 月 d 日 以时令法 划分的 干支月
    int GetTermMonth(int y, int m, int d);
    // 生成时令法的干支年月
    int GenTermGanzhi(LunarSolarDate & ld);
    int GenTermGanzhi(int y, int m, int d, int &cycY, int &cycM);
    void OutPut();
protected:
private:
    LunarSolarDate m_day[31];   // 公历月最多31天
    char m_dayNum;      // 公历月的天数
    char m_month;       // 公历月 1-12
    int  m_year;        // 公历年
};
#endif
 
/

#include "stdafx.h"
#include "term.h"
#include <math.h>
#include <string.h>
// 公历平年每月的天数
char g_solarMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
// 天干, 地支
char Gan[][3] = {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
char Zhi[][3] = {"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
char solarTerm[][5] ={"小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"};
int baseYear = 1899;    // 公历 1900.1.1对应的农历:1899.12.1
long lunarInfo[] = {
0x0ab50,
0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,  // 农历1900-1909
0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,  // 1910
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,  // 1920
0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,  // 1930
0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,  // 1940
0x06ca0,0x0b550,0x15355,0x04da0,0x0a5d0,0x14573,0x052d0,0x0a9a8,0x0e950,0x06aa0,  // 1950
0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0, 
0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b5a0,0x195a6,  // 1970
0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570, 
0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,  // 1990
0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,  // 2000-2009
0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,  // 2010
0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,  // 2020-2029
0x05aa0,0x076a3,0x096d0,0x04afb,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45, 
0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0,  // 2040-2049
0x14B63,0x09370,0x049F8
};
int TotalYear = sizeof(lunarInfo)/sizeof(long) + baseYear;

Term g_term[][24] = {
    { { 1, 5,19, 8,46}, { 1,20,12,27,41}, { 2, 4, 6,47,50}, { 2,14,10,51,17}
    , { 3, 6, 0,42,22}, { 3,21, 1,32,12}, { 4, 5, 5,30,29}, { 4,20,12,29,47}
    , { 5, 5,22,44, 1}, { 5,21,11,33,54}, { 6, 6, 2,49,23}, { 6,21,19,28,24}
    , { 7, 7,13, 2,23}, { 7,23, 6,21,12}, { 8, 7,22,49,07}, { 8,23,13,26,57}
    , { 9, 8, 1,44,39}, { 9,23,11, 9,02}, {10, 8,17,26,29}, {10,23,20,35, 3}
    , {11, 7,20,42,28}, {11,22,18,14,32}, {12, 7,13,38,21}, {12,22,07,38,26}
    } // 以上为 2010
    ,{{ 1, 6, 0,54,36}, { 1,20,18,18,31}, { 2, 4,12,32,55}, { 2,19, 8,25,19}
    , { 3, 6, 6,29,58}, { 3,21, 7,20,44}, { 4, 5,11,11,58}, { 4,20,18,17,27}
    , { 5, 6, 4,23,14}, { 5,21,17,21,11}, { 6, 6, 8,27,21}, { 6,22, 1,16,30}
    , { 7, 7,18,42, 1}, { 7,23,12,11,49}, { 8, 8, 4,33,27}, { 8,23,19,20,38}
    , { 9, 8, 7,34,12}, { 9,23,17, 4,37}, {10, 8,23,19, 4}, {10,24, 2,30,17}
    , {11, 8, 2,34,54}, {11,23, 0, 7,47}, {12, 7,19,28,59}, {12,22,13,30, 1}
    } // 以上为 2011
    ,{{ 1, 6, 6,43,54}, { 1,21, 0, 9,48}, { 2, 4,18,22,21}, { 2,19,14,17,34}
    , { 3, 5,12,21, 2}, { 3,20,13,14,25}, { 4, 4,17, 5,36}, { 4,20, 0,12, 4}
    , { 5, 5,10,19,40}, { 5,20,23,15,31}, { 6, 5,14,25,53}, { 6,21, 7, 8,48}
    , { 7, 7, 0,40,43}, { 7,22,18, 0,52}, { 8, 7,10,30,32}, { 8,23, 1, 6,50}
    , { 9, 7,13,29, 0}, { 9,22,22,49, 0}, {10, 8, 5,11,43}, {10,23, 8,13,33}
    , {11, 7, 8,25,56}, {11,22, 5,50, 7}, {12, 7, 1,18,55}, {12,21,19,11,36}
    } // 以上为 2012
};
int g_baseY = 2010; // 公历年
int g_maxY = sizeof(g_term)/sizeof(Term)/24 + g_baseY;

CCalendar::CCalendar(int year, int month):m_year(year), m_month(month)
{
    m_dayNum = MonthDays(year, month);
    int day = 1;
    int w = WeekDay(year, month, day);
    MyDate lunarDate;
    Lunar(year, month, day, lunarDate);
    int nLunarTotalDay = lunarDate.isLeap ? LunarLeapDays(year):LunarMonthDays(year, month);
    for (int i=0; i < m_dayNum; ++i)
    {
        if (lunarDate.day > nLunarTotalDay)
        {
            Lunar(year, month, day, lunarDate);
            nLunarTotalDay = lunarDate.isLeap ? LunarLeapDays(year):LunarMonthDays(year, month);
        }
        m_day[i].year   = m_year;
        m_day[i].month  = m_month;
        m_day[i].day    = day++;
        m_day[i].week   = w++;
        m_day[i].lunarY = lunarDate.year;
        m_day[i].lunarM = lunarDate.month;
        m_day[i].lunarD = lunarDate.day++;
        m_day[i].isLeapM= lunarDate.isLeap;
        if (w == 7) w = 0;
    }
}
// 公历的 y 年 m 月 d 日 是否为农历节气,如果是,则返回 0 - 23。否则返回 -1。
// m 取值 1 - 12
// d 取值 1 - 31
int CCalendar::IsTerm(int y, int m, int d, Term & term)
{
    if (y<g_baseY || y>=g_maxY) 
        return -1;
    int s = (m-1)*2;
    if (g_term[y-g_baseY][s].day == d) {
        term = g_term[y-g_baseY][s];
        return s;
    }
    else if (g_term[y-g_baseY][s+1].day == d) {
        term = g_term[y-g_baseY][s+1];
        return s+1;
    }
    return -1;
}
// 取 y 年的 第 n+1 个节气
// n 取值:0 - 23
int CCalendar::GetTerm(int y, int n, Term & term)
{
    if (y<g_baseY || y>=g_maxY) 
        return -1;
    term = g_term[y-g_baseY][n];
    return 0;
}
// 月纪的起算时间
// 一月 寅月       二月 卯月       三月 辰月       四月 巳月       五月 午月       六月 未月
// 从立春到惊蛰    从惊蛰到清明    从清明到立夏    从立夏到芒种    从芒种到小暑    从小暑到立秋
// 
// 七月 申月       八月 酉月       九月 戌月       十月 亥月       十一月 子月     十二月 丑月
// 从立秋到白露    从白露到寒露    从寒露到立冬    从立冬到大雪    从大雪到小寒    从小寒到立春
// 公历的 y 年 m 月 d 日 以时令法 划分的 干支月
int CCalendar::GetTermMonth(int y, int m, int d)
{
    if (y<g_baseY || y>=g_maxY) 
        return -1;
    int nTermMonth = (m==1) ? 12 : m-1;
    int s = (m-1)*2;
    if (d < g_term[y-g_baseY][s].day) {
        -- nTermMonth;
        if (nTermMonth == 0)
            nTermMonth = 12;
    }
    
    return nTermMonth;
}
// 生成时令法的干支年月
int CCalendar::GenTermGanzhi(LunarSolarDate & ld)
{
    int nTermMonth = GetTermMonth(ld.year, ld.month, ld.day);
    // 节气在农历月首之后
    if (ld.lunarM == 1 && nTermMonth == 12) 
    {
        ld.cycTermM = ld.monCyl - 1;
        ld.cycTermY = ld.lunarY - 1;
    }
    else if (ld.lunarM - nTermMonth == 1)
    {
        ld.cycTermM = ld.monCyl - 1;
        ld.cycTermY = ld.lunarY;
    }
    else if (ld.lunarM == 12 && nTermMonth == 1)
    {
        ld.cycTermM = ld.monCyl + 1;
        ld.cycTermY = ld.lunarY + 1;
    }
    else if (nTermMonth - ld.lunarM == 1)
    {
        ld.cycTermM = ld.monCyl + 1;
    }
    else
    {
        ld.cycTermM = ld.monCyl;
        ld.cycTermY = ld.lunarY;
    }
    
    return 0;
}
int CCalendar::GenTermGanzhi(int y, int m, int d, int &cycY, int &cycM)
{
    MyDate lunarDate;
    Lunar(y, m, d, lunarDate);
    LunarSolarDate ld;
    ld.year     = y;
    ld.month    = m;
    ld.day      = d;
    ld.lunarY   = lunarDate.year;
    ld.lunarM   = lunarDate.month;
    ld.lunarD   = lunarDate.day;
    ld.isLeapM  = lunarDate.isLeap;
    ld.monCyl   = lunarDate.monCyl;
    ld.dayCyl   = lunarDate.dayCyl;
    GenTermGanzhi(ld);
    cycY = ld.cycTermY;
    cycM = ld.cycTermM;
    return 0;
}
void CCalendar::OutPut()
{
    int i;
    printf("--------------------------------------------------------/n");
 printf("%22d 年 %d 月/n", m_year, m_month); 
    printf("    周日    周一    周二    周三    周四    周五    周六/n/n");
    
    // 对齐1号的星期
    for(i = 0; i < m_day[0].week; ++i)
    {
        printf("        ");
    }
    Term term;
    int idx;
    for(i = 0; i < m_dayNum; ++i)
    {
        printf("%4d", m_day[i].day);
        idx = IsTerm(m_year, m_month, m_day[i].day, term);
        if (idx != -1) // 如果是 二十四节气之一,则显示节气
            printf("%s", solarTerm[idx]);
        else
            printf("%s", LunarDay(m_day[i].lunarD).c_str());
        if (m_day[i].week == 6) printf("/n/n");
    }
    printf("/n");

    char GanZhi[5];
    for (i = 1; i < 10; ++i)
    {
        MyDate d1;
        Lunar(m_year, 2, i, d1);
        printf("公历%d年%d月%d日对应的干支(首尾法)", m_year, 2, i);
        Cyclical(d1.year-1864, GanZhi);
        printf("%s年 ", GanZhi);
        Cyclical(d1.monCyl, GanZhi);
        printf("%s月 ", GanZhi);
        Cyclical(d1.dayCyl, GanZhi);
        printf("%s日", GanZhi);
        printf("  时令法:");
        int yearCyc, monCyc;
        GenTermGanzhi(m_year, 2, i, yearCyc, monCyc);
        Cyclical(yearCyc-1864, GanZhi);
        printf("%s年 ", GanZhi);
        Cyclical(monCyc, GanZhi);
        printf("%s月/n", GanZhi);
    }
}
// 根据输入的公历年号和月份,返回该月的天数
int MonthDays(int year, int month)
{
   if(month==2)
      return isleap(year)? 29: 28;
   else
      return g_solarMonth[month-1];
}

// 根据输入的公历日期,返回对应的星期
int WeekDay(int year, int month, int day)
{
//  万年历的公式:S=X-1+(X-1)/4-(X-1)/100+(X-1)/400+C
//  说明:X为公元年数;
//        C为从元旦起,到要算的那天总天数(如:2003年2月13日,C=31+13=44)
//        S/7余数为星期几(如余数为0,1,2,3,4,5,6。分别为星期天,星期一,二,
//    三,四,五,六)
 long sum = year-1 + (year-1)/4 - (year-1)/100 + (year-1)/400;
 for(int i=1; i<month; i++)
  sum += MonthDays(year, i);
 sum += day;
 return (int)sum%7;
}

//------------------------------------------------------------------------------
// 传回农历 y年的总天数 
long LunarYearDays(long y) 
{ 
   long i, sum = 348; // 29 * 12
   for(i=0x8000; i>0x8; i>>=1)
    sum += (lunarInfo[y-baseYear] & i)? 1: 0 ;
   return(sum+LunarLeapDays(y));
}
// 传回农历 y年闰月的天数 
long LunarLeapDays(long y)
{ 
 if(LunarLeapMonth(y))
  return((lunarInfo[y-baseYear] & 0x10000)? 30: 29); 
 else
  return(0);
}
// 传回农历 y年闰哪个月 1-12 , 没闰传回 0 
long LunarLeapMonth(long y) 
{ 
   return(lunarInfo[y-baseYear] & 0xf);
}
// 传回农历 y年m月的总天数 
long LunarMonthDays(long y, long m) 
{ 
   return( (lunarInfo[y-baseYear] & (0x10000>>m))? 30: 29 );
}

// 传入 offset 传回干支, 0=甲子
void Cyclical(long offset, char GanZhi[5]) {
    long i = offset % 60;
    if (i < 0)
        i += 60;
    strcpy(GanZhi, Gan[i%10]);
    strcat(GanZhi, Zhi[i%12]);
}

// 根据公历年月日,返回农历信息 dateOut
void Lunar(int year, int month, int day, MyDate & dateOut)
{
 int i;
 int run=0, ping=0; // 闰年和平年个数
    long temp;
 long sum;
    // 公历1900.1.31为农历的 乙亥年 戊寅月 甲辰日 正月初一
    dateOut.monCyl = 14; // 戊寅月
    dateOut.dayCyl = 40; // 甲辰日
    if ( year>1900 || year==1900 && (month>1 || day==31) )
    {
        // 计算当前时间 和 1900.1.31 之间的天数差
        for(i=1900; i<year; i++) 
        {
            if(isleap(i))
                run++;
            else
                ping++;
        }
        // 计算总天数 
        sum = 366*run + 365*ping;
        for(i=1; i<month; i++)
            sum += MonthDays(year, i);
        sum += day;
        sum -= 31;
        dateOut.dayCyl += sum;
        
        for(i=1900; i<TotalYear && sum>0; i++) 
        {
            temp = LunarYearDays(i);
            sum -= temp;
            dateOut.monCyl += 12;
        }
        
        if(sum<0)
        {
            sum += temp;
            i--;
            dateOut.monCyl -= 12;
        }
        dateOut.year = i;
    }
    else // 1900.1.31日之前的公历日期
    {
        // 计算当前时间 和 1900.1.31 之间的天数差
        if (year==1900) {
            sum = 31-day;
        }
        else
        {
            for(i=1899; i>year; --i) 
            {
                if(isleap(i))
                    run++;
                else
                    ping++;
            }
            // 计算总天数 
            sum = 366*run + 365*ping;
            for(i=month+1; i<13; ++i)
                sum += MonthDays(year, i);
            sum += MonthDays(year, month) - day;
            sum +=31;
        }
        dateOut.dayCyl -= sum;
        for(i=1899; i>=baseYear && sum>0; i--) {
            sum -= LunarYearDays(i);
            dateOut.monCyl -= 12;
        }
        if (sum<0)  // 此处,如果sum 大于 0, 则出错,超出农历年的范围
            sum = -sum;
        dateOut.year = i+1;
    }
    int leap = LunarLeapMonth(dateOut.year); // 闰哪个月
    for (i=1; i<13; ++i)
    {
        temp = LunarMonthDays(dateOut.year, i);
        if (sum >= temp)
            sum -= temp;
        else
        {
            dateOut.month = i;
            dateOut.day = sum + 1;
            dateOut.isLeap = false;
            break;
        }
        if (i == leap) // 闰月
        {
            temp = LunarLeapDays(dateOut.year);
            if (sum >= temp)
                sum -= temp;
            else
            {
                dateOut.month = i;
                dateOut.day = sum + 1;
                dateOut.isLeap = true;
                break;
            }
        }
        dateOut.monCyl ++;
    }
}
// 返回农历日day的汉子表示, day 取值返回 1-30
string LunarDay(char day)
{
 string s;
    s.resize(4);
 static char nStr1[][3] = {"日","一","二","三","四","五","六","七","八","九","十"};
 static char nStr2[][3] = {"初","十","廿","卅"};
   
 switch (day) {
 case 10:
  s = "初十"; break;
 case 20:
  s = "二十"; break;
  break;
 case 30:
  s = "三十"; break;
  break;
 default :
  s = nStr2[(int)floor(day/10)];
  s+= nStr1[day%10];
 }
 return(s);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值