Skip to content

Commit 9302a83

Browse files
authored
Merge pull request #245 from github/update-rounding-rules-for-months-years-in-duration
update rounding rules for months/years in Duration
2 parents a276b7a + ae3e321 commit 9302a83

File tree

3 files changed

+1908
-441
lines changed

3 files changed

+1908
-441
lines changed

src/duration.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,14 @@ export function elapsedTime(date: Date, precision: Unit = 'second', now = Date.n
119119
)
120120
}
121121

122-
export function roundToSingleUnit(duration: Duration): Duration {
122+
interface RoundingOpts {
123+
relativeTo: Date | number
124+
}
125+
126+
export function roundToSingleUnit(duration: Duration, {relativeTo = Date.now()}: Partial<RoundingOpts> = {}): Duration {
127+
relativeTo = new Date(relativeTo)
123128
if (duration.blank) return duration
129+
const sign = duration.sign
124130
let years = Math.abs(duration.years)
125131
let months = Math.abs(duration.months)
126132
let weeks = Math.abs(duration.weeks)
@@ -131,7 +137,9 @@ export function roundToSingleUnit(duration: Duration): Duration {
131137
let milliseconds = Math.abs(duration.milliseconds)
132138

133139
if (milliseconds >= 900) seconds += Math.round(milliseconds / 1000)
134-
if (seconds || minutes || hours || days || weeks || months || years) milliseconds = 0
140+
if (seconds || minutes || hours || days || weeks || months || years) {
141+
milliseconds = 0
142+
}
135143

136144
if (seconds >= 55) minutes += Math.round(seconds / 60)
137145
if (minutes || hours || days || weeks || months || years) seconds = 0
@@ -148,10 +156,17 @@ export function roundToSingleUnit(duration: Duration): Duration {
148156
if (weeks >= 4) months += Math.round(weeks / 4)
149157
if (months || years) weeks = 0
150158

151-
if (months >= 11) years += Math.round(months / 12)
159+
const currentMonth = relativeTo.getMonth()
160+
const delta = sign < 0 ? currentMonth : 12 - currentMonth
161+
if (months && months >= delta) {
162+
years += 1
163+
relativeTo.setFullYear(relativeTo.getFullYear() + sign)
164+
relativeTo.setMonth(0)
165+
months -= delta
166+
years += Math.floor(months / 12)
167+
}
152168
if (years) months = 0
153169

154-
const sign = duration.sign
155170
return new Duration(
156171
years * sign,
157172
months * sign,
@@ -164,8 +179,11 @@ export function roundToSingleUnit(duration: Duration): Duration {
164179
)
165180
}
166181

167-
export function getRelativeTimeUnit(duration: Duration): [number, Intl.RelativeTimeFormatUnit] {
168-
const rounded = roundToSingleUnit(duration)
182+
export function getRelativeTimeUnit(
183+
duration: Duration,
184+
opts?: Partial<RoundingOpts>,
185+
): [number, Intl.RelativeTimeFormatUnit] {
186+
const rounded = roundToSingleUnit(duration, opts)
169187
if (rounded.blank) return [0, 'second']
170188
for (const unit of unitNames) {
171189
if (unit === 'millisecond') continue

0 commit comments

Comments
 (0)