2

I was using "moment.js" in my project (like age calculator), but I want to replace it with "date-fns".

Using moment.js, I formatted the input value as DD / MM / YYYY (for TR) and was calculating the age by subtracting the current date but right now I am having trouble doing this with date-fns. I felt like moment.js came easier to use.

Moment.js age calculator codes: I entered the input on 10/03/1998. (DD/MM/YYYY -> Turkey)

const birthDay = moment(value, 'DD/MM/YYYY');
console.log(birthDay); // (output: 10/03/1998)
const now = moment();
console.log(now); // (output: Thu Mar 04 2021 10:40:09 // TR Local Time)
const age = moment.duration(now.diff(birthDay)).years();
console.log(age); // (output: 22)

I tried to do it with date-fns but was not successful. I can not calculate the age.

const birthDay = format(new Date(value), 'dd/MM/yyyy');
console.log(birthDay); // (output: 03/10/1998 - **issue 1**)
const now = new Date();
console.log(now); // (output: Thu Mar 04 2021 10:45:18 // TR Local Time)
const age = differenceInCalendarYears(now, birthDay);
console.log(age); // (output: NaN - - **issue 2**)

I would appreciate it if you could help with date-fns.

I edited for the answer, right now it's like this:

 const birthDay = new Date(value);
 console.log(birthDay); // Oct 03 1998 (03/10/1998) it's MM/DD, I want DD/MM
 const now = new Date();
 console.log(now); // Mar 04 2021
 const age = differenceInCalendarYears(now, birthDay);
 console.log(age); // it should be 22 but 23.
ogulcan
  • 125
  • 1
  • 4
  • 13
  • It's worth mentioning that you should not use `differenceInCalendarYears` as the result will be incorrect. Please see my answer below stackoverflow.com/a/68673608/886592 – volpato Aug 11 '21 at 10:36

4 Answers4

7

Your age depends on whether you had your anniversary on the current year. That's why you should NOT use differenceInCalendarYears to calculate the age: it does not take into account the current month and day, only the year.

Use differenceInYears instead, or intervalToDuration if you want to get the age including months and days.

const { differenceInCalendarYears, differenceInYears, intervalToDuration, parse } = require("date-fns")

function calculateAge(dob) {
    const date = parse(dob, "dd/MM/yyyy", new Date());
    const age = differenceInYears(new Date(), date);
    return age;
}

// INCORRECT
function calculateAge2(dob) {
    const date = parse(dob, "dd/MM/yyyy", new Date());
    const age = differenceInCalendarYears(new Date(), date);
    return age;
}

console.log("dob = 01/04/2000"); // Running on 2021-08-05
console.log('- using differenceInYears: ', calculateAge("01/04/2000")); // 21
console.log('- using differenceInCalendarYears: ', calculateAge2("01/04/2000")); // 21

console.log("dob = 01/10/2000"); // Running on 2021-08-05
console.log('- using differenceInYears: ', calculateAge("01/10/2000")); // 20
console.log('- using differenceInCalendarYears: ', calculateAge2("01/10/2000")); // 21

function calculateFullAge(dob) {
    const birthDate = parse(dob, "dd/MM/yyyy", new Date());
    const { years, months, days } = intervalToDuration({ start: birthDate, end: new Date()});
    return { years, months, days };
}

// Running on 2021-08-05
console.log('- using intervalToDuration: ', calculateFullAge("01/04/2000")); // {years: 21, months: 4, days: 4}
console.log('- using intervalToDuration: ', calculateFullAge("01/10/2000")); // {years: 20, months: 10, days: 4}

You can run this in the following runkit

volpato
  • 1,262
  • 17
  • 21
6

I recently had a similar situation & this is how I implemented it

import { differenceInYears, parse } from "date-fns"

const calculateAge = (dob: string): number => {
    const date = parse(dob, "dd/MM/yyyy", new Date())
    const age = differenceInYears(new Date(), date)
    return age
  }


calculateAge("11/11/2019")    // returns 2 

PS: consider removing types (:string & :number) if you're only using JS

Syed Mustaqhim
  • 453
  • 3
  • 13
  • 2
    You should not use `differenceInCalendarYears` as the result will be incorrect. Please see my answer below https://stackoverflow.com/a/68673608/886592 – volpato Aug 05 '21 at 21:20
2

Try this ;)

import { intervalToDuration } from "date-fns"

const calculateAge = (dob: string): number => {
  const interval = intervalToDuration({
    start: new Date(dob),
    end: new Date(),
  })

  return interval.years ? interval.years : 0
}
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 31 '22 at 03:17
1

Your problem is parsing the date string (timestamp) using:

const birthDay = new Date(value);

It's strongly recommended not to use the built–in parser, see Why does Date.parse give incorrect results?

Since you're using Date.fns, use it for parsing too.

And as @volpato points out, you should use differenceInYears not differenceInCalendarYears as the later is effectively just currentDate.getFullYear() - birthday.getFullYear():

let dateFns = require("date-fns")

let d = '10/03/1998'; // 10 Mar 1998
let date = dateFns.parse(d, 'dd/MM/yyyy', new Date());
let age = dateFns.differenceInYears(new Date(), date);
console.log(age); // 23 when run on 4 Mar 2021

The above can be run at npm.runkit.com

RobG
  • 142,382
  • 31
  • 172
  • 209
  • You should not use `differenceInCalendarYears` as the result will be incorrect. Please see my answer below https://stackoverflow.com/a/68673608/886592 – volpato Aug 05 '21 at 21:20
  • 1
    @volpato—cool, you probably should post a comment to that effect on the OP since other answers (including mine) just focused on the parsing issue and ignored other issues in the code. :-) – RobG Aug 06 '21 at 02:20