Cuidado com o fuso horário
O uso do objeto date para representar imediatamente uma data leva a um enorme problema de excesso de precisão. Você precisa gerenciar o tempo e o fuso horário para mantê-los fora, e eles podem voltar a qualquer momento. A resposta aceita para essa pergunta cai na armadilha.
Uma data javascript não tem noção de fuso horário . É um momento no tempo (ticks desde a época) com funções práticas (estáticas) para traduzir de e para strings, usando por padrão o fuso horário "local" do dispositivo ou, se especificado, UTC ou outro fuso horário. Para representar just-a-date ™ com um objeto de data, você deseja que suas datas representem o UTC à meia-noite no início da data em questão. Essa é uma convenção comum e necessária que permite trabalhar com datas, independentemente da estação ou do fuso horário de sua criação. Portanto, você precisa estar muito vigilante para gerenciar a noção de fuso horário, tanto ao criar seu objeto UTC Date da meia-noite quanto ao serializá-lo.
Muitas pessoas ficam confusas com o comportamento padrão do console. Se você pulverizar uma data no console, a saída exibida incluirá seu fuso horário. Isso ocorre apenas porque o console chama toString()
sua data e toString()
fornece uma representação local. A data subjacente não possui fuso horário ! (Enquanto a hora corresponder ao deslocamento do fuso horário, você ainda terá um objeto de data UTC da meia-noite)
Desserializando (ou criando objetos UTC Date da meia-noite)
Este é o passo de arredondamento, com o truque de que existem duas respostas "certas". Na maioria das vezes, você deseja que sua data reflita o fuso horário do usuário. Clique se hoje é seu aniversário . Os usuários da Nova Zelândia e EUA clicam ao mesmo tempo e obtêm datas diferentes. Nesse caso, faça isso ...
// 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()));
Às vezes, a comparabilidade internacional supera a precisão local. Nesse caso, faça isso ...
// the date in London of a moment in time. Device timezone is ignored.
new Date(Date.UTC(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate()));
Desserializar uma data
Frequentemente, as datas na transmissão estão no formato AAAA-MM-DD. Para desserializá-los, faça isso ...
var midnightUTCDate = new Date( dateString + 'T00:00:00Z');
Serialização
Tendo tomado o cuidado de gerenciar o fuso horário ao criar, agora é necessário manter o fuso horário ao converter novamente em uma representação de sequência. Então você pode usar com segurança ...
toISOString()
getUTCxxx()
getTime() //returns a number with no time or timezone.
.toLocaleDateString("fr",{timezone:"UTC"}) // whatever locale you want, but ALWAYS UTC.
E evite totalmente tudo o mais, especialmente ...
getYear()
, getMonth()
,getDate()
Então, para responder sua pergunta, 7 anos tarde demais ...
<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>
Veja em execução ...
Atualização 2019 ... coisas grátis ...
Dada a popularidade desta resposta, coloquei tudo em código. A função a seguir retorna um objeto de data agrupada e expõe apenas as funções seguras para uso com o just-a-date ™.
Chame-o com um objeto Date e ele resolverá o JustADate refletindo o fuso horário do usuário. Chame-o com uma sequência: se a sequência for uma ISO 8601 com o fuso horário especificado, concluiremos a parte do tempo. Se o fuso horário não for especificado, nós o converteremos em uma data que reflita o fuso horário local, assim como nos objetos de data.
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{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())
date1 === date2
não parece fornecer um comportamento consistente; é melhor fazerdate1.valueOf() === b.valueOf()
ou até mesmodate1.getTime() === date2.getTime()
. Estranho.