2008
07-31

万年历程序
新旧历界限为1752年9月
相关信息看论坛内
http://www.vcgood.com/bbs/forum_posts.asp?TID=2567
编译MinGW
gcc xcal.c -o xcal.exe –std=c99
windows下测试通过
[code]
/**********************************************************************/
/* project : 万年历                                                   */
/* version : Ver 0.9                                                  */
/* file    : xcal.c                                                   */
/* author  : xstar.wxb                                                */
/* date    : 2008/07/31                                               */
/* history :                                                          */
/**********************************************************************/
#include <stdio.h>
#include <stdlib.h>


/* 星期 */
#define WEEKDAY "Su Mo Tu We Th Fr Sa"


/* 数字的ASCII码形式 */
char NUM[ 10 ] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };


/* 月份 */
char *MONTH[ 12 ] = {
 "January",
 "February",
 "March",
 "April",
 "May",
 "June",
 "July",
 "August",
 "September",
 "October",
 "November",
 "December"
};


/* 月份数据 */
/* MONDAY[ 0 ] 为平年数据 */
/* MONDAY[ 1 ] 为闰年数据 */
/* MONDAY[ 2 ] 为特殊年份数据 1752年 */
int MONDAY[ 3 ][ 12 ] = {
 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
 { 31, 29, 31, 30, 31, 30, 31, 31, 19, 31, 30, 31 }
};


/* 日期与星期对应结构 */
typedef struct _DAY {
 int monthday;
 int weekday;
} DAY;


/* 儒略历(Julian Calendar) 1 - 1751 */
int JulianCalendar(int year, int month, DAY *day);
/* 格里历(GregorianCalendar) 1753 - ... */
int GregorianCalendar(int year, int month, DAY *day);
/* 特殊的1752年 */
int Special1752(int year, int month, DAY *day);
/* 显示日历函数 */
int displaymonth(int year, int month, int days, DAY *day);


/* 主函数 */
int main(int argc, char *argv[])
{
 int year = 0;    /* 输入的年份(1 - 9999)                 */
 int month = 0;   /* 输入的月份(1 - 12)                   */


 int days = 0;    /* 返回值,输入月份的天数               */
 DAY day[ 31 ];   /* 返回值,输入月份的日期和星期对应关系 */


 /* 参数个数判断 */
 if (argc != 3)
 {
  /* 错误的时候,显示用法 */
  printf( "Usage: xcal month year\n" );


  return -1;
 }


 /* 转换为数字 */
 year = atoi( argv[ 2 ] );
 month = atoi( argv[ 1 ] );


 /* 判断输入的参数,简单判断 */
 if ((year < 1) || (year > 9999))
 {
  printf( "1 <= year <= 9999\n" );


  return -1;
 }


 /* 判断输入的参数,简单判断 */
 if ((month < 1) || (month > 12))
 {
  printf( "1 <= month <= 12\n" );


  return -1;
 }


 /* 判断输入的年份,调用适用的历法 */
 if (year < 1752) {
  /* 儒略历(Julian Calendar) 1 - 1751 */
  days = JulianCalendar( year, month, &day[ 0 ] );
 } else if (year == 1752) {
  /* 特殊的1752年 */
  days = Special1752( year, month, &day[ 0 ] );
 } else if (year > 1752) {
  /* 格里历(GregorianCalendar) 1753 - ... */
  days = GregorianCalendar( year, month, &day[ 0 ] );
 }


 /* 显示日历 */
 displaymonth( year, month, days, &day[ 0 ] );


 return 0;
}


/* 儒略历(Julian Calendar) */
/* 公元1年1月1日为星期六 */
/* 1年1月1日 - 1752年9月2日 */
/* 1 3 5 7 8 10 12 为大月,31天 */
/* 4 6 9 11 为小月,30天 */
/* 2 能被4整除的年份为闰年,29天,其他年份为平年,28天 */
int JulianCalendar(int year, int month, DAY *day)
{
 int leap = 0;      /* 适用的月份数据    */
 int firstday = 6;  /* 每月1日的星期数   */


 /* 是否为闰年,设置适用的月份数据 */
 if ((year % 4) == 0)
 {
  leap = 1;
 }


 /* 计算每年的1月1日的星期数 */
 /* 计算累加天数,1月1日: 前一年平年星期数累加一,前一年闰年星期数加二 */
 /* year年1月1日 */
 firstday = (5 + (5 * year - 1) / 4) % 7;


 /* 计算month月1日的星期数 */
 for (int i = 0; i < month - 1; i++)
 {
  firstday += MONDAY[ leap ][ i ];
 }


 /* year年month月1日 */
 firstday = firstday % 7;


 /* month月 */
 for (int i = 0; i < MONDAY[ leap ][ month - 1 ]; i++)
 {
  day->monthday = i + 1;
  day->weekday = (firstday + i) % 7;


  day++;
 }


 /* 返回当月天数 */
 return MONDAY[ leap ][ month - 1 ];
}


