时区问题需注意
使用日期对象直接表示日期会带来精度过高的问题。您需要管理时间和时区以避免这种情况,但它们可能在任何步骤中悄然回来。这个问题的被接受的答案也陷入了这个陷阱。
Javascript日期对象没有时区概念。它是一个时刻(自纪元以来的滴答数),具有用于转换成字符串和解析字符串的便捷(静态)函数,默认使用设备的“本地”时区,或者如果指定,则是UTC或其他时区。要使用日期对象表示只是日期™,您需要让您的日期表示所涉及日期的UTC午夜。这是一种常见而必要的约定,它使您能够处理与其创建季节或时区无关的日期。因此,您需要非常警惕,以管理时区的概念,无论是创建您的午夜UTC日期对象还是序列化它时。
很多人都对控制台的默认行为感到困惑。如果将日期放入控制台,您会看到输出会包括您的时区。这只是因为控制台在您的日期上调用了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');
序列化
在创建时已经考虑好了时区管理,现在需要确保在将其转换回字符串表示时将时区排除在外。因此,您可以安全地使用以下方法:
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);
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年更新...免费使用...
鉴于此回答的受欢迎程度,我将所有的功能都添加到了代码中。下面的函数返回一个包装后的日期对象,并且只公开那些仅与只有日期相关的函数。
使用Date对象调用它,就会解析为反映用户时区的JustADate。使用字符串调用:如果字符串是带有指定时区的ISO 8601,则我们将仅四舍五入时间部分。如果未指定时区,则会将其转换为反映本地时区的日期,就像对待日期对象一样。
function JustADate(initDate){
var utcMidnightDateObj = null
if(!initDate)
initDate = new Date();
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(!(initDate instanceof Date))
initDate = new Date(initDate);
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)
}
}
}
console.log(JustADate('1963-11-22T12:30:00-06:00').toLocaleDateString())
console.log("@prototype's issue fixed... " + JustADate('1963-11-22').toLocaleDateString())
date1.toDateString() === date2.toDateString()
这段代码与日期相关,意思是判断date1
和date2
是否在同一天。 - Naveendate.setFullYear(yyyy,mm,dd)
时,我得到了错误的结果,当我在日期上使用toString时,月份增加了1。在这个链接(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setFullYear)上在FireFox和Edge上进行了测试。 - Cheshiremoe