Comparando parte da data apenas sem comparar a hora no JavaScript


397

O que há de errado com o código abaixo?

Talvez fosse mais simples comparar a data e não a hora. Também não sei como fazer isso e procurei, mas não consegui encontrar o meu problema exato.

Aliás, quando eu mostro as duas datas em um alerta, elas são exatamente iguais.

Meu código:

window.addEvent('domready', function() {
    var now = new Date();
    var input = $('datum').getValue();
    var dateArray = input.split('/');
    var userMonth = parseInt(dateArray[1])-1;
    var userDate = new Date();
    userDate.setFullYear(dateArray[2], userMonth, dateArray[0], now.getHours(), now.getMinutes(), now.getSeconds(), now.getMilliseconds());

    if (userDate > now)
    {
        alert(now + '\n' + userDate);
    }
});

Existe uma maneira mais simples de comparar datas e não incluir a hora?

Respostas:


781

Ainda estou aprendendo JavaScript, e a única maneira que encontrei para comparar duas datas sem o tempo é usar o setHoursmétodo do objeto Date e definir horas, minutos, segundos e milissegundos para zero. Em seguida, compare as duas datas.

Por exemplo,

date1 = new Date()
date2 = new Date(2011,8,20)

date2será definido com horas, minutos, segundos e milissegundos para zero, mas a data1 os definirá para a hora em que a data1 foi criada. Para se livrar das horas, minutos, segundos e milissegundos na data1, faça o seguinte:

date1.setHours(0,0,0,0)

Agora você pode comparar as duas datas como DATAS apenas sem se preocupar com elementos de tempo.


63
Esteja ciente de que o teste por date1 === date2não parece fornecer um comportamento consistente; é melhor fazer date1.valueOf() === b.valueOf()ou até mesmo date1.getTime() === date2.getTime(). Estranho.
Erwin Wessels

4
Cuidado: se date1 e date2 estiverem no inverno e no verão, e você planeja iterar de um para o outro com addDays (1), o problema é que eles não terão o mesmo fuso horário por causa do horário de verão, portanto, o último comparar que deve ter datas iguais não funcionará porque as duas datas não são realmente 00: 00: 00: 0.
913 Oliver Oliver

9
Eu sei que essa é uma pergunta antiga, mas aparece primeiro no google durante a pesquisa. Tenha cuidado com esta resposta. Isso fornecerá respostas incorretas se o usuário não estiver no mesmo fuso horário que o criador do objeto de data. Por exemplo, altere o fuso horário no SO do computador para o horário da Costa Leste (EUA). Abra o console do seu navegador e digite var date2 = new Date(2011,8,20). Agora altere o fuso horário do sistema operacional para Horário do Pacífico (EUA). No mesmo console do navegador, digite date2.toDateString()e você voltará Mon Sep 19 2011em vez da terça-feira, dia 20!
Adam

9
Observe também que setHours()define o tempo com base no fuso horário atual, detectado automaticamente pelo navegador. Tente: t = new Date("2016-02-29T01:45:49.098Z"); t.setHours(0,0,0,0); console.log(t.toJSON());será impresso "2016-02-28T15:00:00.000Z", data 28, mas não 29 Meu fuso horário atual éAsia/Tokyo
transang

8
Essa resposta realmente deve ser atualizada para usar setUTCxxxmétodos em vez das variantes com reconhecimento de fuso horário / local.
Stijn de Witt

136

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())


3
Sua resposta contém informações realmente valiosas! Infelizmente, você não adicionou a resposta à pergunta real do OP, impedindo-me de votá-la novamente. Tente adicionar um pequeno trecho de código que responda à pergunta do OP.
Stijn de Witt

Ha ha ha @ '7 anos tarde demais'! Eu gosto do seu estilo de usuário1585345! Você conseguiu meu voto!
Stijn de Witt

Achei isso útil. Observe que há um erro de digitação no snippet "comparabilidade internacional". Eu acho que deveria ser: new Date (Date.UTC (myDate.getUTCFullYear (), myDate.getUTCMonth (), myDate.getUTCDate ()));
RikRak

11
Eu gostaria de poder votar esta resposta 100 vezes !!!
Sнаđошƒаӽ

77

Que tal agora?

Date.prototype.withoutTime = function () {
    var d = new Date(this);
    d.setHours(0, 0, 0, 0);
    return d;
}

Permite comparar a parte da data dessa data sem afetar o valor da sua variável:

var date1 = new Date(2014,1,1);
new Date().withoutTime() > date1.withoutTime(); // true

Essa é de longe a resposta mais elegante para o post original. Eu não criei uma função separada para meus propósitos, apenas incluí as duas linhas de código.
Danimal Reks

25

Usando Moment.js

