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);
}