通算日数を日付に変換する

西暦1年1月1日を基準にして、通算日数(1〜)を日付に変換します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの設定

  1. 空の新規プロジェクトを作成して下さい。
  2. ページ先頭の画像を参考にして DialogBox を作成して下さい。
    キャプションとIDを次のように設定して下さい。
    キャプション ID
    西暦年月日 IDC_EDIT1
    通算日数 IDC_EDIT2
    曜日 IDC_EDIT3
    通算日数計算 IDOK
    年月日計算 IDOK2
    終了 IDCANCEL
  3. ソースプログラムをフォルダに格納してプロジェクトに追加します。
    [デバッグ]を選択してビルドに続いて実行を行います。
    年月日の表示を確認して、通算日数計算をクリックすると1年1月1日からの通算日数と曜日が表示されます。
    通算日数に数値を設定して、年月日計算をクリックすると年月日と曜日が表示されます。

プログラムの説明

  1. このプログラムはカレンダーに関係する計算方法の理解を深めるために作成したものです。
    生年月日を入力して、曜日と生存日数を表示 と併せて参照して下さい。
    実際には「西暦1年1月1日」などは存在しません。
    詳細は カレンダの話 を参照して下さい。
    このプログラムでは32ビットの int 型を使っています。
    VCの古いバージョンでは int 型が16ビットになっていて、正しい結果が表示されないことがあるので注意して下さい。
  2. WTBL[][4] は曜日のテーブルです。
    MTBL[12] は大の月と小の月のテーブルで、累積した日数を格納しています。
    yy,mm,dd は年月日を計算する数値の領域です。
    sdate[64] は文字列を編集する作業領域です。
        char    WTBL[][4]= { "日","月","火","水","木","金","土" };
        int     MTBL[12]=  { 0,31,59,90,120,151,181,212,243,273,304,334 };
        int     yy,mm,dd,yobi,count;
        char    sdate[64];
        
  3. WM_INITDIALOG: には DialogBox の初期化のときに制御が渡されます。
    西暦年月日に仮の値として「1999/1/1」を設定しています。
            case WM_INITDIALOG:
                SetWindowText(hDlg,"西暦1年1月1日からの通算日数");
                SetDlgItemText(hDlg,IDC_EDIT1,"1999/1/1");
                break;
        
  4. 通算日数計算ボタンがクリックされたとき、曜日と通算日数を求めて表示します。
    setymd() 関数で yy,mm,dd を取得します。
    days() で通算日数を求めます。
                switch(LOWORD(wParam))
                {   case IDOK:          //西暦1年1月1日からの通算日数と曜日の計算
                        GetDlgItemText(hDlg,IDC_EDIT1,str,sizeof(str));
                        setymd(str);
                        count= days(yy,mm,dd);
                        yobi= count%7L;
                        wsprintf(str,"%d",count);
                        SetDlgItemText(hDlg,IDC_EDIT2,str);
                        SetDlgItemText(hDlg,IDC_EDIT3,WTBL[yobi]);
                        break;
        
  5. 年月日計算ボタンがクリックされたとき、曜日と年月日を求めて表示します。
    strdate() 関数で年月日を計算しています。
                    case IDOK2:         //通算日数から日付と曜日を計算
                        GetDlgItemText(hDlg,IDC_EDIT2,str,sizeof(str));
                        count= atoi(str);
                        yobi= count%7L;
                        SetDlgItemText(hDlg,IDC_EDIT1,strdate(count));
                        SetDlgItemText(hDlg,IDC_EDIT3,WTBL[yobi]);
                        break;
        
  6. 西暦1年1月1日からの通算日数を調べる関数です。
    西暦1年1月1日を指定すると「1」がリターンされます。
    uruu(yy) はうるう年の判定です。
        int  days(int yy, int mm, int dd)
        {   int     w;
            w=  (yy-1)*365L;            //年*365
            w+= (yy/4L - yy/100L + yy/400L + MTBL[mm-1] + dd);
            if (mm<3 && uruu(yy))  w--;
            return(w);
        }
        
  7. 閏(うるう)年を調べる関数です。
    うるう年の説明は カレンダの話 を参照して下さい。
        int  uruu(int year)
        {   if (year%400L==0L)  return(1);
            if (year%100L==0L)  return(0);
            if (year%4L==0L)    return(1);
            return(0);
        }
        
  8. 文字列の年月日から yy,mm,dd を求める関数です。
    年月日は '/' で区切って下さい。
        void  setymd(char str[])
        {   int     i;
    
            yy= atoi(str);
            for(i=1; i<64 && str[i]!='/'; i++);
            mm= atoi(str+i+1);
            for(i++; i<64 && str[i]!='/'; i++);
            dd= atoi(str+i+1);
        }
        
  9. 通算日数から日付を計算する関数です。
    yy/mm/dd の形式で日付をリターンします。
        char *strdate(int count)
        {   int     cw,w;
    
            cw= count;
            yy= cw/365+1;           //西暦年(1〜)
            w= days(yy,1,1)-1;      //前年までの日数
            while(cw<=w)
            {   yy--;
                w= days(yy,1,1)-1;
            }
            cw-= w;
            for(mm=11; mm>0 && MTBL[mm]>=cw; mm--);
            cw-= MTBL[mm];
            mm++;                   //月(1〜12)
            if (mm>2 && uruu(yy))  cw--;
            wsprintf(sdate,"%d/%d/%d",yy,mm,cw);
            return sdate;
        }
        

全ソースコード

超初心者の方のために全ソースコードを掲載します。 (^_^;)

/************************************************/
/*★ 西暦1年1月1日からの通算日数   前田 稔 ★*/
/************************************************/
#include    <windows.h>
#include    "resource.h"

char    WTBL[][4]= { "日","月","火","水","木","金","土" };
int     MTBL[12]=  { 0,31,59,90,120,151,181,212,243,273,304,334 };
int     yy,mm,dd,yobi,count;
char    sdate[64];

// 関数のプロトタイプ宣言
LRESULT CALLBACK DialogProc( HWND, UINT, WPARAM, LPARAM );

//★ 文字列の日付(1999/1/1)から、年月日を数値に変換
void  setymd(char str[])
{   int     i;

    yy= atoi(str);
    for(i=1; i<64 && str[i]!='/'; i++);
    mm= atoi(str+i+1);
    for(i++; i<64 && str[i]!='/'; i++);
    dd= atoi(str+i+1);
}

//★ 閏年を調べる関数
int  uruu(int year)
{   if (year%400L==0L)  return(1);
    if (year%100L==0L)  return(0);
    if (year%4L==0L)    return(1);
    return(0);
}

//★ 西暦1年1月1日からの通算日数を調べる関数
int  days(int yy, int mm, int dd)
{   int     w;
    w=  (yy-1)*365L;            //年*365
    w+= (yy/4L - yy/100L + yy/400L + MTBL[mm-1] + dd);
    if (mm<3 && uruu(yy))  w--;
    return(w);
}

//★ 西暦1年1月1日からの通算日数(1〜)で日付を計算
char *strdate(int count)
{   int     cw,w;

    cw= count;
    yy= cw/365+1;			//西暦年(1〜)
    w= days(yy,1,1)-1;      //前年までの日数
    while(cw<=w)
    {   yy--;
        w= days(yy,1,1)-1;
    }
    cw-= w;
    for(mm=11; mm>0 && MTBL[mm]>=cw; mm--);
    cw-= MTBL[mm];
    mm++;                   //月(1〜12)
    if (mm>2 && uruu(yy))  cw--;
    wsprintf(sdate,"%d/%d/%d",yy,mm,cw);
    return sdate;
}

//★ Windows MAIN 関数
int  APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int )
{
    DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,(DLGPROC)DialogProc);
    return TRUE;
}

