文字列を操作して「3日前」の日付を作成したくないと思います。つまり、このスニペットは次のとおりです。
var varBegin = (d.getMonth()+1) + "-" + (d.getDate()-3) + "-" + d.getFullYear()
まず、入力フィールドで区切り記号としてスラッシュを使用しているのに、ここで区切り記号としてハイフンを使用している理由がわかりません。
いずれにせよ、それは日付を作成するための信頼できる方法ではありません。文字列を Date オブジェクトのコンストラクターにフィードすると、実質的にDate.parse()
. これは、ブラウザによって動作が異なります。
これをチェックしてください:
> new Date('1-1-2012');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
> new Date('01-01-2012');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
> new Date('2012-1-1');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
かなり良さそうですよね?しかし、それはChrome上にあります。
最新バージョンの Firefox で、まったく同じ呼び出しで何が起こるかを確認してください。
> new Date('1-1-2012');
Date {Invalid Date}
> new Date('01-01-2012');
Date {Invalid Date}
> new Date('2012-1-1');
Date {Invalid Date}
> new Date('2012-01-01');
Date {Sat Dec 31 2011 16:00:00 GMT-0800 (PST)}
さらに、両方のブラウザでこの動作を確認してください。
> new Date('2012-01-01');
Sat Dec 31 2011 16:00:00 GMT-0800 (PST)
月と日付の数字の先頭にゼロを追加するだけで、タイム ワープが発生します。それをなくすには、時間とタイムゾーン(私にとってはPST)を設定する必要があります:
> new Date('2012-01-01T00:00:00-08:00')
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
基本的に、日付文字列の解析は頭痛の種です。this、this、およびthisのような仕様を消化して説明する必要はありません。
年、月、日の値を (この順序で) Date オブジェクトのコンストラクターに渡します。これにより、日付が確実に作成されるため、比較は有効です。
このように、特定の例では:
var WARNING_PERIOD_IN_DAYS = 3;
// Extract month, day, year from form input, 'trimming' whitespace.
var re = /^\s*(\d{1,2})\/(\d{1,2})\/(\d{4})\s*$/;
var match = re.exec(inputVal); // from "myForm.SC_date.value".
if (match) {
var month = parseInt(match[1]) - 1; // Zero-indexed months.
var date = parseInt(match[2]);
var year = parseInt(match[3]);
var inputDate = new Date(year, month, date);
var currentDate = new Date();
var threeDaysAgo = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDay() - WARNING_PERIOD_IN_DAYS);
console.log((inputDate > threeDaysAgo) ? 'Within warning period' : 'No warning needed');
}
仕様について言えば、ここで注目すべき点が 1 つあります。それは、JavaScript では日付値を「ラップ」でき (大きすぎる、または負の値になる可能性があります)、結果の Date は依然として有効で正しいということです。理由は次のとおりです。
ECMAScript 262仕様から、を呼び出すと次のようになりますsetDate()
。
**15.9.5.36 Date.prototype.setDate (date)**
1. Let t be the result of LocalTime(this time value).
2. Let dt be ToNumber(date).
3. Let newDate be MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t)).
4. Let u be TimeClip(UTC(newDate)).
5. Set the [[PrimitiveValue]] internal property of this Date object to u.
6. Return u.
これは重要なビットです:MakeDay(YearFromTime(t), MonthFromTime(t), dt)
MakeDay は、Date オブジェクトの現在の時刻の値 (エポック時間のミリ秒単位) から年と月を取得し、次のようにします。
**15.9.1.12 MakeDay (year, month, date)**
The operator MakeDay calculates a number of days from its three arguments, which must be ECMAScript Number values. This operator functions as follows:
1. If year is not finite or month is not finite or date is not finite, return NaN.
2. Let y be ToInteger(year).
3. Let m be ToInteger(month).
4. Let dt be ToInteger(date).
5. Let ym be y + floor(m /12).
6. Let mn be m modulo 12.
7. Find a value t such that YearFromTime(t) == ym and MonthFromTime(t) == mn and DateFromTime(t) == 1;
but if this is not possible (because some argument is out of range), return NaN.
8. Return Day(t) + dt - 1.
これはかなり複雑に見えますが、基本的には次のとおりです。
floor
、modulo
、およびビットは、月のdate==1
ロールオーバー (負の月または 12 を超える月) を処理します。
- エポック時間の結果のインスタントは、日数に変換されます。
- 日付の値がその日数に追加されます。日付の値が負の場合は問題ありません。減算されるだけです。
- 結果は setDate() に返されます。
- setDate は MakeDate() を呼び出します。これは、日数と日中の時間をエポック時間のミリ秒に変換します。
- Date オブジェクトの内部時間は、この新しいエポック時間に設定されます。
そのため、次のようなことができます ( V8 JS エンジン プロジェクトのMakeDay()
関数からのコメント)。
// MakeDay(2007, -4, 20) --> MakeDay(2006, 8, 20)
// MakeDay(2007, -33, 1) --> MakeDay(2004, 3, 1)
// MakeDay(2007, 14, -50) --> MakeDay(2007, 8, 11)
わかりました。これは、この特定の問題について詳しく説明しすぎたことはほぼ間違いありません。しかし、私は、舞台裏で実際に何が起こっているのかを明確にしたかっただけです。お待ち頂きまして、ありがとうございます。
そして…最後に一つだけ…
その HTML スニペットにはランダムな</textarea>
ハングアウトがあります。その前のどこかに開口部がある場合は<textarea>
、他の要素の一部を誤って囲んでいます。開口部がない場合は<textarea>
削除してください。