/* 格里历(GregorianCalendar) */
/* 公元1753年1月1日为星期一 */
/* 1752年9月14日 - 现在,现行历法标准 */
/* 1 3 5 7 8 10 12 为大月,31天 */
/* 4 6 9 11 为小月,30天 */
/* 2 能被4整除且不能被100整除或能被400整除的年份为闰年,29天,其他年份为平年,28天 */
int GregorianCalendar(int year, int month, DAY *day)
{
 int leap = 0;      /* 适用的月份数据    */
 int firstday = 1;  /* 每月1日的星期数   */


 int days = 0;      /* 累加天数          */


 /* 是否为闰年,设置适用的月份数据 */
 if ((((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0))
 {
  leap = 1;
 }


 /* 计算每年的1月1日的星期数 */
 /* 初始化 */
 days = 0;


 /* 计算累加天数,1月1日: 前一年平年星期数累加一,前一年闰年星期数加二 */
 for (int n = 1753; n < year; n++)
 {
  if ((((n % 4) == 0) && ((n % 100) != 0)) || ((n % 400) == 0))
  {
   days += 2; /* 闰年 */
  } else {
   days++;    /* 平年 */
  }
 }


 /* year年1月1日 */
 firstday = (firstday + days) % 7;


 /* 计算month月1日的星期数 */
 for (int i = 0; i < month - 1; i++)
 {
  firstday += MONDAY[ leap ][ i ];
 }


 /* year年month月1日 */
 firstday = firstday % 7;


 /* month月 */
 for (int i = 0; i < MONDAY[ leap ][ month - 1 ]; i++)
 {
  day->monthday = i + 1;
  day->weekday = (firstday + i) % 7;


  day++;
 }


 /* 返回当月天数 */
 return MONDAY[ leap ][ month - 1 ];
}


/* 推行新历法的时候为了消除历法和太阳周期的误差,1752年9月2日下一日期为1752年9月14日 */
/* 为计算方便这一年单独提取出来计算 */
/* 公元1752年1月1日为星期三 */
int Special1752(int year, int month, DAY *day)
{
 int leap = 2;      /* 适用的月份数据 特殊年份    */
 int firstday = 3;  /* 每月1日的星期数            */


 /* 计算month月1日的星期数 */
 for (int i = 0; i < month - 1; i++)
 {
  firstday += MONDAY[ leap ][ i ];
 }


 /* 1752年month月1日 */
 firstday = firstday % 7;


 /* 9月份特殊处理 */
 if (month == 9)
 {
  /* month月 */
  for (int i = 0; i < MONDAY[ leap ][ month - 1 ]; i++)
  {
   day->monthday = i + 1;


   /* 1752年9月2日下一日期为1752年9月14日 */
   if (day->monthday > 2)
   {
    day->monthday += 11;
   }


   day->weekday = (firstday + i) % 7;


   day++;
  }


  /* 返回当月天数 */
  return MONDAY[ leap ][ month - 1 ];
 }


 /* 其他月份的处理 */
 for (int i = 0; i < MONDAY[ leap ][ month - 1 ]; i++)
 {
  day->monthday = i + 1;
  day->weekday = (firstday + i) % 7;


  day++;
 }


 /* 返回当月天数 */
 return MONDAY[ leap ][ month - 1 ];
}


/* 显示日历函数 */
int displaymonth(int year, int month, int days, DAY *day)
{
 int line = 0;                  /* 行 */


 /* 显示用 */
 char BUFF[ 6 ][ 21 ] = {
  "                    ",    /* 20 space */
  "                    ",
  "                    ",
  "                    ",
  "                    ",
  "                    "
 };


 /* 初始化 */
 line = 0;


 /* 设置每行显示的内容 */
 for (int i = 0; i < days; i++)
 {
  BUFF[ line ][ day[ i ].weekday * 3 ] = NUM[ day[ i ].monthday / 10 ];
  BUFF[ line ][ day[ i ].weekday * 3 + 1 ] = NUM[ day[ i ].monthday % 10 ];


  if (day[ i ].weekday == 6)
  {
   line++;
  }
 }


 /* 显示 */
 printf( "  %s  %4d\n", MONTH[ month - 1], year );
 printf( "%s\n", WEEKDAY );


 for (int i = 0; i < 6; i++)
 {
  printf( "%s\n", BUFF[ i ] );
 }


 return 0;
}
[/code]


万年历》有 3 条评论

  1. whos 说:

    楼主发威啦。

  2. emily 说:

    风格很好,很佩服!我写的程序刚开始还蛮好,后来要更新升级什么的就乱了 。后来我自己看的都郁闷。搂主可以传授点经验么?

  3. xstar 说:

    经验没什么啊!
    找个好点的编程规范!严格遵守!
    另外写完后,多做检查!格式化一下!

    这个程序还可以规范一下的!比如接口的说明等!
    另外接口参数有效性的判断等!这些都是需要完善一下的!所以版本暂时定为0.9版本!
    另外还有两个功能没实现!
    一是显示一年的年历!
    当参数为一个的时候!参数为年份数据!

                        year
           1               2                3
           4               5                6
           7               8                9
           10             11               12
    显示年历
    二是显示当前月份!
    当没有任何参数输入的时候!显示当前月份的月历!

留下一个回复