第6回

  タイマー、日付と時刻  


タイマー

 ある時間後や、ある時間ごとに処理をするためには、タイマーを使います。

 変数 = setTimeout(実行する処理, 時間[ミリ秒])
 clearTimeout(変数)

 setTimeout はタイマーを設定し、ここで指定した変数を clearTimeout で指定することで、タイマーを解除します。

<HTML>
<HEAD>
<SCRIPT TYPE="text/javascript">
    var tm,i=0;
    function msg()
    {
        mes=new Array("いらっしゃい","よくきたな","もう帰るの","バイバイ");  
        document.form01.txt01.value=mes[i];
        i++;
        if(i==4)
            i=0;
        clearTimeout(tm);
        tm=setTimeout("msg()",1000);
    }
</SCRIPT>
</HEAD>
<BODY>
<FORM NAME="form01">
<INPUT TYPE="button" VALUE="スタート" onClick="msg()">
 <INPUT TYPE="button" VALUE="ストップ" onClick="clearTimeout(tm)"><P>
<INPUT TYPE="text" NAME="txt01">
</FORM>
</BODY>
</HTML>

 ここをクリックしてください。この例では [スタート] をクリックすると、setTimeout により、1000ミリ秒 = 1秒ごとに、メッセージを繰り返し表示し、[ストップ] をクリックするとこのタイマーを止めます。なお、msg() の中で、clearTimeout(tm) を実行していますが、これがないと、 [スタート] を複数回クリックしたときに、タイマーが複数起動してしまいます。

 ● 当選番号を決める例

 次の例は、タイマーと乱数を利用して、多くの番号の中から当選番号を決めるものです。ここをクリックしてください。最小/最大ナンバーを入力して、[スタート] をクリックすると、乱数により、50~150ミリ秒間隔に [当選ナンバー] の番号が変わり、[ストップ] をクリックすると、このとき [当選ナンバー] に表示されていた番号が [当選リスト] のコピーされます。
 なお、当選した番号は配列 nnum に代入して、 [当選ナンバー] に表示する前にチェックし、ダブリがないようにしています。最小~最大ナンバーが全て出てしまうと、[終了しました] というメッセージを出します。

<HTML>
<HEAD>
<SCRIPT TYPE="text/javascript">
    var d01,d02;
    var tm;
    nnum=new Array();
    function calc()
    {
        with(document.form01)
        {
            d01=txt01.value*1; // 最小ナンバー
            d02=txt02.value*1; // 最大ナンバー
            if(nnum.length==d02-d01+1) // 全てのナンバーが出たら終了
                alert("終了しました");
            else if(d02 > d01)
            {
                clearTimeout(tm);
                mcalc();
            }
            else
                alert("正しい数値を入力してください");
        }
    }
    function mcalc()
    {
        var i,ttemp,snum,flag=1;
        ttemp=(Math.floor(Math.random()*100))+50; // 50~100ミリ秒
        tm=setTimeout("mcalc()",ttemp);
        with(document.form01)
        {
            while(flag==1)
            { // snum は最小~最大の間のランダムな整数
                snum=Math.floor(Math.random()*(d02-d01+1))+d01;
                for(i=0;i<nnum.length;i++)
                {
                    if(snum==nnum[i]) // すでに出たナンバーと同じなら中止  
                    {
                        flag=0;
                        break;
                    }
                }
                if(flag==1)
                {
                    txt03.value=snum; // 数字を代入
                    flag=0;
                }
                else
                    flag=1;
            }
        }
    }
    function mlist()
    {
        with(document.form01)
        {
            if(txt03.value!=nnum[nnum.length-1])
            {
                clearTimeout(tm);
                nnum[nnum.length]=txt03.value;
                list.value=" No."+txt03.value+"\n"+list.value;
            } // [ストップ] を続けて押したときは処理しない
        }
    }
</SCRIPT>
</HEAD>
<BODY>
<FORM NAME="form01">
最小ナンバー:<INPUT TYPE="text" NAME="txt01"><BR>
最大ナンバー:<INPUT TYPE="text" NAME="txt02"><P>
<INPUT TYPE="button" VALUE="スタート" onClick="calc()">
 <INPUT TYPE="button" VALUE="ストップ" onClick="mlist()"><P>
<HR>当選ナンバー:<INPUT TYPE="text" NAME="txt03"><P>
<HR>当選リスト<BR>
<TEXTAREA NAME="list" ROWS="10" COLS="20"></TEXTAREA>
<INPUT TYPE="RESET" VALUE="リセット" onClick="nnum.length=0">
</FORM>
</BODY>
</HTML>

