JavaScript による日付・時刻・時間の計算・演算のまとめ

JavaScript でいろいろな日付の計算関係をまとめてみました。前回の日付関係のまとめエントリの JavaScript版です。

日付の単位について

基本的なことですが、一応まとめておきます。

1秒は1000ミリ秒
1分は60秒
1時間は60分

よって

1時間=60分=3600秒=3600000ミリ秒
1日=24時間=1440分=86400秒=86400000ミリ秒

現在時刻の取得

まずは、最もよく使う処理です。

//今日の日時を表示
var date = new Date();

document.write(date.getFullYear()  + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + "<br />\r\n");

getFullYear()は古いブラウザだと対応していない場合があります。古いブラウザにも対応させる場合はgetYear()を使うことになりますが、その場合ブラウザによって挙動が違う場合があるので注意が必要です。
getMonthの結果は1〜12月を0〜11で返してきます。そのため、上記の例では +1 をしています。

指定した日付のDate型オブジェクトを生成

指定した日付のDate型オブジェクトを生成します。
ここでも、月は 1〜12月を0〜11の数字で表すため、月の値を -1 しています。

//2007-8-17を表すオブジェクトを生成する
var date = new Date(2007, 8 - 1, 17);

document.write(date.getFullYear()  + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + "<br />\r\n");

日付/時刻のパース

日付/時刻を表したある書式の文字列から、年、月、日、時、分、秒を取得します。

//文字列からミリ秒を取得
var time = Date.parse("2007/08/16 10:30:15");

//ミリ秒から日付を求める
var date = new Date();
date.setTime(time);

document.write(date.getFullYear()  + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + "<br />\r\n");

日付の妥当性チェック

指定された日付が有効な日付かどうかをチェックします。
フォームから入力された日付の値をチェックする際はよく使いますね。
JavaScriptではズバリそのものの関数がないのでcheckDate関数を作って見ました。

/**
 * 日付の妥当性チェック
 * year 年
 * month 月
 * day 日
 */
function checkDate(year, month, day) {
    var dt = new Date(year, month - 1, day);
    if(dt == null || dt.getFullYear() != year || dt.getMonth() + 1 != month || dt.getDate() != day) {
        return false;
    }
    return true;
}

//flag1はfalseになります
var flag1 = checkDate(2007, 4, 31);
document.write("flag1=" + flag1 + "<br />\r\n");

//flag2はtrueになります
var flag2 = checkDate(2007, 1, 31);
document.write("flag2=" + flag2 + "<br />\r\n");

//flag3はtrueになります
var flag3 = checkDate(2000, 2, 29);
document.write("flag3=" + flag3 + "<br />\r\n");

うるう年(閏年)の判定

次の条件をチェックする関数を定義して使います。

西暦年が4で割り切れる年はうるう年
ただし、西暦年が100で割り切れる年は平年
ただし、西暦年が400で割り切れる年はうるう年

うるう年判定関数checkLeapyearを定義して使います。