Se você tem a opção de incluir uma biblioteca de terceiros, definitivamente vale a pena dar uma olhada no Moment.js . Isso facilita o trabalho Datee DateTimemuito, muito mais.

Por exemplo, vendo se uma Data vem após outra Data, mas excluindo o horário, você faria algo assim:

var date1 = new Date(2016,9,20,12,0,0); // October 20, 2016 12:00:00
var date2 = new Date(2016,9,20,12,1,0); // October 20, 2016 12:01:00

// Comparison including time.
moment(date2).isAfter(date1); // => true

// Comparison excluding time.
moment(date2).isAfter(date1, 'day'); // => false

O segundo parâmetro que você passar para isAfteré a precisão para fazer a comparação e pode ser qualquer um year, month, week, day, hour, minuteou second.


4
obteve uma aceleração de 100x passando de uma solução momentjs para uma solução Date () + sethours. amigos cuidadosos :-)
2c2c

@ 2c2c Interessante. Definitivamente bom saber o impacto no desempenho. Quantas operações você usou para seu benchmark?
Joshua Pinter

11
eu estava em cerca de 1mil comparações. não funcionavam configurar uma referência real
2c2c

17

Basta comparar usando .toDateString como abaixo:

new Date().toDateString();

Isso fará com que você retorne apenas a parte da data e não a hora ou o fuso horário, assim:

"Sex 03 Fev 2017"

Portanto, ambas as datas podem ser comparadas nesse formato da mesma forma, sem parte do tempo.


2
É um bom começo, mas não permitirá comparações porque agora é uma string. Para comparar, altere-o novamente para um objeto Date fazendo o seguinte new Date(new Date().toDateString());
Grid Trekkor

@GridTrekkor True, mas se você deseja apenas um teste rápido de igualdade, esta é a solução mais simples.
CM

8

Essa pode ser uma versão um pouco mais limpa, observe também que você sempre deve usar um radix ao usar o parseInt.

window.addEvent('domready', function() {
    // Create a Date object set to midnight on today's date
    var today = new Date((new Date()).setHours(0, 0, 0, 0)),
    input = $('datum').getValue(),
    dateArray = input.split('/'),
    // Always specify a radix with parseInt(), setting the radix to 10 ensures that
    // the number is interpreted as a decimal.  It is particularly important with
    // dates, if the user had entered '09' for the month and you don't use a
    // radix '09' is interpreted as an octal number and parseInt would return 0, not 9!
    userMonth = parseInt(dateArray[1], 10) - 1,
    // Create a Date object set to midnight on the day the user specified
    userDate = new Date(dateArray[2], userMonth, dateArray[0], 0, 0, 0, 0);

    // Convert date objects to milliseconds and compare
    if(userDate.getTime() > today.getTime())
    {
            alert(today+'\n'+userDate);
    }
});

Confira a página MDC parseInt para obter mais informações sobre o radix.

O JSLint é uma ótima ferramenta para capturar coisas como um radical ausente e muitas outras coisas que podem causar erros obscuros e difíceis de depurar. Obriga você a usar melhores padrões de codificação para evitar futuras dores de cabeça. Eu o uso em todos os projetos JavaScript que eu codifico.


@EmKay Isso não deve ser tão grande agora, já que o ES5 é bastante padrão na maioria dos navegadores e proíbe a interpretação octal, MAS alguns navegadores ainda podem estar usando a antiga interpretação octal por razões de compatibilidade com versões anteriores, então eu continuaria usando um radix para um futuro próximo.
Código inútil

Se você usar interpretações octais no modo estrito , lançará erros, o que é uma boa coisa, pois ajuda a encontrar erros que podem ser mal interpretados.
Código inútil


4

Se você estiver realmente comparando a data apenas com nenhum componente de hora, outra solução que pode parecer errada, mas funciona e evita todas as Date()dores de cabeça de fuso horário e tempo é comparar a data da string ISO diretamente usando a comparação de string:

> "2019-04-22" <= "2019-04-23"
true
> "2019-04-22" <= "2019-04-22"
true
> "2019-04-22" <= "2019-04-21"
false
> "2019-04-22" === "2019-04-22"
true

Você pode obter a data atual (data UTC, não necessariamente a data local do usuário) usando:

> new Date().toISOString().split("T")[0]
"2019-04-22"

Meu argumento a favor é a simplicidade do programador - é muito menos provável que você estrague isso do que tentar manipular datas e compensações corretamente, provavelmente ao custo da velocidade (não comparei o desempenho)


Você também pode fazer new Date().toISOString().substr(0, 10) // "2019-04-22".
stomy

Para a data local (data não UTC), você pode usar new Date().toLocaleDateString() // "8/26/2019". Mas comparar o texto não será preciso (como "8/26/2019" >= "9/29/2001"é falso). Portanto, você precisará convertê-lo new Date(new Date().toLocaleDateString())para comparar com precisão com outra Data.
stomy