//★ Dialog Box の CALLBACK 関数
LRESULT CALLBACK DialogProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)
{   char        str[64];

    switch(msg)
    {
        case WM_INITDIALOG:
            SetWindowText(hDlg,"西暦1年1月1日からの通算日数");
            SetDlgItemText(hDlg,IDC_EDIT1,"1999/1/1");
            break;
        case WM_COMMAND:
            switch(LOWORD(wParam))
            {   case IDOK:          //西暦1年1月1日からの通算日数と曜日の計算
                    GetDlgItemText(hDlg,IDC_EDIT1,str,sizeof(str));
                    setymd(str);
                    count= days(yy,mm,dd);
                    yobi= count%7L;
                    wsprintf(str,"%d",count);
                    SetDlgItemText(hDlg,IDC_EDIT2,str);
                    SetDlgItemText(hDlg,IDC_EDIT3,WTBL[yobi]);
                    break;
                case IDOK2:         //通算日数から日付と曜日を計算
                    GetDlgItemText(hDlg,IDC_EDIT2,str,sizeof(str));
                    count= atoi(str);
                    yobi= count%7L;
                    SetDlgItemText(hDlg,IDC_EDIT1,strdate(count));
                    SetDlgItemText(hDlg,IDC_EDIT3,WTBL[yobi]);
                    break;
                case IDCANCEL:
                    PostQuitMessage(0);
                    return TRUE;
            }
            break;
        case WM_CLOSE:
            EndDialog(hDlg, TRUE); 
            return TRUE;
            break;
    }
    return FALSE;
}

前田稔(Maeda Minoru)の超初心者の Windows(C言語)

前田稔(Maeda Minoru)の超初心者の C#(Frame Work)