//うるう年(閏年)の判定
function checkLeapyear(year) {
    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

//flag1はtrueになります
var flag1 = checkLeapyear(2000);
document.write("flag1=" + flag1 + "<br />\r\n");

//flag2はfalseになります
var flag2 = checkLeapyear(2007);
document.write("flag2=" + flag2 + "<br />\r\n");

n日後、n日前の日付を求める

今日から1週間後は何月何日?とか、10日前は何月何日?みたいな計算を行う場合に使います。
日付をミリ秒に変換して計算します。

//n日後、n日前の日付を求める
/**
 * 年月日と加算日からn日後、n日前を求める関数
 * year 年
 * month 月
 * day 日
 * addDays 加算日。マイナス指定でn日前も設定可能
 */
function computeDate(year, month, day, addDays) {
    var dt = new Date(year, month - 1, day);
    var baseSec = dt.getTime();
    var addSec = addDays * 86400000;//日数 * 1日のミリ秒数
    var targetSec = baseSec + addSec;
    dt.setTime(targetSec);
    return dt;
}

//2007年8月10日の30日後の日付を取得
//2007-9-9が表示されます
var date = computeDate(2007, 8, 10, 30);
document.write(date.getFullYear()  + "-" + (date.getMonth() + 1) + "-" + date.getDate() + "<br />\r\n");

//2007年8月10日の2週間前の日付を取得
//2007-7-27が表示されます
var date = computeDate(2007, 8, 10, -14);
document.write(date.getFullYear()  + "-" + (date.getMonth() + 1) + "-" + date.getDate() + "<br />\r\n");

任意の年月の月末日を求める

任意年月の月末日を求めます。2月のうるう年判定のため月だけではなくて年の情報も必要です。

/**
 * 年月を指定して月末日を求める関数
 * year 年
 * month 月
 */
function getMonthEndDay(year, month) {
    //日付を0にすると前月の末日を指定したことになります
    //指定月の翌月の0日を取得して末日を求めます
    //そのため、ここでは month - 1 は行いません
    var dt = new Date(year, month, 0);
    return dt.getDate();
}

//2007年2月の月末日を求めます
//28が表示されます
var day = getMonthEndDay(2007, 2);
document.write("2007-2 = " + day + "<br />\r\n");

//2007年12月の月末日を求めます
//31が表示されます
var day = getMonthEndDay(2007, 12);
document.write("2007-12 = " + day + "<br />\r\n");

nヶ月後、nヶ月前の日付を求める

nヶ月後とは単純にn * 30日ではないことに注意してください。
例えば、1月10日の1ヶ月後は2月10日ですが、1月31日の1ヶ月後は2月28日(うるう年の場合2月29日)になるという考え方です。

/**
 * 年月日と加算月からnヶ月後、nヶ月前の日付を求める
 * year 年
 * month 月
 * day 日
 * addMonths 加算月。マイナス指定でnヶ月前も設定可能
 */
function computeMonth(year, month, day, addMonths) {
    month += addMonths;
    var endDay = getMonthEndDay(year, month);//ここで、前述した月末日を求める関数を使用します
    if(day > endDay) day = endDay;
    var dt = new Date(year, month - 1, day);
    return dt;
}

//2000年1月31日の1ヶ月後の日付
//2000-2-29が表示されます
var date = computeMonth(2000, 1, 31, 1);
document.write("2000-1-31 + 1 month = " + date.getFullYear()  + "-" + (date.getMonth() + 1) + "-" + date.getDate() + "<br />\r\n");

//2000年7月31日の2ヶ月後の日付
//2007-9-30が表示されます
var date = computeMonth(2007, 7, 31, 2);
document.write("2007-7-31 + 2 months = " + date.getFullYear()  + "-" + (date.getMonth() + 1) + "-" + date.getDate() + "<br />\r\n");

日付の比較を行う

日付の比較を行います。

//2007-8-10と2007-7-31を比較します
//処理Aが実行されます
var dt1 = new Date(2007, 8 - 1, 10);
var dt2 = new Date(2007, 7 - 1, 31);
if(dt1.getTime() > dt2.getTime()) {
    //処理A
    document.write("A<br />\r\n");
} else {
    //処理B
    document.write("B<br />\r\n");
}

日付の桁数が常に同じ場合は、ミリ秒値に変換しないで、文字列同士の比較をしても日付の比較は行えます。

2つの日付の差(何日間あるか)を求める

2つの日付の差を求めます。n年n月n日まで、あとn日。みたいな感じでカウントダウンなんかにも使えます。

/**
 * 2つの日付の差を求める関数
 * year1 1つのめ日付の年
 * month1 1つめの日付の月
 * day1 1つめの日付の日
 * year2 2つのめ日付の年
 * month2 2つめの日付の月
 * day2 2つめの日付の日
 */
function compareDate(year1, month1, day1, year2, month2, day2) {
    var dt1 = new Date(year1, month1 - 1, day1);
    var dt2 = new Date(year2, month2 - 1, day2);
    var diff = dt1 - dt2;
    var diffDay = diff / 86400000;//1日は86400000ミリ秒
    return diffDay;
}

//2007年8月9日と2007年7月9日の差を求める
//31が表示されます
var days = compareDate(2007, 8, 9, 2007, 7, 9);
document.write("2007-8-9 - 2007-7-9 = " + days + "days<br />\r\n");

//2007年1月10日と2006年10月10日の差を求める
//92が表示されます
var days = compareDate(2007, 1, 10, 2006, 10, 10);
document.write("2007-1-10 - 2006-10-10 = " + days + " days<br />\r\n");

任意の日付の曜日を取得

任意の日付の曜日を取得します。日本語の曜日名を取得するのに、配列を使っています。

//2007年8月10日の曜日を表示
//金曜日が表示されます
var week = new Array("日", "月", "火", "水", "木", "金", "土");
var dt = new Date(2007, 8 - 1, 10);
var dayOfWeek = week[dt.getDay()];

document.write("曜日=" + dayOfWeek + "<br />\r\n");

任意の年月の第n曜日の日付を求める

指定した年月の第n曜日の日付を求めます。
よくある、定休日は毎月第1月曜日と第3月曜日です。みたいな時の実際の日付を求めるのに使えます。

/**
 * 任意の年月の第n曜日の日付を求める関数
 * year 年
 * month 月
 * number 何番目の曜日か、第1曜日なら1。第3曜日なら3
 * dayOfWeek 求めたい曜日。0〜6までの数字で曜日の日〜土を指定する
 */
function getWhatDayOfWeek(year, month, number, dayOfWeek) {
    var firstDt = new Date(year, month - 1, 1);
    var firstDayOfWeek = firstDt.getDay();//指定した年月の1日の曜日を取得
    var day = dayOfWeek - firstDayOfWeek + 1;
    if(day <= 0) day += 7;//1週間を足す
    var dt = new Date(year, month - 1, day);
    var msTime = dt.getTime();
    msTime += (86400000 * 7 * (number - 1));//n曜日まで1週間を足し込み
    dt.setTime(msTime);
    return dt;
}

//2007-8 第4月曜日を求める
//2007-8-27が表示されます
var date = getWhatDayOfWeek(2007, 8, 4, 1);
document.write("2007-8 第4月曜日 = " + date.getFullYear()  + "-" + (date.getMonth() + 1) + "-" + date.getDate() + "<br />\r\n");

//2007-8 第3水曜日を求める
//2007-8-15が表示されます
var date = getWhatDayOfWeek(2007, 8, 3, 3);
document.write("2007-8 第3水曜日 = " + date.getFullYear()  + "-" + (date.getMonth() + 1) + "-" + date.getDate() + "<br />\r\n");

以上、とりあえず、日付・時刻関連の計算のまとめでした。
上記のサンプルコードは自由に使っていただいてOKです。
ただ、エラー処理や例外処理等は考慮されていませんので、使うときは適宜調整するといいかもしれないです。

-- 2008-11-24追記 --------
「任意の年月の第n曜日の日付を求める」に特定の日付の時に前月の日付を表示してしまうというバグがありました。
具体的には2008年12月第1日曜日を取得すると2008年11月30日が表示される等です。
現在バグは修正してあります。また、併せて一部ソースコードの簡略化を行いました。

-- 2009-05-24追記 --------
Dateオブジェクトを用いている関数を西暦0〜99年の範囲で使用した場合に+1900年されて正常に動作しない場合があるとの指摘をうけました。これは、Dateオブジェクトのコンストラクタを利用して年を設定した場合、西暦99年以前は+1900年されてしまうというJavascriptの仕様のためです。
ですので、西暦0?99年の範囲で関数を使用したい場合は、setFullYearメソッドを使って年を適宜設定し直してもらえればと思います。
例えば、妥当性チェックの関数は

function checkDate(year, month, day) {
    var dt = new Date(year, month - 1, day);
    if(dt.getFullYear() != year)
        dt.setFullYear(year);//ここで設定し直している
    if(dt == null || dt.getFullYear() != year || dt.getMonth() + 1 != month || dt.getDate() != day) {
        return false;
    }
    return true;
}

というような感じに書き換えることによって対応できます。
※コメント欄も併せて参照してみてください。

Twitterでも情報配信中!



コメント(7)


ゅりっぺ

いつも参考にさせていただいています。
今日はこちらのおかげで業務が本当に助かりました。
ありがとうございました。


hoge256

お役に立ったみたいでうれしいです。
日付関連の処理って業務で結構使うのに、あんまりサンプルがなかったりするんですよね。


yumebi

はじめまして、ソースを参考にさせていただきました。

それで、「任意の年月の第n曜日の日付を求める」において
2008/12/や
2009/06/での算出が-1weekになってしまうのです。
むむむむぃ。


hoge256

どうやらバグがあったようです。申し訳ありません。
ただいま修正しましたので、試してみてもらえればと思います。>yumebiさん


yumebi

hoge256 さま

お世話になっております。
早速の改修、誠にありがとうございます。

動作確認させていただきました。
非常にありがたいライブラリの数々、
参考にさせていただきます?。

それでは、失礼いたします。


はじめまして。幾つかの関数を使わせて頂いております。

日付の妥当性チェック関数のテストをしていて気付いたのですが
西暦99年以前が上手く動作しないのですがどうでしょうか?
(プラス1900年にならないでしょうか? 例:99年→1999年)
※自分の環境はFirefox3.0.10 / IE6 / Windows XP SP2です。

某巨大板で質問した所、setFullYear() を使うといいと聞いたので勝手ながら改良させて頂きました。
多分曜日取得など他のものも99年以前は正しくないかもしれません

function checkDate(year, month, day) {
var dt = new Date(year, month – 1, day);
if(dt.getFullYear() != year)
dt.setFullYear(year);
if(dt == null || dt.getFullYear() != year || dt.getMonth() + 1 != month || dt.getDate() != day) {
return false;
}
return true;
}


hoge256

ご指摘ありがとうございます。
Dateオブジェクトのコンストラクタを利用して年を設定した場合、西暦99年以前は+1900年されてしまうのが仕様のようですね。
なので、このページで紹介している関数を西暦0?99年の範囲で使用したい場合は、ご指摘の通りsetFullYearを使って再度、年を設定し直すのがいいようです。
とりあえず、ブログ本文にも追記しておきました。
いろいろありがとうございました。


コメントを残す

メールアドレスが公開されることはありません。



次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

※コメントは承認制です。承認されるまで表示されません。