luxon
luxon copied to clipboard
`toRelative` is really slow
Describe the bug
Not necessarily a bug, but toRelative()
is really slow and the reason isn't the Intl api.
I'm using luxon in a react-native app, and when formatting dates on a mid-level Android phone, a single call to .toRelative()
takes around 15 milliseconds to return.
When you have a bigger list, this absolutely kills performance.
I tracked it down to this function: https://github.com/moment/luxon/blob/9a7e46b6e635db89c1c94e18a8c53c28341b7c5e/src/datetime.js#L1782-L1802
You can also verify this by running the built in benchmark in luxon at: https://github.com/moment/luxon/blob/e0c8f874304cd4ecc3944bdcff3d8f8c27102a18/benchmarks/datetime.js#L59-L61
Which can only do around 10000 operations per second on my M1 cpu in NodeJS. Others functions in that benchmark can do hundreds of thousands, so it's definitely a problem.
To Reproduce
Run the benchmark at https://github.com/moment/luxon/blob/e0c8f874304cd4ecc3944bdcff3d8f8c27102a18/benchmarks/datetime.js#L59-L61
Actual vs Expected behavior
Should not be so slow.
Desktop (please complete the following information):
- OS: Android
- Browser: React-Native
- Luxon version: 1.25.0
Additional context
Note that using https://www.npmjs.com/package/javascript-time-ago is much much faster (less than 1 ms per format on the same Android device), so I'm sure some improvements are possible
Here's a quick benchmark:
const Benchmark = require("benchmark");
const { DateTime } = require("luxon");
const TimeAgo = require("javascript-time-ago");
const en = require("javascript-time-ago/locale/en");
const suite = new Benchmark.Suite();
const dt = DateTime.now().minus({ days: 42 });
const date = dt.toJSDate();
TimeAgo.addLocale(en)
const ta = new TimeAgo("en");
console.log(dt.toRelative());
console.log(ta.format(date));
suite
.add("luxon", () => {
dt.toRelative();
})
.add("javascript-time-ago", () => {
ta.format(date);
})
.on("cycle", (event) => {
console.log(String(event.target));
})
.on("complete", function () {
console.log("Fastest is " + this.filter("fastest").map("name"));
})
.run();
Results:
1 month ago
1 month ago
luxon x 12,427 ops/sec ±1.25% (89 runs sampled)
javascript-time-ago x 249,242 ops/sec ±3.58% (93 runs sampled)
Fastest is javascript-time-ago
Hi @andreialecu ! Thanks for your investigation, it's helpful. But your Luxon version that you tried currently is too old.
Could you please try it again and show the results?
➜ node benchmark.js
luxon x 59,360 ops/sec ±0.69% (94 runs sampled)
javascript-time-ago x 366,422 ops/sec ±0.28% (100 runs sampled)
Fastest is javascript-time-ago
Still 6x slower than javascript-time-ago
with luxon 2.3.0
. Seems faster than before however.
Oh, thanks for this such a quick answer!
@andreialecu could you please tip me with following:
As I understand toRelative()
function can't display the label like "just now" (as javascript-time-ago
can) for rounded seconds, or for units array that we can pass as options into toRelative()
like:
[ "years", "quarters", "months", "weeks", "days", "hours", "minutes"]
https://moment.github.io/luxon/api-docs/index.html#datetimetorelative
?
I ended up not using toRelative()
because of the performance problems with it on React Native Android, but as far as I remember it cannot display just now
, no.
Okay, thanks! @andreialecu