moment / luxon

⏱ A library for working with dates and times in JS
https://moment.github.io/luxon
MIT License
15.23k stars 730 forks source link

toFormat with 'ZZZZ' token is significantly slower than without #1436

Open lemmingapex opened 1 year ago

lemmingapex commented 1 year ago

Describe the bug toFormat with 'ZZZZ' (or fetching the a DateTimes's offsetNameShort) is significantly slower than a format without 'ZZZZ'

To Reproduce

const iterations = 100000;

console.time("withZZZZ");
for (let i = 0; i < iterations; i++) {
  luxon.DateTime.fromMillis(Math.floor(Math.random()*iterations)).setZone("America/New_York").toFormat("h:mm:ss.SSS a ZZZZ");
}
console.timeEnd("withZZZZ");

console.time("withoutZZZZ");
for (let i = 0; i < iterations; i++) {
  luxon.DateTime.fromMillis(Math.floor(Math.random()*iterations)).setZone("America/New_York").toFormat("h:mm:ss.SSS a")
}
console.timeEnd("withoutZZZZ");

console.time("withOffsetNameShort");
for (let i = 0; i < iterations; i++) {
  dt = luxon.DateTime.fromMillis(Math.floor(Math.random()*iterations)).setZone("America/New_York");
  dt.toFormat("h:mm:ss.SSS a ") + dt.offsetNameShort;
}
console.timeEnd("withOffsetNameShort");

Actual vs Expected behavior In the above example. 'withZZZZ' is about 12 times slower on my machine than 'withoutZZZZ'. I did not expect such a drastic difference in performance. Do you have any suggestions on how I can speed up this code? (the timezone does not change within the loop, the millis do change within the loop)

Desktop (please complete the following information):

Any information you have is helpful. Thanks!

lemmingapex commented 1 year ago

This cache of the offsetNameShort based on isInDST gives a ~60% increase in speed, but the isInDST is still quite slow. I would expect this call to be quicker. Any ideas as to the slowness in the .isInDST call?

const iterations = 100000;
const zoneName = "America/New_York";

const offsetNameShortCache = {
  "DST": null,
  "notDST": null
};

getOffsetNameShort = (dateTime) => {
  let cacheKey = "notDST";
  if (dateTime.isInDST) {
    cacheKey = "DST";
  }
  let offsetNameShort = offsetNameShortCache[cacheKey];
  if (offsetNameShort == null) {
    offsetNameShort = dt.toFormat("ZZZZ");
    offsetNameShortCache[cacheKey] = offsetNameShort;
  }
  return offsetNameShort;
};

console.time("withCache");
for (let i = 0; i < iterations; i++) {
  dt = luxon.DateTime.fromMillis(Math.floor(Math.random()*iterations)).setZone(zoneName);
  dt.toFormat("h:mm:ss.SSS a ") + getOffsetNameShort(dt);
}
console.timeEnd("withCache");
lemmingapex commented 5 months ago

Any update on this?