I want to check if a person is exaclty or over 18 years old. So I used the diff()
and duration()
functions to calculate the age of person. I wrote some tests with boundry values to test my logic. I wanted to test if I am exactly one day younger than 18 and exactly 18. So I chose two birthdays for testing (today is 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
I think the calculation is correct, because of leap-years. But in terms of birthday, the person shouldn't be 18 years old. Maybe there's a other way to do it with momentjs and I'm doing it wrong. If so, it would be nice to be mentioned in documentation of 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>
Chrome Version 56.0.2924.87 (64-bit) on 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
I think the calculation is wrong, but it's super close. Perhaps due to rounding errors?
For example:
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
So, in this case, moment.duration(end.diff(start)).asYears()
will return 18
around 16 hours before it should.
If you are trying to check if an age is over or equal to 18, you could compare the years, then (if 18 years apart) the months, then the days.
// 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();
}
Does it work better if you just use
age = moment().diff(birthday, 'years');
@mj1856
Ya, this works just fine.
// 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
Most helpful comment
Does it work better if you just use