论坛风格切换切换到宽版
  • 6309阅读
  • 13回复

万年历星期的算法 [复制链接]

上一主题 下一主题
离线邓福强
 
发帖
34
只看楼主 倒序阅读 0楼 发表于: 2007-12-19
本人初学单片机,想写个万年历,但不知星期的算法,网上的算法看不明白,思前想后自己开发了一个算法。如要植入单片机还可以优化,请自己优化!我下面只是给大家一个思路好理解。

从2000/1/1------2099/12/31测试通过。



#include <reg52.h>

unsigned char week(unsigned int,unsigned char,unsigned char);

unsigned char week(unsigned int year,unsigned char month,unsigned char day)
{
  unsigned char m,d,temp,week;
  unsigned int y;

  m=1,d=1,week=6;y=2000; //初始化2000/01/01是星期六

  while(y!=year)   //處理年(2000開始++)
    {
            week++;     //是上一年的星期的下一天 公式:365%7=1
           if(week>6)   //如是星期六
            week=0;   //回到0(星期日)
           if(y%4==0)   //判斷是否是閏年,閏年2月是29天 公式:366%7=2
           //如真是是要計算萬年用if(((y%4==0)&&(y%100!=0))||(y%400==0))) 這是減少編譯代碼長度
              {
            week++;           //星期多加一天
            if(week>6)         //如是星期六
                week=0;           //回到0(星期日)
          }
                y++;       //下一年的1月1日
    }
  while(m!=month)   //處理月(1月開始++)    
      {
      switch(m)
              {
        case 1:
        case 3:
                  case 5:
        case 7:
                  case 8:
                  case 10:
        case 12: temp=31%7;break; //大月天數

                  case 2:{             //閏月天數
                          if(y%4==0)     //判斷是否是閏年,閏年2月是29天 公式:366%7=2
                                   //如真是是要計算萬年用if(((y%4==0)&&(y%100!=0))||(y%400==0))) 這是減少編譯代碼長度
                                    temp=29%7;
                                   else temp=28%7;
                                   break;
                              }
        case 4:
                  case 6:
                  case 9:
                  case 11:temp=30%7;break;       //小月天數
              }
      while(temp)         //處理月
              {
        week++;
            if(week>6)       //如是星期六
                week=0;         //回到0(星期日)
                  temp--;        
              }
    m++;               //處理月

      }

  while(d!=day)     //處理日(從1日開始++)      
    {
        week++;
           if(week>6)   //如是星期六
            week=0;   //回到0(星期日)
           d++;
    }
  return week;     //返回星期
}


void main()
{

unsigned char temp;
temp=week(2099,12,31);
while(1);
}
离线bd7qw
发帖
2370
只看该作者 1楼 发表于: 2007-12-19
我修改过一汇编的,大部分自己写了,呵呵,成功
离线东方皇宇
只看该作者 2楼 发表于: 2008-03-10
楼主高人,支持了
离线bd1es
发帖
2096
只看该作者 3楼 发表于: 2008-04-13
我提供两个算法,第一个是传统的,与您的思路一致,只是代码有所优化。第二个是按照数学方法优化的,是我从网上抄的。

这个程序有测试案例,把程序贴到eclipse中编译,运行一下可看效果。虽然这两个算法都是万年历,但是实际日历受天文学的影响,在公元3200还是3400年之后我记不清了,会产生闰年误差。所以所谓万年历算法只在公式上正确,而实际的日期还是应该以天文部门发布的为准。

程序在附件里,改成51c的时候应该把const替换成code,以便把数组放到rom里。

原本程序是贴在这里的,可是实在难看,就改成html附件了,顺便修正括号错误。
附件: DayOfWeek.zip (0 K) 下载次数:252
离线alont
发帖
38
只看该作者 4楼 发表于: 2008-06-06
用%很费存储空间的,最好改成减法!我都是这样做的。星期几比较容易求,我做了100年农历。
离线bd7bq
发帖
1491
只看该作者 5楼 发表于: 2008-06-06
if(month>2) month-=2;
else
{
  if(month<3)
  {
     month+=10;
     year--;
  }
}
week=(year+(year/4)+((13*month-1)/5)+day)%7;

这个可以的.另外谁有utc转bjt的精简程序呢?
离线bd7bq
发帖
1491
只看该作者 6楼 发表于: 2008-06-06
'
用%很费存储空间的,最好改成减法!我都是这样做的。星期几比较容易求,我做了100年农历。
'

现在的编译器都自己能优化的了.刚带着疑问试了下.
采用week%=7; 整个程序编译下来,937字节;
采用week=week-week/7*7;整个程序944字节.
是否有其它减法?
离线alont
发帖
38
只看该作者 7楼 发表于: 2008-06-08
'
现在的编译器都自己能优化的了.刚带着疑问试了下.
采用week%=7; 整个程序编译下来,937字节;
采用week=week-week/7*7;整个程序944字节.
是否有其它减法?
'
有乘法也不行,我用:
while(week>=7)week-=7;
你试试如何?
离线bd7bq
发帖
1491
只看该作者 8楼 发表于: 2008-06-08
'
有乘法也不行,我用:
while(week>=7)week-=7;
你试试如何?
'
刚在我这个程序里试的结果:
week%=7; 代码:935
while(week>=7)week-=7;代码:945
而且,如果week比较大的话,你的循环会很多次,理论上来说效率比较低.
keil的编译优化不错了.人为的去弄一些小细节,有时候反而弄巧成拙.
记得有大学老师提出一些优化算法,结果被学生证实为想当然的小聪明,实际无效.
我也只有桶底的水.和大家学习.
离线bd7bq
发帖
1491
只看该作者 9楼 发表于: 2008-06-08
再求utc转bjt的精简程序..
离线BG4UVR
发帖
11287
只看该作者 10楼 发表于: 2008-06-08
'
再求utc转bjt的精简程序..
'

