我认为您不想通过操作字符串来构建“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。
因此,这是一个更好的选择——将年、月和日期值(按顺序)传递给 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 的月份)。modulo
date==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>
,则将其删除。