#include "stdafx.h"
#include "string.h"
#include "math.h"
#include "string"
#include "time.h"
#include "math.h"
#include <windows.h>
using namespace std;
// Calendar.cpp : Defines the entry point for the console application.
//
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
long lYearDays(long y) ;
long leapMonth(long y);
long leapDays(long y);
long monthDays(long y, long m);
//====================== 中文日期
string cDay(unsigned char day);
typedef struct
{
unsigned short year;
unsigned char month;
unsigned char day;
bool isLeap;
} MyDate;
void Lunar(MyDate& dateIn, MyDate & dateOut);
void Lunar(long offset, MyDate & dateOut);
// ---------------------------------------------------------------------------
/*
萬年曆全集
程序可以實現如下三種功能:
求某個日期對應的星期
求某年某月有的天數
輸出某年的日曆.
例如,打印2008年日曆如下:
-------------------------------------------------------------------------
2008 年
--------------------------------------------------------------------------
一 月 二 月
週日 週一 週二 週三 週四 週五 週六 週日 週一 週二 週三 週四 週五 週六
1 2 3 4 5 1 2
6 7 8 9 10 11 12 3 4 5 6 7 8 9
13 14 15 16 17 18 19 10 11 12 13 14 15 16
20 21 22 23 24 25 26 17 18 19 20 21 22 23
27 28 29 30 31 24 25 26 27 28 29
三 月 四 月
週日 週一 週二 週三 週四 週五 週六 週日 週一 週二 週三 週四 週五 週六
1 1 2 3 4 5
2 3 4 5 6 7 8 6 7 8 9 10 11 12
9 10 11 12 13 14 15 13 14 15 16 17 18 19
16 17 18 19 20 21 22 20 21 22 23 24 25 26
23 24 25 26 27 28 29 27 28 29 30
30 31
五 月 六 月
週日 週一 週二 週三 週四 週五 週六 週日 週一 週二 週三 週四 週五 週六
1 2 3 1 2 3 4 5 6 7
4 5 6 7 8 9 10 8 9 10 11 12 13 14
11 12 13 14 15 16 17 15 16 17 18 19 20 21
18 19 20 21 22 23 24 22 23 24 25 26 27 28
25 26 27 28 29 30 31 29 30
七 月 八 月
週日 週一 週二 週三 週四 週五 週六 週日 週一 週二 週三 週四 週五 週六
1 2 3 4 5 1 2
6 7 8 9 10 11 12 3 4 5 6 7 8 9
13 14 15 16 17 18 19 10 11 12 13 14 15 16
20 21 22 23 24 25 26 17 18 19 20 21 22 23
27 28 29 30 31 24 25 26 27 28 29 30
31
九 月 十 月
週日 週一 週二 週三 週四 週五 週六 週日 週一 週二 週三 週四 週五 週六
1 2 3 4 5 6 1 2 3 4
7 8 9 10 11 12 13 5 6 7 8 9 10 11
14 15 16 17 18 19 20 12 13 14 15 16 17 18
21 22 23 24 25 26 27 19 20 21 22 23 24 25
28 29 30 26 27 28 29 30 31
十一 月 十二 月
週日 週一 週二 週三 週四 週五 週六 週日 週一 週二 週三 週四 週五 週六
1 1 2 3 4 5 6
2 3 4 5 6 7 8 7 8 9 10 11 12 13
9 10 11 12 13 14 15 14 15 16 17 18 19 20
16 17 18 19 20 21 22 21 22 23 24 25 26 27
23 24 25 26 27 28 29 28 29 30 31
30
// 二,打印版(:即既能輸出到屏幕,又可輸出到文件)
/*萬年曆全集:程序可以實現如下三種功能:
求某個日期對應的星期
求某年某月有的天數
輸出某年的日曆
*/
/*2006-1-2 樑見斌*/
#include <stdlib.h>
#include <stdio.h>
struct mon
{
int maxdata;
int data;
};
void SeekWeekDay(void); //求某個日期對應的星期函數
int WeekDay(int year, int month, int day); //根據輸入的日期,返回對應的星期
void HowManyDays(void);//求某年某月有的天數函數
int MonthDays(int year, int month);//根據輸入的年號和月份,返回該月的天數
void PrintWeek(int weekday, FILE *fp);//打印星期幾
void PrintMonth(int month, FILE *fp); //打印月份
void PrintData(); //打印日曆
void TestYear();
int main(void)
{
int choice;
// 400年中有97個閏年
// int j = 0;
// for (int i=1900; i<2299; ++i)
// {
// if (isleap(i))
// {
// printf("%d ", i);
// ++j;
// if ((j%10)==0)
// {
// printf("/n");
// }
// }
// }
// printf("/n");
while (1) {
TestYear();
}
while(1)
{
puts("------------------------------------------");
puts("請輸入您的選擇:");
puts("輸入1求某個日期對應的星期");
puts("輸入2求某年某月有的天數");
puts("輸入3輸出某年的日曆");
puts("輸入4結束程序");
puts("------------------------------------------");
scanf("%d", &choice); fflush(stdin);
switch(choice)
{
case 1: SeekWeekDay(); break;
case 2: HowManyDays(); break;
case 3: PrintData(); break;
case 4: return 0;
default: puts("輸入錯誤,請重新輸入"); break;
}
printf("/n"); printf("/n");
}
system("pause");
return 0;
}
// 求某年某月有的天數函數
void HowManyDays(void)
{
int year, month, days;
puts("請輸入年號和月份:");
scanf("%d%d", &year, &month); fflush(stdin);
printf("你的輸入爲 %d年%d月,", year, month);
days = MonthDays(year, month); // 根據輸入的年號和月份,返回該月的天數
printf(" %d年%d月有%d天/n", year, month, days);
}
// 求某個日期對應的星期函數
void SeekWeekDay(void)
{
FILE *fp;
int year, month, day, weekday;
if ( (fp=fopen("wnlweek.txt","w+")) == NULL)
{
fprintf(stderr,"/nError opening file/n");
exit(1);
}
puts("請輸入年,月, 日:");
scanf("%d%d%d", &year, &month, &day); fflush(stdin);
printf("你的輸入爲 %d年%d月%d日/n", year, month, day);
weekday = WeekDay(year, month, day); // 根據輸入的日期,返回對應的星期
printf("這天是 ");
PrintWeek(weekday, fp); // 打印星期幾
}
// 打印星期幾
void PrintWeek(int weekday, FILE *fp)
{
switch(weekday)
{
case 0 : fprintf(stdout, "%s","週日 "); fprintf(fp, "%s","週日 "); break;
case 1 : fprintf(stdout, "%s","週一 "); fprintf(fp, "%s","週一 "); break;
case 2 : fprintf(stdout, "%s","週二 "); fprintf(fp, "%s","週二 "); break;
case 3 : fprintf(stdout, "%s","週三 "); fprintf(fp, "%s","週三 "); break;
case 4 : fprintf(stdout, "%s","週四 "); fprintf(fp, "%s","週四 "); break;
case 5 : fprintf(stdout, "%s","週五 "); fprintf(fp, "%s","週五 "); break;
case 6 : fprintf(stdout, "%s","週六 "); fprintf(fp, "%s","週六 "); break;
}
}
void PrintMonth(int month, FILE *fp) //打印月份
{
switch(month)
{
case 1 : fprintf(stdout, "%s","一 月 "); fprintf(fp, "%s","一 月 ");break;
case 2 : fprintf(stdout, "%s","二 月 "); fprintf(fp, "%s","二 月 ");break;
case 3 : fprintf(stdout, "%s","三 月 "); fprintf(fp, "%s","三 月 ");break;
case 4 : fprintf(stdout, "%s","四 月 "); fprintf(fp, "%s","四 月 ");break;
case 5 : fprintf(stdout, "%s","五 月 "); fprintf(fp, "%s","五 月 ");break;
case 6 : fprintf(stdout, "%s","六 月 "); fprintf(fp, "%s","六 月 ");break;
case 7 : fprintf(stdout, "%s","七 月 "); fprintf(fp, "%s","七 月 ");break;
case 8 : fprintf(stdout, "%s","八 月 "); fprintf(fp, "%s","八 月 ");break;
case 9 : fprintf(stdout, "%s","九 月 "); fprintf(fp, "%s","九 月 ");break;
case 10: fprintf(stdout, "%s","十 月 "); fprintf(fp, "%s","十 月 ");break;
case 11: fprintf(stdout, "%s","十一 月 "); fprintf(fp, "%s","十一 月 ");break;
case 12: fprintf(stdout, "%s","十二 月 "); fprintf(fp, "%s","十二 月 ");break;
}
}
// 根據輸入的日期,返回對應的星期
int WeekDay(int year, int month, int day)
{
int i;
int run=0, ping=0; // 閏年和平年個數
long sum;
// for(i=1; i<year; i++) {
// if(i%4==0 && i%100!=0 || i%400==0)
// run++;
// else
// ping++;
// }
// // 計算總天數
// sum = 366*run + 365*ping;
// for(i=1; i<month; i++)
// sum += MonthDays(year, i);
// sum += 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。分別爲星期天,星期一,二,
三,四,五,六)
*/
sum = year-1 + (year-1)/4 - (year-1)/100 + (year-1)/400;
for(i=1; i<month; i++)
sum += MonthDays(year, i);
sum += day;
return (int)sum%7;
}
// 根據輸入的年號和月份,返回該月的天數
int MonthDays(int year, int month)
{
switch(month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: return 31;
case 4:
case 6:
case 9:
case 11: return 30;
case 2:
if(year%4==0 && year%100!=0 || year%400==0)
return 29;
else
return 28;
default: puts("這是一個錯誤的月份!"); system("pause"); return 0;
}
}
// 打印日曆,對輸出格式的控制較複雜
void PrintData(void)
{
FILE *fp;
struct mon month[13];
int i, j, k;
int year, mon, week;
if ( (fp=fopen("wnldata.txt","w+")) == NULL)
{
fprintf(stderr,"/nError opening file/n");
exit(1);
}
puts("請輸入年號:");
scanf("%d", &year);
fprintf(stdout, "--------------------------------------------------------------------------/n");
fprintf(fp, "--------------------------------------------------------------------------/n");
fprintf(stdout, "%35d %s/n", year, "年"); fprintf(fp, "%35d %s/n", year,"年");
fprintf(stdout, "--------------------------------------------------------------------------/n");
fprintf(fp, "--------------------------------------------------------------------------/n");
for(i=1; i<13; i++) //存儲該年每個月的總天數和初始日期
{
month[i].data = 1;
month[i].maxdata = MonthDays(year, i);
}
for(i=0; i<6; i++) //總共輸出6排
{
for(j=1; j<=2; j++)//每排輸出2個月
{
mon = 2*i + j;
fprintf(stdout, "%15s", " "); fprintf(fp, "%15s", " ");
PrintMonth(mon, fp); //第一行打印月份
fprintf(stdout, "%15s", " "); fprintf(fp, "%15s", " ");
if(j==1)
{ fprintf(stdout, "/t"); fprintf(fp, "/t"); }
}
fprintf(stdout, "/n"); fprintf(stdout, "/n"); fprintf(fp, "/n"); fprintf(fp, "/n");
for(j=1; j<=2; j++)
{
for(k=0; k<7; k++)
{
PrintWeek(k, fp); //第2行打印星期
}
fprintf(stdout, "/t"); fprintf(fp, "/t");
}
printf("/n"); fprintf(fp, "/n");
for(j=1; j<=2; j++)
{
mon = 2*i + j;
week = WeekDay(year, mon, 1); //根據輸入的日期,返回對應的星期
//控制輸出格式,把每月的1日打印在對應星期的下面
fprintf(stdout, "%*d ", week*5+2, month[mon].data); fprintf(fp, "%*d ", week*5+2, month[mon].data);
month[mon].data++;
week++;
while(week < 7) //接着在該行打印該周剩餘的日期
{
fprintf(stdout, "%2d ", month[mon].data); fprintf(fp, "%2d ", month[mon].data);
month[mon].data++;
week++;
}
if(j==1)
{ fprintf(stdout, "/t"); fprintf(fp, "/t"); }
}
fprintf(stdout, "/n"); fprintf(stdout, "/n"); fprintf(fp, "/n"); fprintf(fp, "/n");
//從第4行起打印該月剩餘的日期,每7個一行;直至該月日期打印完畢
while(month[2*i+1].data<=month[2*i+1].maxdata || month[2*i+2].data<=month[2*i+2].maxdata)
{
for(j=1; j<=2; j++)
{
mon = 2*i + j;
for(k=0; k<7; k++)
{
if(month[mon].data<=month[mon].maxdata)
{ //如果該月日期未打印完,打印該日期
fprintf(stdout, "%2d ", month[mon].data);
fprintf(fp, "%2d ", month[mon].data);
month[mon].data++;
}
else //否則輸出空格
{ fprintf(stdout, " "); fprintf(fp," "); }
}
if(j==1)
{ fprintf(stdout, "/t"); fprintf(fp, "/t"); }
}
fprintf(stdout, "/n"); fprintf(stdout, "/n"); fprintf(fp, "/n"); fprintf(fp, "/n");
}
fprintf(stdout, "/n"); fprintf(fp, "/n");
}
fclose(fp);
}
/*
求一個萬年曆的算法。輸入年,就可輸出該年的年曆
----------------------------------------------------------------------
lunar calendar 陰曆
現在網上有不少萬年曆的網頁,大部分是jsp寫的,你查看它的源碼就清楚了。大意是將
每年陰曆月份的信息記錄在一個數組內。然後按圖索驥……關鍵是這組數據。我這有一組
現成的:
1900 ——+150 = 2050
*/
/*
數組中每個數字表示1年,第一個數字0x04bd8代表1900年。
每個數字17bit,前(最高位)1個bit表示閏月(如果有閏月的話)是否大月;
接着的12bit表示每月是否大月;
1表示大月,30天,0表示小月,29天。
最後4個bit表示是否有閏月和閏哪個月(不等於0即代表所閏月的月號)
*/
//int solarYear = 1900; // 公曆 1900.1.31 對應農曆1900年元月初一
int baseYear = 1899; // 公曆 1900.1.1對應的農曆:1899.12.1
int DistanceDays = 41; // 公曆1989.2.10號是農曆1989.1.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;
// 傳回農曆 y年的總天數
long lYearDays(long y)
{
long i, sum = 348; // 29 * 12
for(i=0x8000; i>0x8; i>>=1)
sum += (lunarInfo[y-baseYear] & i)? 1: 0 ;
return(sum+leapDays(y));
}
// 傳回農曆 y年閏月的天數
long leapDays(long y)
{
if(leapMonth(y))
return((lunarInfo[y-baseYear] & 0x10000)? 30: 29);
else
return(0);
}
// 傳回農曆 y年閏哪個月 1-12 , 沒閏傳回 0
long leapMonth(long y)
{
return(lunarInfo[y-baseYear] & 0xf);
}
// 傳回農曆 y年m月的總天數
long monthDays(long y, long m)
{
return( (lunarInfo[y-baseYear] & (0x10000>>m))? 30: 29 );
}
//------------------------------------------------------------------------------
// 天干, 地支
char Gan[][3] = {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
char Zhi[][3] = {"子","醜","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
//============================== 傳入 offset 傳回干支, 0=甲子
void cyclical(long offset, char GanZhi[5]) {
strcpy(GanZhi, Gan[offset%10]);
strcat(GanZhi, Zhi[offset%12]);
}
char solarTerm[][5] ={"小寒","大寒","立春","雨水","驚蟄","春分","清明","穀雨","立夏","小滿","芒種","夏至","小暑","大暑","立秋","處暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"};
// 先給節氣進行編號,從近日點開始的第一個節氣編爲0,編號如下及其相應的月份如下:
// 0 小寒 臘月 6 清明 三月 12 小暑 六月 18 寒露 九月
// 1 大寒 臘月 7 穀雨 三月 13 大暑 六月 19 霜降 九月
// 2 立春 正月 8 立夏 四月 14 立秋 七月 20 立冬 十月
// 3 雨水 正月 9 小滿 四月 15 處暑 七月 21 小雪 十月
// 4 驚蟄 二月 10 芒種 五月 16 白露 八月 22 大雪 冬月
// 5 春分 二月 11 夏至 五月 17 秋分 八月 23 冬至 冬月
// 把當天和1900年1月0日(星期日)的差稱爲積日,那麼第y年(1900年算第0年)第x 個節氣的積日是
// F = 365.242 * y + 6.2 + 15.22 * x - 1.9 * sin(0.262 * x)
//------------------------------------------------------------------------------
// 算出農曆, 傳入日期物件, 傳回農曆日期物件
// 該物件屬性有 .year .month .day .isLeap .yearCyl .dayCyl .monCyl
void LunarByTerm(long year, int nTerm, MyDate & dateOut)
{
long sum = 365.2422*(year-1900) + 6.2 + 15.22*nTerm - 1.9*sin(0.262*nTerm);
Lunar(sum+365-DistanceDays, dateOut);
}
void TestYear()
{
long day = 0;
printf("請輸入公曆的年號 月 日 第幾個節氣(0-23):/n");
long year, m, d, nTerm;
scanf("%d%d%d%d", &year, &m, &d, &nTerm);
printf("你輸入的是%d年。/n",year);
printf("%d年的數據爲%x。/n",year, lunarInfo[year-baseYear]);
printf("%d年的總天數:%d/n", year, lYearDays(year));
printf("閏月爲:%d,天數爲:%d/n", leapMonth(year), leapDays(year) );
day += leapDays(year);
for (long i=1; i< 13; i++) {
printf("%d月有%d天。/n", i, monthDays(year, i));
day += monthDays(year, i);
}
printf("總天數:%d/n/n", day);
MyDate d1, d2;
d1.year = 2008;
d1.month = 1;
d1.day = 23;
d1.year = year;
d1.month = m;
d1.day = d;
Lunar(d1, d2);
printf("公曆%d年%d月%d日對應的農曆爲:/n", d1.year, d1.month, d1.day);
char GanZhi[5];
cyclical(d2.year-1864, GanZhi);
printf("農曆%d年(%s)%s%d月%s/n", d2.year, GanZhi,
d2.isLeap?"潤":"",
d2.month,
cDay(d2.day).c_str()
);
MyDate d3;
LunarByTerm(d1.year, nTerm, d3);
printf("%s爲:農曆 %d年%s%d月%d日/n/n", solarTerm[nTerm], d3.year,
d3.isLeap?"潤":"", d3.month, d3.day);
}
// 算出農曆, 傳入日期物件, 傳回農曆日期物件
// 該物件屬性有 .year .month .day .isLeap .yearCyl .dayCyl .monCyl
void Lunar(MyDate& dateIn, MyDate & dateOut)
{
int i;
int run=0, ping=0; // 閏年和平年個數
long sum;
// 計算當前時間dateIn 和 baseYear 年1月1號 之間的天數差
for(i=baseYear; i<dateIn.year; i++) {
if(i%4==0 && i%100!=0 || i%400==0)
run++;
else
ping++;
}
// 計算總天數
sum = 366*run + 365*ping;
for(i=1; i<dateIn.month; i++)
sum += MonthDays(dateIn.year, i);
sum += dateIn.day;
sum -= DistanceDays;
Lunar(sum, dateOut);
}
void Lunar(long offset, MyDate & dateOut)
{
int i;
long temp;
for(i=baseYear; i<TotalYear && offset>0; i++)
{
temp = lYearDays(i);
offset -= temp;
}
if(offset<0)
{
offset += temp;
i--;
}
dateOut.year = i;
int leap = leapMonth(i); // 閏哪個月
dateOut.isLeap = false;
for(i=1; i<13 && offset>0; i++)
{
// 閏月
if(leap>0 && (i==leap+1) && !dateOut.isLeap)
{
--i;
dateOut.isLeap = true;
temp = leapDays(dateOut.year);
}
else
{
temp = monthDays(dateOut.year, i);
}
// 解除閏月
if(dateOut.isLeap && (i==leap+1))
dateOut.isLeap = false;
offset -= temp;
}
if(offset==0 && leap>0 && (i==leap+1))
{
if(dateOut.isLeap)
{
dateOut.isLeap = false;
}
else
{
dateOut.isLeap = true;
--i;
}
}
if(offset<0)
{
offset += temp;
--i;
}
dateOut.month = i;
dateOut.day = offset + 1;
}
//====================== 中文日期
string cDay(unsigned char day)
{
string s;
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);
}