1

我有一个 HTML 表单,允许用户在其中输入日期以打印报告。但是,如果该日期在当前日期的 3 天内,我将其设置为告诉用户他们必须等待 3 天。出于某种原因,当我输入“09/30/2012”之类的代码时代码有效,但是当我输入“10/01/2012”时,错误检查会跳过。不过,如果它是两位数的月份(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

因此,这是一个更好的选择——将年、月和日期值(按顺序)传递给 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');
}

说到规范,这里有一件很酷的事情要注意,那就是在 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月份翻转(负数或大于 12 的月份)。modulodate==1
  • 生成的纪元时间瞬间转换为天数。
  • 您的日期值将添加到该天数。如果您的日期值是负数,那很好,它只会被减去。
  • 结果被传递回 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 回答