4

Basta usar toDateString () nas duas datas. toDateString não inclui a hora; portanto, por 2 vezes na mesma data, os valores serão iguais, conforme demonstrado abaixo.

var d1 = new Date(2019,01,01,1,20)
var d2 = new Date(2019,01,01,2,20)
console.log(d1==d2) // false
console.log(d1.toDateString() == d2.toDateString()) // true

Obviamente, algumas das preocupações de fuso horário expressas em outras partes desta questão são válidas, mas em muitos cenários, essas não são relevantes.


11
No meu caso, esta solução é muito melhor do que a resposta selecionada e as respostas mais votadas. É explicitamente dito no título "sem comparar o tempo", esta solução faz exatamente isso, economizando a necessidade de definir o tempo para manipular a comparação. Para responder "O evento X e o evento Y aconteceram no mesmo dia", faz mais sentido comparar apenas a data do que responder "É 00: 00: 00.00 AM da data do evento X exatamente o mesmo com 00:00: 00.00 da data do evento Y? " que é o que muitos outros respondentes estão fazendo
Mr.K

3

É assim que eu faço:

var myDate  = new Date($('input[name=frequency_start]').val()).setHours(0,0,0,0);
var today   = new Date().setHours(0,0,0,0);
if(today>myDate){
    jAlert('Please Enter a date in the future','Date Start Error', function(){
        $('input[name=frequency_start]').focus().select();
    });
}

Atualmente, eu uso isso em produção e não tenho nenhum problema ou incompatibilidade de navegador, etc ... por que você está dizendo que isso getTime()é necessário?
Fabrizio

5
Esteja ciente de que setHours()modifica o objeto em que é chamado e retorna a data como um número de milissegundos (equivalente a chamada getTime()). Portanto, sua todayvariável não é um Dateobjeto como alguns esperariam, mas na verdade é um número inteiro de milissegundos. Como efeito colateral, é por isso que você não precisou ligar getTime()antes da comparação, pois já o possui de maneira obscura.
Timothy Walters

3

Como não vejo aqui uma abordagem semelhante e não estou gostando de definir h / m / s / ms como 0, pois isso pode causar problemas com a transição precisa para o fuso horário local com o dateobjeto alterado (presumo que sim), deixe-me introduza aqui isso, escrito alguns momentos atrás, função lil:

+: Fácil de usar, realiza operações básicas de comparação (comparando dia, mês e ano sem tempo.)
-: Parece que esse é o oposto completo do pensamento "pronto para uso".

function datecompare(date1, sign, date2) {
    var day1 = date1.getDate();
    var mon1 = date1.getMonth();
    var year1 = date1.getFullYear();
    var day2 = date2.getDate();
    var mon2 = date2.getMonth();
    var year2 = date2.getFullYear();
    if (sign === '===') {
        if (day1 === day2 && mon1 === mon2 && year1 === year2) return true;
        else return false;
    }
    else if (sign === '>') {
        if (year1 > year2) return true;
        else if (year1 === year2 && mon1 > mon2) return true;
        else if (year1 === year2 && mon1 === mon2 && day1 > day2) return true;
        else return false;
    }    
}

Uso:

datecompare(date1, '===', date2)para verificação de igualdade,
datecompare(date1, '>', date2)para verificação maior,
!datecompare(date1, '>', date2)para verificação menor ou igual

Além disso, obviamente, você pode alternar date1e date2em lugares para conseguir qualquer outra comparação simples.


Bom, além de mais, me ajudou, agora espero que as conversões iso não mordam, haha, thx.
Edencorbin

3

Uma maneira eficiente e correta de comparar datas é:

Math.floor(date1.getTime() / 86400000) > Math.floor(date2.getTime() / 86400000);

Ele ignora a parte do tempo, funciona para diferentes fusos horários e você também pode comparar a igualdade ==. 86400000 é o número de milissegundos em um dia ( = 24*60*60*1000).

Cuidado: o operador de igualdade nunca== deve ser usado para comparar objetos Date, porque falha quando você espera que um teste de igualdade funcione porque ele está comparando dois objetos Date (e não compara as duas datas), por exemplo:

> date1;
outputs: Thu Mar 08 2018 00:00:00 GMT+1300

> date2;
outputs: Thu Mar 08 2018 00:00:00 GMT+1300

> date1 == date2;
outputs: false

> Math.floor(date1.getTime() / 86400000) == Math.floor(date2.getTime() / 86400000);
outputs: true

Notas: Se você estiver comparando objetos Date com a parte da hora definida como zero, poderá usar, date1.getTime() == date2.getTime()mas dificilmente vale a pena a otimização. Você pode usar <, >, <=, ou >=quando se comparam Data objetos diretamente porque esses operadores primeiro converter o objeto Data chamando .valueOf()antes que o operador faz a comparação.


