iamkun / dayjs

⏰ Day.js 2kB immutable date-time library alternative to Moment.js with the same modern API
https://day.js.org
MIT License
47.01k stars 2.3k forks source link

dayjs duration Incorrect calculation #2726

Open 15678871232 opened 2 months ago

15678871232 commented 2 months ago

Describe the bug A clear and concise description of what the bug is. const duration2023 = this.$dayjs.duration(this.$dayjs('2023-12-31 23:59:59').diff(this.$dayjs('2023-01-01 00:00:00'))); out: { "years": 0, "months": 12, "days": 4, "hours": 23, "minutes": 59, "seconds": 59, "milliseconds": 0 }

const duration2024 = this.$dayjs.duration(this.$dayjs('2024-12-31 23:59:59').diff(this.$dayjs('2024-01-01 00:00:00'))); out: { "years": 1, "months": 0, "days": 0, "hours": 23, "minutes": 59, "seconds": 59, "milliseconds": 0 }

years 0&&1 Expected behavior A clear and concise description of what you expected to happen. Consistent year Information

juliusv commented 2 months ago

I think I'm seeing the same similar bug for converting a duration to either hours or days for anything larger than 30 days (it works until that point, breaks down after).

Here's a few simple test cases to reproduce where it breaks:

  // SUCCEEDS, it returns 29 days.
  it('convert just less than 30-something days to days', () => {
    expect(dayjs.duration((86400000 * 30) - 1).days()).toBe(29)
  })
  // FAILS, it returns 0 instead of 30 days.
  it('convert just less than 31-something days to days', () => {
    expect(dayjs.duration((86400000 * 31) - 1).days()).toBe(30)
  })
  // SUCCEEDS, it returns 23 hours.
  it('convert just less than 30-something days to hours', () => {
    expect(dayjs.duration((86400000 * 30) - 1).hours()).toBe(23)
  })
  // FAILS, it returns 13 instead of 23 hours.
  it('convert just less than 31-something days to hours', () => {
    expect(dayjs.duration((86400000 * 31) - 1).hours()).toBe(23)
  })
juliusv commented 2 months ago

Sorry, I wasn't dayjs-ing correctly. 30 is of course the number of days in a month, and months are separately extracted, and then 0 for the days makes sense. And then 13 for the hours comes from the fact that a month is not defined as exactly 30 days, but as const MILLISECONDS_A_MONTH = MILLISECONDS_A_YEAR / 12.

So please ignore my comment.