Quero verificar se a pessoa tem idade exata ou tem mais de 18 anos. Portanto, usei as funções diff()
e duration()
para calcular a idade da pessoa. Eu escrevi alguns testes com valores de limite para testar minha lógica. Queria testar se tenho exatamente um dia menos de 18 anos e exatamente 18 anos. Escolhi dois aniversários para fazer o teste (hoje é 27/02/2017):
// today date is: 27.02.2017
// exactly age 18
var birthday = moment("27.02.1999", "DD.MM.YYYY"),
age = moment.duration(moment().diff(birthday)).asYears();
console.log(age); // output: 18.00325100985672; expected: == 18
// one day under age 18
var birthday = moment("28.02.1999", "DD.MM.YYYY"),
age = moment.duration(moment().diff(birthday)).asYears();
console.log(age); // output: 18.00053005036735; expected: < 18
Acho que o cálculo está correto, por causa dos anos bissextos. Mas em termos de aniversário, a pessoa não deveria ter 18 anos. Talvez haja outra maneira de fazer isso com os momentos e eu estou fazendo errado. Nesse caso, seria bom ser mencionado na documentação do momentjs.
<form id="newsletter-form" data-parsley-validate="">
<input id="birthday" type="text" class="form-control" required="" data-parsley-minage="18">
<input type="submit" class="btn btn-default" value="subscribe">
</form>
<script type="text/javascript">
$(function () {
window.Parsley.addValidator('minage', {
validateString: function(value, minAge) {
var birthday = moment(value, "DD.MM.YYYY"),
age = moment.duration(moment().diff(birthday)).asYears();
return (age >= minAge);
},
requirementType: 'integer',
messages: {
en: 'You must be mature.'
}
});
});
</script>
<script type="text/javascript">
$(function () {
$('#newsletter-form').parsley()
// field validation
.on('form:submit', function() {
return false; // do not submit
});
});
</script>
Versão do Chrome 56.0.2924.87 (64 bits) no Windows 7
console.log( (new Date()).toString()) // Mon Feb 27 2017 13:38:04 GMT+0100 (Mitteleuropäische Zeit)
console.log((new Date()).toLocaleString()) // 27.2.2017, 13:38:04
console.log( (new Date()).getTimezoneOffset()) // -60
console.log( navigator.userAgent) // Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
console.log(moment.version) // 2.17.1
Acho que o cálculo está errado, mas está super parecido. Talvez devido a erros de arredondamento?
Por exemplo:
a = moment("27.02.1999", "DD.MM.YYYY");
b = moment("28.02.1999", "DD.MM.YYYY");
c = moment("27.02.2017", "DD.MM.YYYY");
moment.duration(c.diff(a)).asYears(); // 18.00173857094944
moment.duration(c.diff(b)).asYears(); // 17.99900066394245
Portanto, neste caso, moment.duration(end.diff(start)).asYears()
retornará 18
cerca de 16 horas antes do esperado.
Se você está tentando verificar se uma idade é maior ou igual a 18, você pode comparar os anos, depois (se houver 18 anos de diferença) os meses e depois os dias.
// pseudocode, correctness not guaranteed
function is18(start, end) {
if (end.year() - start.year() == 18) {
if (end.month() == start.month()) {
return end.date() >= start.date();
}
return end.month() > start.month();
}
return end.year() - 18 > start.year();
}
Funciona melhor se você apenas usar
age = moment().diff(birthday, 'years');
@ mj1856
Sim, isso funciona muito bem.
// today date is: 03.03.2017
// exactly age 18
var birthday = moment("03.03.1999", "DD.MM.YYYY"),
age = moment().diff(birthday, 'years');
console.log(age); // output: 18; expected: == 18
// one day under age 18
var birthday = moment("04.03.1999", "DD.MM.YYYY"),
age = moment().diff(birthday, 'years');
console.log(age); // output: 17; expected: < 18
Comentários muito úteis
Funciona melhor se você apenas usar