web-dev-qa-db-ja.com

単純なJavaScriptの日付計算...実際にはそうではありません

2011年7月6日水曜日から始まる隔週のスケジュールに基づいて、次のリサイクル日を示す簡単なスクリプトを作成しようとしています。そこで、この簡単な関数を作成しました...

    function getNextDate(startDate) {
        if (today <= startDate) {
            return startDate;
        }
        // calculate the day since the start date.
        var totalDays = Math.ceil((today.getTime()-startDate.getTime())/(one_day));
        // check to see if this day falls on a recycle day 
        var bumpDays = totalDays%14;  // mod 14 -- pickup up every 14 days...
        // pickup is today
        if (bumpDays == 0) {
            return today;
        }
        // return the closest day which is in 14 days, less the # of days since the last
        // pick up..
        var ms =  today.getTime() + ((14- bumpDays) * one_day);
        return new Date(ms);
    }

そしてそれを次のように呼ぶことができます...

 var today=new Date();
 var one_day=1000*60*60*24;  // one day in milliseconds
 var nextDate = getNextDate(new Date(2011,06,06));

これまでのところ良いです...しかし、「今日」を2011年10月27日まで予測すると、2011年11月9日水曜日ではなく、2011年11月8日火曜日が次の日付になります...実際、これから毎日2011年10月26日までは正しいピックアップを予測します...そして2011年10月27日から2012年2月28日までのすべての日付は水曜日ではなく火曜日を予測します。そして、2012年2月29日(うるう年)から2012年10月24日(うーん、10月)までのすべての日付が水曜日を正しく予測します。何が足りないのですか?どんな助けでも大歓迎です。

V

15
user799301

これを行う最も簡単な方法は、Dateを使用してsetDateオブジェクトを更新することです。この回答へのコメントは、これが正式に仕様の一部ではないことを示しているため、すべての主要なブラウザーでサポートされています。

[〜#〜] never [〜#〜]元のDate呼び出しを行ったオブジェクトとは異なるgetDateオブジェクトを更新する必要があります。

サンプル実装:

var incrementDate = function (date, amount) {
    var tmpDate = new Date(date);
    tmpDate.setDate(tmpDate.getDate() + amount)
    return tmpDate;
};

日付をインクリメントしようとしている場合は、この関数を使用してください。正の値と負の値の両方を受け入れます。また、使用された日付オブジェクトが変更されないことを保証します。これにより、更新によってオブジェクトの値が変更されることが予想されない場合に発生する可能性のあるエラーを防ぐことができます。


誤った使用法:

var startDate = new Date('2013-11-01T11:00:00');
var a = new Date();
a.setDate(startDate.getDate() + 14)

これにより、startDateの「日付」値がaの値に基づいて14日で更新されます。 aの値は、以前に定義されたstartDateと同じではないため、間違った値を取得する可能性があります。

35
Exelian

Exellianの回答を拡張して、将来の期間(私の場合は次の支払い日)を計算する場合は、単純なループを実行できます。

var today = new Date();
var basePayDate = new Date(2012, 9, 23, 0, 0, 0, 0);

while (basePayDate < today) {
    basePayDate.setDate(basePayDate.getDate()+14);
}

var nextPayDate = new Date(basePayDate.getTime());
basePayDate.setDate(nextPayDate.getDate()-14);

document.writeln("<p>Previous pay Date: " + basePayDate.toString());
document.writeln("<p>Current Date: " + today.toString());
document.writeln("<p>Next pay Date: " + nextPayDate.toString());

コア日付サービスが期待どおりに機能すると仮定すると、これは奇妙な問題にはなりません。私は認めなければなりません、私はそれを何年も先までテストしませんでした...

4
yalarad

注:同様の問題が発生しました。週単位で日付の配列を作成したかったのです。つまり、開始日は2011年10月23日で、12週間続きます。私のコードは多かれ少なかれこれでした:

var myDate = new Date(Date.parse(document.eventForm.startDate.value));
var toDate = new Date(myDate);

var week = 60 * 60 * 24 * 7 * 1000;
var milliseconds = toDate.getTime();

dateArray[0] = myDate.format('m/d/Y');

for (var count = 1; count < numberOccurrences; count++) {
    milliseconds += week;
toDate.setTime(milliseconds);
    dateArray[count] = toDate.format('m/d/Y');
}

時刻を指定せず、米国に住んでいるため、デフォルトの時刻は深夜でした。夏時間の境界を越えると、前日に移動しました。うん。週の計算を行う前に、時刻を正午に設定することで問題を解決しました。

2
Debby