日付と時刻

 現在の日付と時刻を得るためには、new を使用して日付オブジェクトを作成します。ここをクリックしてください。[表示] をクリックすると、Aには、Date() で作成した、現在の日付/時刻の日付オブジェクト dtm が表示されます。Bには、日付オブジェクト dtm より得た値から、日本語表記の時刻の日付が表示されます。Cには toGMTString によりグリニッジ標準時、Dには toLocaleString によりローカル時が表示されます。

<HTML>
<HEAD>
<SCRIPT TYPE="text/javascript">
    function disp()
    {
        week=new Array("日","月","火","水","木","金","土");
        dtm=new Date();
        var yy=dtm.getFullYear();
        var mm=dtm.getMonth()+1;
        var dd=dtm.getDate();
        var ww=week[dtm.getDay()];
        var hh=dtm.getHours();
        var nn=dtm.getMinutes();
        var ss=dtm.getSeconds();
        with(document.form01)
        {
            txt01.value=dtm;
            txt02.value=yy+"年"+mm+"月"+dd+"日("+ww+"曜日)"+hh+"時"+nn+"分"+ss+"秒";  
            txt03.value=dtm.toGMTString();
            txt04.value=dtm.toLocaleString();
        }
    }
</SCRIPT>
</HEAD>
<BODY>
<FORM NAME="form01">
A:<INPUT TYPE="text" NAME="txt01" SIZE=50>(dtm)<BR>
B:<INPUT TYPE="text" NAME="txt02" SIZE=50>(日本語表記)<BR>
C:<INPUT TYPE="text" NAME="txt03" SIZE=50>(グリニッジ標準時)<BR>
D:<INPUT TYPE="text" NAME="txt04" SIZE=50>(ローカル時)<P>
<INPUT TYPE="button" VALUE="表示" onClick="disp()">
</FORM>
</BODY>
</HTML>

 このなかで、getFullYear は古いブラウザが対応していません。対応している getYear の場合、2000年以降の表示がブラウザにより異なってしまうので、ここでは getFullYear を使用しています。getMonth は0から始まり、実際の月より1小さい値になるので、+1 しています。
 getMonth などを使用して表示するB以外は、ブラウザにより表示が異なります。
 ● 曜日と、今日から何日目かを表示する例

 入力した日の曜日と、今日から何日目かを表示します。ここをクリックしてください。

<HTML>
<HEAD>
<SCRIPT TYPE="text/javascript">
    function disp()
    {
        week=new Array("日","月","火","水","木","金","土");
        dtm=new Date();
        with(document.form01)
        {
            var yy=txt01.value;
            var mm=txt02.value-1;
            var dd=txt03.value;
            dtn=new Date(yy,mm,dd);
            txt04.value=week[dtn.getDay()];
            txt05.value=Math.ceil((dtn.getTime()-dtm.getTime())/8.64E07);  
        }
    }
</SCRIPT>
</HEAD>
<BODY>
年(4桁)、月、日 を入力してください。
<FORM NAME="form01">
<INPUT TYPE="text" NAME="txt01" SIZE=5>年
<INPUT TYPE="text" NAME="txt02" SIZE=3>月
<INPUT TYPE="text" NAME="txt03" SIZE=3>日
 <INPUT TYPE="button" VALUE="表示" onClick="disp()">
 <INPUT TYPE="reset" VALUE="リセット">
<HR> この日は<INPUT TYPE="text" NAME="txt04" SIZE=4>曜日
 今日から<INPUT TYPE="text" NAME="txt05" SIZE=10>日目です。
</FORM>
</BODY>
</HTML>

 Date() は、引数を省略すると、現在の日付と時刻の日付オブジェクトを作成しますが、日付を表す文字列を指定できます。この日の曜日を getDay で求めます。
 getTime は、日付オブジェクトから、1970年1月1日0時からの経過時間をミリ秒で返します。現在との差を、1日の時間をミリ秒で表した 8.64E07(60*60*24*1000) で除して日にしています。

 ● マウスをクリックする反応速度を測定する例

 表示が変わってから、マウスをクリックするまでの反応速度を測定するものです。ここをクリックしてください。[スタート] をクリックすると、2~3秒後にテキストボックスに黒い ■ が表示されます。表示されてからクリックするまでの時間を表示して、判定します。

<HTML>
<HEAD>
<SCRIPT TYPE="text/javascript">
    var tm,t01;
    function calca()
    {
        var ttemp;
        ttemp=(Math.floor(Math.random()*1000))+2000;
        tm=setTimeout("calcb()",ttemp);
        t01=(new Date()).getTime()+ttemp;
    }
    function calcb()
    {
        document.form01.txt01.value="■■■■■■■■■■■";
        clearTimeout(tm);
    }
    function calcc()
    {
        var t02;
        t02=(new Date()).getTime();
        with(document.form01)
        {
            txt02.value=t02-t01;
            if((t02-t01)<=0)
                txt03.value="黒くなってからクリックしてください";  
            else if((t02-t01)<=200)
                txt03.value="速すぎ!!";
            else if((t02-t01)<=400)
                txt03.value="普通です";
            else
                txt03.value="ちょっと遅いんじゃ...";
        }
    }
