Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 52 additions & 5 deletions src/plugin/duration/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,58 @@ class Duration {
return wrapper(this.$ms, this)
}

humanize(withSuffix) {
return $d()
.add(this.$ms, 'ms')
.locale(this.$l)
.fromNow(!withSuffix)
humanize(options) {
let withSuffix = false

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i feel like withSuffix should rather be interval, referring to it being a time interval.

after all this isn't necessarily a suffix, it changes the entire sentence, not only the end of it.

let round = true
if (typeof options === 'boolean') {
withSuffix = options
} else if (typeof options === 'object' && options !== null) {
({ withSuffix, round = true } = options)
}
if (round) {
return $d()
.add(this.$ms, 'ms')
.locale(this.$l)
.fromNow(!withSuffix)
}
const loc = $d().locale(this.$l).$locale().relativeTime
const units = ['years', 'months', 'days', 'hours', 'minutes', 'seconds']
const unitMap = {
years: 'y',
months: 'M',
days: 'd',
hours: 'h',
minutes: 'm',
seconds: 's'
}
let resultStr = ''
const isFuture = this.$ms > 0
for (let i = 0; i < units.length; i += 1) {
const unitName = units[i]
const val = this.get(unitName)
if (val) {
const absVal = Math.abs(val)
const unitKey = unitMap[unitName]
let locKey = unitKey
if (absVal !== 1) {
const pluralKey = `${unitKey}${unitKey}`
if (loc[pluralKey]) {
locKey = pluralKey
}
}
const format = loc[locKey]
resultStr = format.replace('%d', absVal)
break
}
}
if (!resultStr) {
resultStr = loc.s
}
if (withSuffix) {
const pastOrFuture = isFuture ? loc.future : loc.past
return pastOrFuture.replace('%s', resultStr)
}
return resultStr
}

valueOf() {
Expand Down
1 change: 1 addition & 0 deletions src/plugin/relativeTime/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default (o, c, d) => {
future: 'in %s',
past: '%s ago',
s: 'a few seconds',
ss: '%d seconds',
m: 'a minute',
mm: '%d minutes',
h: 'an hour',
Expand Down
51 changes: 51 additions & 0 deletions test/plugin/duration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,54 @@ describe('Format', () => {
.toBe('2/02.0002TEST9:09:6:06:8:08:5:05:1:01:010')
})
})

it('humanize() with round: false option', () => {
// Test case from issue #2970: 45 minutes
expect(dayjs.duration({ minutes: 45 }).humanize({ round: false }))
.toBe('45 minutes')

// Test case from issue #2970: 10 seconds
expect(dayjs.duration({ seconds: 10 }).humanize({ round: false }))
.toBe('10 seconds')

// Test single second
expect(dayjs.duration({ seconds: 1 }).humanize({ round: false }))
.toBe('a few seconds')
Comment on lines +318 to +319

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i feel like if we say

dayjs.duration({ seconds: 1 }).humanize({ round: false })

it should be a second, to be consistent with

dayjs.duration({ minutes: 1 }).humanize({ round: false })

being a minute

same applies to withSuffix: true


// Test 1 minute
expect(dayjs.duration({ minutes: 1 }).humanize({ round: false }))
.toBe('a minute')

// Test 2 hours
expect(dayjs.duration({ hours: 2 }).humanize({ round: false }))
.toBe('2 hours')

// Test 1 year
expect(dayjs.duration({ years: 1 }).humanize({ round: false }))
.toBe('a year')

// --- Test backward compatibility (old way) ---
expect(dayjs.duration({ minutes: 45 }).humanize())
.toBe('an hour')

// --- Test suffix (withSuffix: true) + rounding off ---
expect(dayjs.duration({ minutes: 45 }).humanize({ round: false, withSuffix: true }))
.toBe('in 45 minutes')

// --- Test suffix (withSuffix: true) + rounding on (old way) ---
expect(dayjs.duration({ minutes: 45 }).humanize(true))
.toBe('in an hour')

// --- Test negative duration ---
expect(dayjs.duration({ minutes: -45 }).humanize({ round: false, withSuffix: true }))
.toBe('45 minutes ago')

// --- NEW TESTS FOR 100% COVERAGE ---
// Test fallback for zero/milliseconds
expect(dayjs.duration({ milliseconds: 100 }).humanize({ round: false }))
.toBe('a few seconds')

// Test fallback for zero/milliseconds WITH suffix
expect(dayjs.duration({ milliseconds: 200 }).humanize({ round: false, withSuffix: true }))
.toBe('in a few seconds')
})