注意时区
使用date对象直接表示一个日期会使您陷入严重的精度过高问题。你需要管理时间和时区来阻止他们,他们可以在任何时候偷偷溜回来。这个问题的公认答案落入了陷阱。
A javascript date has no notion of timezone. It's a moment in time (ticks since the epoch) with handy (static) functions for translating to and from strings, using by default the "local" timezone of the device, or, if specified, UTC or another timezone. To represent just-a-date™ with a date object, you want your dates to represent UTC midnight at the start of the date in question. This is a common and necessary convention that lets you work with dates regardless of the season or timezone of their creation. So you need to be very vigilant to manage the notion of timezone, both when you create your midnight UTC Date object, and when you serialize it.
许多人对主机的默认行为感到困惑。如果向控制台喷射日期,您看到的输出将包括您的时区。这只是因为控制台在您的日期上调用toString(),而toString()为您提供了一个本地表示。基础日期没有时区!(只要时间匹配时区偏移量,您仍然有一个午夜UTC日期对象)
反序列化(或创建午夜UTC日期对象)
这是舍入步骤,诀窍是有两个“正确”答案。大多数情况下,您希望日期反映用户的本地时区。我现在所在的地方是几号?新西兰和美国的用户可以同时点击,通常会得到不同的日期。在这种情况下,做这个…
// create a date (utc midnight) reflecting the value of myDate and the environment's timezone offset.
new Date(Date.UTC(myDate.getFullYear(),myDate.getMonth(), myDate.getDate()));
有时,国际间的可比性胜过当地的准确性。在这种情况下,做这个…
// the date in London of a moment in time. Device timezone is ignored.
new Date(Date.UTC(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate()));
反序列化日期
线路上的日期通常采用YYYY-MM-DD格式。要反序列化它们,请这样做…
var midnightUTCDate = new Date( dateString + 'T00:00:00Z');
序列化
在创建时注意管理timezone之后,现在需要确保在转换回字符串表示时将timezone排除在外。所以你可以安全地使用…
toISOString ()
getUTCxxx ()
getTime() //返回一个没有时间和时区的数字。
. tolocaledatestring ("fr",{timeZone:"UTC"}) //任何你想要的语言环境,但总是UTC。
完全避免其他任何事情,尤其是……
getYear(),getMonth(),getDate()
所以回答你的问题,7年太晚了…
<input type="date" onchange="isInPast(event)">
<script>
var isInPast = function(event){
var userEntered = new Date(event.target.valueAsNumber); // valueAsNumber has no time or timezone!
var now = new Date();
var today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() ));
if(userEntered.getTime() < today.getTime())
alert("date is past");
else if(userEntered.getTime() == today.getTime())
alert("date is today");
else
alert("date is future");
}
</script>
看它在跑……
更新2022…免费的测试工具…
下面的代码现在是一个npm包Epoq。代码在github上。不客气:-)
更新2019…免费的东西……
鉴于这个答案很受欢迎,我把它都写进了代码。下面的函数返回一个包装好的日期对象,并且只公开那些可以安全地与just-a-date™一起使用的函数。
使用Date对象调用它,它将解析为反映用户时区的JustADate。用一个字符串调用它:如果字符串是一个指定了时区的ISO 8601,我们将只舍入时间部分。如果没有指定timezone,我们将把它转换为反映本地时区的日期,就像日期对象一样。
function JustADate(initDate){
var utcMidnightDateObj = null
// if no date supplied, use Now.
if(!initDate)
initDate = new Date();
// if initDate specifies a timezone offset, or is already UTC, just keep the date part, reflecting the date _in that timezone_
if(typeof initDate === "string" && initDate.match(/(-\d\d|(\+|-)\d{2}:\d{2}|Z)$/gm)){
utcMidnightDateObj = new Date( initDate.substring(0,10) + 'T00:00:00Z');
} else {
// if init date is not already a date object, feed it to the date constructor.
if(!(initDate instanceof Date))
initDate = new Date(initDate);
// Vital Step! Strip time part. Create UTC midnight dateObj according to local timezone.
utcMidnightDateObj = new Date(Date.UTC(initDate.getFullYear(),initDate.getMonth(), initDate.getDate()));
}
return {
toISOString:()=>utcMidnightDateObj.toISOString(),
getUTCDate:()=>utcMidnightDateObj.getUTCDate(),
getUTCDay:()=>utcMidnightDateObj.getUTCDay(),
getUTCFullYear:()=>utcMidnightDateObj.getUTCFullYear(),
getUTCMonth:()=>utcMidnightDateObj.getUTCMonth(),
setUTCDate:(arg)=>utcMidnightDateObj.setUTCDate(arg),
setUTCFullYear:(arg)=>utcMidnightDateObj.setUTCFullYear(arg),
setUTCMonth:(arg)=>utcMidnightDateObj.setUTCMonth(arg),
addDays:(days)=>{
utcMidnightDateObj.setUTCDate(utcMidnightDateObj.getUTCDate + days)
},
toString:()=>utcMidnightDateObj.toString(),
toLocaleDateString:(locale,options)=>{
options = options || {};
options.timeZone = "UTC";
locale = locale || "en-EN";
return utcMidnightDateObj.toLocaleDateString(locale,options)
}
}
}
// if initDate already has a timezone, we'll just use the date part directly
console.log(JustADate('1963-11-22T12:30:00-06:00').toLocaleDateString())
// Test case from @prototype's comment
console.log("@prototype's issue fixed... " + JustADate('1963-11-22').toLocaleDateString())