1

ユーザーが日付を入力してレポートを印刷できる HTML フォームがあります。ただし、その日付が現在の日付から 3 日以内の場合は、ユーザーに 3 日待つ必要があることを伝えるように設定しています。何らかの理由で、「09/30/2012」のようなものを入力するとコードが機能しますが、「10/01/2012」と入力すると、エラー チェックがスキップされます。ただし、2 桁の月 (10、11、および 12) の場合は、エラー チェックを完全にスキップするようです。何かアイデアがあれば教えてください。ありがとう

JS コード:

var date = myForm.SC_date.value;
var d = new Date(date);
var varBegin = (d.getMonth()+1) + "-" + (d.getDate()-3) + "-" + d.getFullYear()
re = /^\d{1,2}\/\d{1,2}\/\d{4}$/;

if (myForm.SC_date.value == "")
    window.alert("Please enter the requested date of variance.  NOTE: Date must be 3 days prior to today's date.")

            //Here is where I am having issues  
/*else if(new Date(date) > new Date(varBegin))
    window.alert("Invalid date.  You must wait at least 3 days before you can request a report.")*/

else if(!myForm.SC_date.value.match(re))
    window.alert("Invalid date.  Please enter the date as follows: mm/dd/yyyy.")

HTML コード:

<td>Date of Variance </td>
    <td colspan="2"><input name="SC_date:*" id="SC_date" type="text" tabindex="06">
      </textarea><b><span class="style3">*</span>&nbsp;&nbsp;</b><span class="style2">(mm/dd/yyyy)</span>
    </td>
4

3 に答える 3

2

文字列を操作して「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)

基本的に、日付文字列の解析は頭痛の種です。thisthis、および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.

これはかなり複雑に見えますが、基本的には次のとおりです。

  • floormodulo、およびビットは、月の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>削除してください。

于 2012-10-04T05:27:02.223 に答える
0

Globalize.jsやDate.jsなど、受け入れられる日付形式を制御できるライブラリを使用します。次に、実行する正確なテストを定義します。特に、時刻が重要であるかどうか、およびテストがユーザーのシステムの現在の時間に関連する必要があるかどうかを定義します(これはnew Date()引数なしで取得できるものです)。次に、たとえば@Mamsaacで概説されているように時間差を計算し、単純な算術でミリ秒を日数に変換できます。

使用するのは非論理的でDate()あり、結果を確認せずに、入力でパターンマッチングを開始します。さらに、Date()定義上、システムに依存するため、使用することはめったにありません。mm / dd/yyyyのような形式を受け入れる保証はありません。

于 2012-10-04T04:49:51.773 に答える
0

時間を気にしない場合は、次のことをお勧めします。

var dUser = new Date(date); //just like you did before
var dVarBegin = new Date("10/05/2012"); //here you do whatever is the date you are setting.
var diff = dVarBegin.getTime() - dUser.getTime();
//now diff is the difference in milliseconds!

3 日間に関するあなたの要件を完全には理解していません。ただし、日付の比較が必要な場合は、今すぐ比較できます。これがうまくいくことを願っています。さらに何か必要な場合は、3 日間のことについて少し詳しく説明してください。

于 2012-10-04T02:20:12.060 に答える