utc转bjt我做过。如果不处理闰年,那是相当地简单。处理起闰年,那是相当地麻烦。
下面的是我做gps解码时自己写的,目前还没有发错有错误,请您参考

  1. //bjt计算
  2. bhour=((time[0]-0x30)*10+time[1]-0x30)+8;                  //北京时间转换
  3. bday=(date[6]-0x30)*10+date[7]-0x30;
  4. bmonth=(date[4]-0x30)*10+date[5]-0x30;
  5. byear=(date[0]-0x30)*1000+(date[1]-0x30)*100+(date[2]-0x30)*10+date[3]-0x30;
  6. if(bhour>=24){                              //如果小时数大于24
  7.      bhour-=24;                                    //小时数减24
  8.      bday++;                                          //日期数加1
  9.      switch(bday){                                    //判断日期
  10.            case 29:                                          //普通年的2月份
  11.                  if((!((byear%400==0)||((byear%4==0)&&(byear%100!=0)))&&(bmonth==2))){
  12.                        bday=1;
  13.                        bmonth++;
  14.                  }
  15.                  break;
  16.            case 30:                                          //如果是闰年的2月
  17.                  if(((byear%400==0)||((byear%4==0)&&(byear%100!=0)))&&(bmonth==2)){
  18.                        bday=1;
  19.                        bmonth++;
  20.                  }
  21.                  break;
  22.            case 31:
  23.                  if((bmonth==4)||(bmonth==6)||(bmonth==9)||(bmonth==11)){
  24.                        bday=1;
  25.                        bmonth++;
  26.                  }
  27.                  break;
  28.            case 32:
  29.                  bday=1;
  30.                  bmonth++;
  31.                  if(bmonth>=13){
  32.                        byear++;
  33.                        bmonth=1;
  34.                  }
  35.                  break;
  36.      }
  37. }


未转换的时间放在time数组中,是ascii码格式,日期放在date数组中,也是ascii码格式。结果放在bhour, bday, bmonth, byear中,是二进制数据
离线bd7bq
发帖
1491
只看该作者 11楼 发表于: 2008-06-08
是的,我也基本上是这样写的,不知道还有没有精简的方法, :)
离线机器猫
发帖
3719
只看该作者 12楼 发表于: 2008-06-08
用户被禁言,该主题自动屏蔽!
离线BG7PMZ
发帖
3139
只看该作者 13楼 发表于: 2010-05-28
'
utc转bjt我做过。如果不处理闰年,那是相当地简单。处理起闰年,那是相当地麻烦。
下面的是我做gps解码时自己写的,目前还没有发错有错误,请您参考
  1. //bjt计算
  2. bhour=((time[0]-0x30)*10+time[1]-0x30)+8;                  //北京时间转换
  3. bday=(date[6]-0x30)*10+date[7]-0x30;
  4. bmonth=(date[4]-0x30)*10+date[5]-0x30;
  5. byear=(date[0]-0x30)*1000+(date[1]-0x30)*100+(date[2]-0x30)*10+date[3]-0x30;
  6. if(bhour>=24){                              //如果小时数大于24
  7.      bhour-=24;                                    //小时数减24
  8.      bday++;                                          //日期数加1
  9.      switch(bday){                                    //判断日期
  10.            case 29:                                          //普通年的2月份
  11.                  if((!((byear%400==0)||((byear%4==0)&&(byear%100!=0)))&&(bmonth==2))){
  12.                        bday=1;
  13.                        bmonth++;
  14.                  }
  15.                  break;
  16.            case 30:                                          //如果是闰年的2月
  17.                  if(((byear%400==0)||((byear%4==0)&&(byear%100!=0)))&&(bmonth==2)){
  18.                        bday=1;
  19.                        bmonth++;
  20.                  }
  21.                  break;
  22.            case 31:
  23.                  if((bmonth==4)||(bmonth==6)||(bmonth==9)||(bmonth==11)){
  24.                        bday=1;
  25.                        bmonth++;
  26.                  }
  27.                  break;
  28.            case 32:
  29.                  bday=1;
  30.                  bmonth++;
  31.                  if(bmonth>=13){
  32.                        byear++;
  33.                        bmonth=1;
  34.                  }
  35.                  break;
  36.      }
  37. }

未转换的时间放在time数组中,是ascii码格式,日期放在date数组中,也是ascii码格式。结果放在bhour, bday, bmonth, byear中,是二进制数据
'
不錯,剛用到,收下了,謝謝