</SCRIPT>
</HEAD>
<BODY>
<FORM NAME="form01">
反応速度テスト
 <INPUT TYPE="button" VALUE="スタート" onClick="calca()"><P>
 <INPUT TYPE="text" NAME="txt01" SIZE=20>
 <INPUT TYPE="button" VALUE="クリック" onClick="calcc()"><HR>
時間:<INPUT TYPE="text" NAME="txt02" SIZE=20>ミリ秒<BR>
判定:<INPUT TYPE="text" NAME="txt03" SIZE=40>
 <INPUT TYPE="reset" VALUE="リセット">
</FORM>
</BODY>
</HTML>

 やってみると、速くクリックしたようでも、表示される時間はだいぶ大きくなります。プログラムとしては正しくても、ミリ秒まで正確に得ることはできないようで、反応速度を正確に測定するのは無理のようです。小さい数値を出すには、黒くなる前に予測してクリックする必要があるので、ゲーム的には使えるかもしれません。

 ● カレンダーの例

 ロードしたときは今月のカレンダーを表示し、[前月]/[次月] または、入力した年月のカレンダーを表示することができます。ここをクリックしてください。

<HTML>
<HEAD>
<SCRIPT TYPE="text/javascript">
    function dispm()
    {
        var i;
        week=new Array("日","月","火","水","木","金","土");
        dtm=new Date();
        with(document.form01)
        {
            for(i=0;i<=6;i++) // 曜日を代入
                elements[i+7].value=week[i];
            txt01.value=dtm.getFullYear();
            txt02.value=dtm.getMonth()+1;
            txt03.value=txt01.value+"年"+txt02.value+"月"+dtm.getDate()+"日"  
        }
        disp();
    }
    function dispn(tp)
    {
        with(document.form01)
        {
            if(tp.value=="前月")
            {
                if(txt02.value==1) // txt01:年 txt02:月
                {
                    txt02.value="12";
                    txt01.value--;
                }
                else
                    txt02.value--;
            }
            else
            {
                if(txt02.value==12)
                {
                    txt02.value="1";
                    txt01.value++;
                }
                else
                    txt02.value++;
            }
        }
        disp();
    }
    function disp()
    {
        var i,j,k,d01,d02;
        with(document.form01)
        {
            d01=txt01.value; //d01:年 d02:月
            d02=txt02.value-1;
            if(d01<=0 || d02<0 ||d02>11)
            {
                alert("入力した値が異常です。本日に戻ります。");
                dispm();
                return false;
            }
            j=(new Date(d01,d02,1)).getDay(); // j はこの月の1日の曜日
            if(d02==12)
                k=(new Date(d01+1,1,1)).getDay(); // k は次月1日の曜日
            else
                k=(new Date(d01,d02+1,1)).getDay();
            for(i=1;i<=42;i++)
                elements[i+13].value=""; // カレンダーを空白に初期化
            for(i=1;i<=31;i++)
            {
                if(i>=28 && (new Date(d01,d02,i)).getDay()==k)
                    break; // 曜日が次月1日と同じなら中止
                elements[i+j+13].value=i; // 日を代入
            }
        }
    }
</SCRIPT>
</HEAD>
<BODY onLoad=dispm();>
<FORM NAME="form01">
<INPUT TYPE="text" NAME=txt01 SIZE=5>年
<INPUT TYPE="text" NAME=txt02 SIZE=3>月
 <INPUT TYPE="button" VALUE="表示" onClick="disp()")>
<P><INPUT TYPE="button" VALUE="前月" onClick="dispn(this)")>
<INPUT TYPE="button" VALUE="次月" onClick="dispn(this)")>
 <INPUT TYPE="button" VALUE="本日" onClick="dispm()")>
<INPUT TYPE="text" NAME=txt03 SIZE=20><HR>
<SCRIPT TYPE="text/javascript">
    var tb;
    for(tb=1;tb<=49;tb++)
    {
        document.write("<INPUT TYPE='text' SIZE=2>");
        if(tb%7==0)
            document.write("<BR>");
    }
</SCRIPT>
</FORM>
</BODY>
</HTML>

 ロードしたとき、[本日] をクリックしたとき、入力された年月が異常なときは、dispm() が実行されて、今月のカレンダーが表示されます。
 disp() がカレンダーに数字を表示する部分です。まず、年月に異常な数字が入力されている場合は、メッセージを出してから dispm() を実行して、本日に戻ります。この月の1日の曜日を j=(new Date(d01,d02,1)).getDay() により求め、入力するテキストボックスの位置を決めます。その月が何日まであるか? を知るために、28日以後の曜日を、次の月の1日の曜日と比較して、同じなら入力を終了しています。