2

Depois de ler esta pergunta no mesmo período após a publicação, decidi postar outra solução, pois não a achei satisfatória, pelo menos para as minhas necessidades:

Eu usei algo como isto:

var currentDate= new Date().setHours(0,0,0,0);

var startDay = new Date(currentDate - 86400000 * 2);
var finalDay = new Date(currentDate + 86400000 * 2);

Dessa forma, eu poderia ter usado as datas no formato que desejava para processar posteriormente. Mas isso foi apenas para minha necessidade, mas eu decidi publicá-lo de qualquer maneira, talvez isso ajude alguém


11
Observe que sua currentDatevariável não é uma data, é um número de milissegundos desde 01-01-19 1970. O setHours()método modifica o objeto de data em que é chamado e retorna o equivalente a getTime()(valor da data em milissegundos desde 01-01 1970).
Timóteo Walters #

1

Certifique-se de construir userDatecom um ano de 4 dígitos como setFullYear(10, ...) !== setFullYear(2010, ...).


1

Você pode usar aritmética com o total de ms.

var date = new Date(date1);
date.setHours(0, 0, 0, 0);

var diff = date2.getTime() - date.getTime();
return diff >= 0 && diff < 86400000;

Eu gosto disso porque nenhuma atualização nas datas originais é feita e é realizada mais rapidamente do que a divisão e a comparação de strings.

Espero que esta ajuda!


1

Esse JS mudará o conteúdo após a data definida, aqui está a mesma coisa, mas no w3schools

date1 = new Date()
date2 = new Date(2019,5,2) //the date you are comparing

date1.setHours(0,0,0,0)

var stockcnt = document.getElementById('demo').innerHTML;
if (date1 > date2){
document.getElementById('demo').innerHTML="yes"; //change if date is > set date (date2)
}else{
document.getElementById('demo').innerHTML="hello"; //change if date is < set date (date2)
}
<p id="demo">hello</p> <!--What will be changed-->
<!--if you check back in tomorrow, it will say yes instead of hello... or you could change the date... or change > to <-->


1

Isso funciona para mim:

 export default (chosenDate) => {
  const now = new Date();
  const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
  const splitChosenDate = chosenDate.split('/');

  today.setHours(0, 0, 0, 0);
  const fromDate = today.getTime();
  const toDate = new Date(splitChosenDate[2], splitChosenDate[1] - 1, splitChosenDate[0]).getTime();

  return toDate < fromDate;
};

Na resposta aceita, há um problema de fuso horário e no outro horário não é 00:00:00


0

Sei que esta pergunta já foi respondida e talvez essa não seja a melhor maneira, mas no meu cenário está funcionando perfeitamente, então pensei que poderia ajudar alguém como eu.

se você tem date stringcomo

String dateString="2018-01-01T18:19:12.543";

e você só deseja comparar a parte da data com outro objeto Date em JS,

var anotherDate=new Date(); //some date

então você tem que converto stringde Dateobjeto usandonew Date("2018-01-01T18:19:12.543");

e aqui está o truque: -

var valueDate =new Date(new Date(dateString).toDateString());

            return valueDate.valueOf() == anotherDate.valueOf(); //here is the final result

Eu usei toDateString()deDate object JS, que retorna apenas a string Date.

Nota: Não se esqueça de usar o .valueOf() função ao comparar as datas.

mais informações sobre .valeOf()aqui é referência

Feliz codificação.


0

Isso vai ajudar. Eu consegui fazer assim.

var currentDate = new Date(new Date().getFullYear(), new Date().getMonth() , new Date().getDate())

0

Comparando com setHours()será uma solução. Amostra:

var d1 = new Date();
var d2 = new Date("2019-2-23");
if(d1.setHours(0,0,0,0) == d2.setHours(0,0,0,0)){
    console.log(true)
}else{
    console.log(false)
}

0
var fromdate = new Date(MM/DD/YYYY);
var todate = new Date(MM/DD/YYYY);
if (fromdate > todate){
    console.log('False');
}else{
    console.log('True');
}

se seu formato de data for diferente, use moment.js biblioteca para converter o formato da sua data e use o código acima para comparar duas datas

Exemplo:

Se a sua data estiver em "DD / MM / AAAA" e quiser convertê-la em "MM / DD / AAAA", consulte o exemplo de código abaixo

var newfromdate = new Date(moment(fromdate, "DD/MM/YYYY").format("MM/DD/YYYY"));
console.log(newfromdate);
var newtodate = new Date(moment(todate, "DD/MM/YYYY").format("MM/DD/YYYY"));
console.log(newtodate);

0

Você pode usar fp_incr (0). Que define a parte do fuso horário como meia-noite e retorna um objeto de data.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.