TOP Column Menu 戻る
WideStudio かんどころ(6)
WideStudioによる無作法なC++  2003/05/03

第六回 本格的カレンダーのプログラムを作る
カレンダーの論理(3)

復習
前回までで、ある年月のカレンダー作成にあたっては、その月の1日の曜日がわかり、月末が何日かわかれば出来るということでした。


年月日に関する操作
曜日についての考え方
1週間は7日なので、7日毎に同じ曜日になるのですね。今日と同じ曜日は7日後も14日後も21日後も70日後も140日後も210日後も700日後も7000日後も70000日後も同じ曜日なのですね。
月の日数について考え方は
 31日ある月は
  1月と3月と5月と7月と8月と10月と12月は31日
 30日ある月は
  4月と6月と9月と11月は30日
 28日の月は
  2月である。
  しかし、2月は西暦が4で割り切れる年は29日になる
  しかし、2月は西暦が100で割り切れる年は28日になる
  しかし、2月は西暦が400で割り切れる年は29日になる
という性格があり
年の日数についての考え方も
  1年は365日である。
  しかし、1年は西暦が4で割り切れる年は366日になる
  しかし、1年は西暦が100で割り切れる年は365日になる
  しかし、1年は西暦が400で割り切れる年は366日になる

ある年の1月1日の曜日を調べておいて基準として、その日から何日たっているかがわかれば、完全に曜日がわかることになる。
そのためには、基準となる年月日を決定し、その曜日を調べておく必要がある。
次に基準日から何日たっているのかを計算する関数が必要である。
 もし、決定された基準日が月曜の場合は補正日を1とし、火曜なら2とし、土曜なら、6として、何日たったかを計算した数値に補正日を加算した数値を7で割りあまった数字が0なら日曜だし 1なら月曜だし、2なら火曜だし、6なら土曜だと計算することが出来る。


方針
基準年月日 1990年1月1日とする。この日は月曜日です
関数名 引数 コメント
Ymd2Number long ymd 年月日を引数として渡すと基準日から何日経過したを返す関数
getDaysOfMonth int year,int month 年と月の二つの数値を引数としてわたすと月末の日付を返す関数
getDaysOfYear int year 年を引数として渡すと年間の日数を返す関数
1990年から2399年まで通用するカレンダー
関数名Ymd2Number
引数 long ymd
機能 年月日から一連番号を作る
注意 19900101以後についてだけの機能でしかない
解説
この関数についての引数はlong型で基本的に西暦×10000+月×100+日となっている。
つまり引数はもし2003年5月8日なら ymd = 20030508 となる。

long Ymd2Number(long ymd)
{
  long dm=0L;
  int y,m,d,i,dd[12];
  if( ymd < 19900000L ) return(0L);
  dd[0]=31;dd[1]=28;dd[2]=31;dd[3]=30;
  dd[4]=31;dd[5]=30;dd[6]=31;dd[7]=31;
  dd[8]=30;dd[9]=31;dd[10]=30;dd[11]=31;
  y=(int)(ymd/10000);
  m=(int)((ymd/100L)%100);
  d=(int)(ymd % 100);
  if((y % 4)==0) dd[1]=29;
  for( i = 0;i<=( y - 1991);i++){
    dm += 365L;
    if( ((i + 1990) % 4) == 0) dm++;
  }
  for( i = 1;i< m;i++){
    dm+=(long)(dd[i-1]);
  }
  dm+=(long)(d);
  return(dm);
}
関数名 MaxDayObMonth
指定された年の日数を求める

