Non standard date string YYYYMMDD
As pointed out in the comments "Looks quite reasonable..." and as such there is not too much to review...
Well apart from the fact that new Date("19671031")
is not a valid date The date string as parsed by Date must be a valid date strings. (I did not spot this until halfway through the review)
Ignoring the fact your code does not work as a simple oversight and continuing on as initially started...
...I will therefor nit pick, and I do stress the point this is just nit picking for sake of a review.
Constants
Constants as const
The named vars today
, birthDate
, m
can all be const. In fact the whole thing can be rewritten to only use constants.
Names
Names are too verbose. The general rule is to use the scope to infer meaning, for names to preference 1 word over 2, 2 words over 3, etc... Short words rather than long. Common abbreviations instead of full words.
birthDate
can be birth
as date is inferred
dateString
can be dateStr
using the common abbreviation for string
today
could be now
. In context today
is the most accurate however nothing is lost if now
is used.
m
does not work as month
. The value represents a quantitative query (How many months?) and as such months
or better yet the abbreviated mths
... eww ... drop the s
for mth
Rewrite A
And then I realize it does not work
function getAge(dateStr) {
const birth = new Date(dateStr);
const now = new Date();
const mth = now.getMonth() - birth.getMonth();
const adjust = mth < 0 || (mth === 0 && now.getDate() < birth.getDate()) ? 1 : 0;
return now.getFullYear() - birth.getFullYear() - adjust;
}
Responsibility
A general rule for functions is that they should only do one thing. Your function has two tasks, parse the date string and calculate the age.
As the date string is likely an un-trusted source (eg user input) and as such requires vetting which is outside the functions responsibility (inferred by the name getAge
) the function should accept a Date rather than a string to parse.
This solves the problem of incorrectly formatted date string.
Rewrite B
As the birth date is now an argument the simple name birth
does not hold enough meaning to be clear so it is changed back to birthDate
function getAge(birthDate) {
const now = new Date();
const mth = now.getMonth() - birthDate.getMonth();
const adjust = mth < 0 || (mth === 0 && now.getDate() < birthDate.getDate()) ? 1 : 0;
return now.getFullYear() - birthDate.getFullYear() - adjust;
}
Parsing and vetting
The task of vetting and parsing the date string can now be handed to a more appropriate function.
The function assumes that the format is YYYYMMDD and returns a date only if the Date accepts the year, month, and day extracted from the string, that the date is earlier than now. It will return an age that fits within the Date object range (age of historical births)
If the date is invalid it can be said to be undefined and as such the function returns a Date
or undefined
.
function parseBirthDate(dateStr) {
const birth = new Date(dateStr.slice(0,4), dateStr.slice(4,6), dateStr.slice(6,8)););
const since = Date.now() - birth.getTime();
return isNaN(since) || since < 0 ? undefined : birth;
}
Using the two functions to get an age.
const birth = parseBirthDate("19671031");
const age = birth ? getAge(birth) : undefined;
Testing
A simple manual test snippet accepts a string input
function getAge(birthDate) {
const now = new Date();
const mth = now.getMonth() - birthDate.getMonth();
const adjust = mth < 0 || (mth === 0 && now.getDate() < birthDate.getDate()) ? 1 : 0;
return now.getFullYear() - birthDate.getFullYear() - adjust;
}
function parseBirthDate(dateStr) {
const birth = new Date(dateStr.slice(0,4), dateStr.slice(4,6), dateStr.slice(6,8));
const since = Date.now() - birth.getTime();
return isNaN(since) || since < 0 ? undefined : birth;
}
birthDate.addEventListener("change", () => {
const birth = parseBirthDate(birthDate.value);
const age = birth ? getAge(birth) : undefined;
ageDisplay.textContent = age !== undefined ?
"Age: " + age + " years old" :
"Invalid birth date!";
})
<label for="birthDate">Enter birth date:</label>
<input type="text" id="birthDate" maxlength="8" placeholder = "YYYYMMDD" size="8">
<div id="ageDisplay"></div>
age--
\$\endgroup\$ – CertainPerformance Oct 29 '20 at 15:32