Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b177067

Browse files
committedDec 31, 2024··
Reimplement elapsedTime to be precise.
The new implementation is consistent with `applyDuration` so that: if with `elapsedTime`: diff = d2 - d1 then with `applyDuration`: d1 + diff == d2
1 parent a80c1bf commit b177067

File tree

3 files changed

+274
-107
lines changed

3 files changed

+274
-107
lines changed
 

‎src/duration.ts

+72-19
Original file line numberDiff line numberDiff line change
@@ -95,27 +95,80 @@ export function applyDuration(date: Date | number, duration: Duration): Date {
9595
return r
9696
}
9797

98-
export function elapsedTime(date: Date, precision: Unit = 'second', now = Date.now()): Duration {
99-
const delta = date.getTime() - now
100-
if (delta === 0) return new Duration()
101-
const sign = Math.sign(delta)
102-
const ms = Math.abs(delta)
103-
const sec = Math.floor(ms / 1000)
104-
const min = Math.floor(sec / 60)
105-
const hr = Math.floor(min / 60)
106-
const day = Math.floor(hr / 24)
107-
const month = Math.floor(day / 30)
108-
const year = Math.floor(month / 12)
109-
const i = unitNames.indexOf(precision) || unitNames.length
98+
// Calculates the elapsed time from `now` to `date`.
99+
export function elapsedTime(
100+
date: Date,
101+
precision: Unit = 'second',
102+
nowTimestamp: Date | number = Date.now(),
103+
): Duration {
104+
const now = new Date(nowTimestamp)
105+
// eslint-disable-next-line prefer-const
106+
let [sign, subtrahend, minuend] = date < now ? [-1, now, date] : [1, date, now]
107+
let ms: number
108+
let sec: number
109+
let min: number
110+
let hr: number
111+
let day: number
112+
let month: number
113+
let year: number
114+
// Using UTC to avoid timezone-specific variations.
115+
if (subtrahend.getUTCMilliseconds() >= minuend.getUTCMilliseconds()) {
116+
ms = subtrahend.getUTCMilliseconds() - minuend.getUTCMilliseconds()
117+
} else {
118+
ms = 1000 + subtrahend.getUTCMilliseconds() - minuend.getUTCMilliseconds()
119+
subtrahend = new Date(subtrahend.getTime() - 1000)
120+
}
121+
122+
if (subtrahend.getUTCSeconds() >= minuend.getUTCSeconds()) {
123+
sec = subtrahend.getUTCSeconds() - minuend.getUTCSeconds()
124+
} else {
125+
sec = 60 + subtrahend.getUTCSeconds() - minuend.getUTCSeconds()
126+
subtrahend = new Date(subtrahend.getTime() - 1000 * 60)
127+
}
128+
129+
if (subtrahend.getUTCMinutes() >= minuend.getUTCMinutes()) {
130+
min = subtrahend.getUTCMinutes() - minuend.getUTCMinutes()
131+
} else {
132+
min = 60 + subtrahend.getUTCMinutes() - minuend.getUTCMinutes()
133+
subtrahend = new Date(subtrahend.getTime() - 1000 * 60 * 60)
134+
}
135+
136+
if (subtrahend.getUTCHours() >= minuend.getUTCHours()) {
137+
hr = subtrahend.getUTCHours() - minuend.getUTCHours()
138+
} else {
139+
hr = 24 + subtrahend.getUTCHours() - minuend.getUTCHours()
140+
subtrahend = new Date(subtrahend.getTime() - 1000 * 60 * 60 * 24)
141+
}
142+
143+
if (subtrahend.getUTCDate() >= minuend.getUTCDate()) {
144+
day = subtrahend.getUTCDate() - minuend.getUTCDate()
145+
} else {
146+
day = subtrahend.getUTCDate()
147+
subtrahend = new Date(subtrahend.getTime() - 1000 * 60 * 60 * 24 * day)
148+
day += Math.max(0, subtrahend.getUTCDate() - minuend.getUTCDate())
149+
}
150+
151+
year = subtrahend.getUTCFullYear() - minuend.getUTCFullYear()
152+
if (subtrahend.getUTCMonth() >= minuend.getUTCMonth()) {
153+
month = subtrahend.getUTCMonth() - minuend.getUTCMonth()
154+
} else {
155+
month = 12 + subtrahend.getUTCMonth() - minuend.getUTCMonth()
156+
year -= 1
157+
}
158+
159+
let precisionIndex = unitNames.indexOf(precision)
160+
if (precisionIndex === -1) {
161+
precisionIndex = unitNames.length
162+
}
110163
return new Duration(
111-
i >= 0 ? year * sign : 0,
112-
i >= 1 ? (month - year * 12) * sign : 0,
164+
precisionIndex >= 0 ? year * sign : 0,
165+
precisionIndex >= 1 ? month * sign : 0,
113166
0,
114-
i >= 3 ? (day - month * 30) * sign : 0,
115-
i >= 4 ? (hr - day * 24) * sign : 0,
116-
i >= 5 ? (min - hr * 60) * sign : 0,
117-
i >= 6 ? (sec - min * 60) * sign : 0,
118-
i >= 7 ? (ms - sec * 1000) * sign : 0,
167+
precisionIndex >= 3 ? day * sign : 0,
168+
precisionIndex >= 4 ? hr * sign : 0,
169+
precisionIndex >= 5 ? min * sign : 0,
170+
precisionIndex >= 6 ? sec * sign : 0,
171+
precisionIndex >= 7 ? ms * sign : 0,
119172
)
120173
}
121174

There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Please sign in to comment.