iint MaxDayOfYear(int yy)
{
  int dmy = 365;
  if( (yy % 4) == 0){
    dmy++;
  }
  if( (yy % 100) == 0){
    dmy--;
  }
  if( (yy % 400) == 0){
    dmy++;
  }
  return(dmy);
}
関数名 MaxDayObMonth
指定された年の指定された月の月末の日を求める
int MaxDayOfMonth(long ym)
{
    int dmy=31;
    switch((int)(ym % 100)){
        case 2:
            dmy=28;
            if( (((int)(ym/100))%4)==0) dmy++;
            if( (((int)(ym/100))%100)==0) dmy--;
            if( (((int)(ym/100))%400)==0) dmy++;
            break;
        case 4: case 6: case 9: case 11:
            dmy=30;break;
    }
    return(dmy);
}
関数名 getYobih
指定された年の指定された年月日の曜日を求める
i
nt getYobi(long ymd)
{
    return((Ymd2Number(ymd) % 7));
}
改良版(Ymd2Number と getYobi 関数の変更と2つの関数の追加により万年カレンダーとなる)
関数名 引数 コメント
Ymd2NumberStart_1_1 long ymd 年月日を引数として渡すとその年の1つき日から何日経過したを返す関数
abs long data 絶対値を返す関数
関数名Ymd2Number
引数 long ymd
機能 年月日から一連番号を作る
注意 機能の制限は原則ない
解説
この関数についての引数はlong型で基本的に西暦×10000+月×100+日となっている。
つまり引数はもし2003年5月8日なら ymd = 20030508 となる。
紀元前4年の12月25日(イエスキリストの誕生日)なら -0041225


long Ymd2Number(long ymd)
{
  long dm;
  long y,i;
  y=(ymd/10000);
  dm=0;
  if( ymd >= 19900000L){
     for(i=1990;i<y;i++){
       dm+=MaxDayOfYear(i);
     }
  }else{
     dm=1;
     for(i=1989;i>=(y);i--){
       dm-=MaxDayOfYear(i);
     }
  }
  dm+=Ymd2NumberStart_1_1(ymd);
  return(dm);
}
関数名Ymd2NumberStart_1_1
引数 long ymd
機能 ymdであらわされた年月日からその年の1月1日からの一連番号を作る
閏年の計算では2月の日数は
その年が4で割った余りが0の時に29日となる
しかし100で割り切れるときは28日となる
さらに400で割り切れれば29日となる。

long Ymd2NumberStart_1_1(long ymd)
//1月1日からの日数算出
{
  long dm=0L;
  int y,m,d,i,dd[12];
  dd[0]=31;dd[1]=28;dd[2]=31;dd[3]=30;
  dd[4]=31;dd[5]=30;dd[6]=31;dd[7]=31;
  dd[8]=30;dd[9]=31;dd[10]=30;dd[11]=31;
  y=(int)(ymd/10000);
  m=(int)((ymd/100L)%100);
  d=(int)(ymd % 100);
  if((y % 4)==0){
    dd[1]++;
    if((y % 100)==0 ) dd[1]--;
    if((y % 400)==0 ) dd[1]++;
  }
  for(i=0;i<(m-1);i++) dm+=dd[i];
  dm+=d;
  return(dm);
}
関数名abs
絶対値をもとめる

long abs(long data)
{
   if(data<0) data*=(-1);
   return(data);
}
関数名getYobi
引数 long number
帰値は0,1,2,3,4,5,6であり,それは日月火水木金土を表す
説明
曜日配列を返す関数

1990以前についてはマイナスとなり、例えば1990年1月1日(月曜日)を1とすれば
1989/12/31は0であり、1989/12/30は-1となる。0は日曜であるが、
-1は何曜日なのか-2日は何曜日なのか
答えは日曜の1日前は土曜日だし2日前は金曜日ということになる。
曜日の取得関数は
マイナスの場合はプラスとして7で割った余りを6から引いた数を7で割った余りが曜日配列の数となる。
上の例だと、-1は1でとして、7-1としそれを7で割った余りつまり6となりこれは土曜をあらわす。
同様に、-2は2でとして、7-2としそれを7で割った余りつまり5となりこれは金曜をあらわす。
では、-77は77でとして、7-0(77 割る7の余り)としそれを7で割った余りつまり0となりこれは日曜をあらわす。


int getYobi(long ymd)
{
    int yb;
    yb=(abs(Ymd2Number(ymd) % 7);
    if( ymd<19900000) yb=(6-yb);
    return(yb);
}