dayjs
dayjs copied to clipboard
Duration between dates seems to be incorrect
Describe the bug Duration seems to be incorrect. The difference between March 29th, 2020 and March 28th 2021 should be less than 12 months
Expected behavior Calculating the difference between two days one year apart from each other should yield a difference of one year.
Information
- Day.js Version: 1.10.3
- OS: Windows 10 20H2
- Browser Chrome 89
- Time zone: GMT -4:00
I'm trying to get the difference between two dates:
- A fixed date (March 29th, 2020)
- Todays date (at the time of writing March 28th, 2021)
I do that with:
const lockdown = dayjs("3/29/2020", "M/DD/YYYYY"); //29th March 2020
const currentDate = dayjs();
// get the difference between the moments
const diff = currentDate.diff(lockdown);
//express as a duration
const diffDuration = dayjs.duration(diff);
// display
const timeInLockDown = {
months: diffDuration.months(),
days: diffDuration.days(),
hours: diffDuration.hours(),
minutes: diffDuration.minutes(),
seconds: diffDuration.seconds()
};
This yields diffDuration
as:
days: 4
hours: 1
milliseconds: 709
minutes: 4
months: 12
seconds: 5
years: 0
Which doesn't make sense to me? It shouldn't 12 months and 4 days. Also, I think that if it is 12 months and 4 days, then years should be 1 but in this instance it's 0.
Is this expected behaviour?
Just to add to @simeon9696 's issue, using the CustomParseFormat
plugin along with Duration
plugin returns NaN
for diff
in above example.
https://runkit.com/6052c5915dac89001a8e3602/606151bf64ef4e00192ea162
I just noticed a bug and it seems related to this issue:
// dayjs version 1.10.5
import dayjs from 'dayjs';
import dayjsDurationPlugin from 'dayjs/plugin/duration';
const a = dayjs('3/19/2018');
const b = dayjs('3/17/2021');
const diff = b.diff(a, 'day'); // => 1094 correct
dayjs.duration(diff, 'days'); // => { years: 2, months: 12, days: 4 } incorrect
I would expect the output to be { years: 3, days: 4 }
.
is there any movement on this? just stumbled across it myself
Is there any further on this, please? I too have encountered this issue.
any update?
I encountered this issue today too.
Example
startDate = dayjs("2021-09-21")
endDate = dayjs("2050-09-21")
dayjs(startDate).add(29, "y").toDate() // returns "2050-09-21", same as endDate as expected -- 29 years' difference
dayjs.duration(endDate.diff(startDate)) // returns an object containing 29 years and 7 days instead
Thoughts
As the code @avand pasted above actually also shows, the issue is the interaction between diff
and duration
.
The method diff
by itself, if you don't specify a unit of time argument, basically returns the difference between the two dates in milliseconds. This difference is accurate but has no context.
If you then pass this milliseconds result to duration
it seems to simply work out how long that should be in terms of fixed month lengths, etc. The milliseconds have no context with them as to the dates they originally sat between. Hence you get these weird rounding errors.
That's my theory anyway.
Workaround?
Until this is fixed, a workaround might be to use diff
more specifically.
So say for me, for now, I want my interface to recognise that from 2021-09-21 to 2050-09-21 is 29 years but that 2021-09-21 to 2050-09-20 (just a day less) is still 28 years.
I can do this with:
dayjs("2050-09-21").diff(dayjs("2021-09-21"), "years")
If I then pass this onto duration
, the result I get back is accurate.
Summary of problem
In short I think both the way diff
gets rid of the context of its calculations and the fact that duration
doesn't expect any context is the problem here.
Further evidence for the above observed in comment on a related issue.
Brief thread on more accurate duration requirements also adds to this.
Same problem here: const monthDifference = dayjs("2023.03.04").diff(dayjs("2023.02.06"), "month"); Result: 0 Though, this does works: const monthDifference = dayjs("2023.03.04").get("month") - (dayjs("2023.02.06").get("month")); Result: 1
Here too:
const diffMonth = to.diff(from, 'month');
console.log({fromParam, toParam, diffMonth, diffMonth2: to.get('month') - from.get('month')});
{fromParam: '2023-05-29', toParam: '2023-07-02', diffMonth: 1, diffMonth2: 2}
"dayjs": "^1.11.7"
"dayjs": "1.11.10"
In my experience, you can't rely on the duration method when calculating duration in months or years. This is due to the fact that months do not contain the same number of days, and the calculations use one fixed value: ~30.41666 (30 days 10 hours).
Example:
const dateFrom = "2024-02-02T00:00:00"; // February 2, 2024
let dateTo = "2024-03-03T00:00:00"; // March 3, 2024
const duration1 = dayjs.duration(dayjs(dateTo).diff(dayjs(dateFrom))); // 0 months, 30 days, 0 hours
dateTo = "2024-03-04T00:00:00"; // March 4, 2024urs
const duration2 = dayjs.duration(dayjs(dateTo).diff(dayjs(dateFrom))); // 1 month. 0 days, 14 hours