Skip to content

Commit

Permalink
feat: Huge perf improvement by caching Intl Api formatters
Browse files Browse the repository at this point in the history
  • Loading branch information
amirhmoradi committed May 31, 2023
1 parent 6575e9f commit 7f19395
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 27 deletions.
16 changes: 13 additions & 3 deletions src/calendarSystems/CalendarSystemBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* @description see README.md file included in the project
*
*/
import { generateMonthNames } from "../calendarUtils/IntlUtils";

// Possible calendars based on the Intl API:
// "buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic", "gregory", "hebrew",
Expand All @@ -18,6 +19,13 @@ export default class CalendarSystemBase {

constructor(locale = "en") {
this.locale = locale;
this.intlCalendar = "gregory";
this.firstMonthNameEnglish = "January";
this.monthNamesLocalized = generateMonthNames(
locale,
"gregory",
"January"
);
}

convertFromGregorian(date) {
Expand Down Expand Up @@ -45,10 +53,12 @@ export default class CalendarSystemBase {
if (monthIndex < 0 || monthIndex >= monthNames.length) {
throw new Error("Invalid month index.");
}
return this.monthNamesLocalized[monthIndex];

return new Intl.DateTimeFormat(this.locale, { month: "long" }).format(
new Date(2022, monthIndex)
);
// generateMonthNames(this.locale, this.intlCalendar, this.firstMonthNameEnglish);
// return new Intl.DateTimeFormat(this.locale, { month: "long" }).format(
// new Date(2022, monthIndex)
// );
}

localeOverride(locale) {
Expand Down
20 changes: 13 additions & 7 deletions src/calendarSystems/GregoryCalendarSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ import CalendarSystemBase from "./CalendarSystemBase";
import { generateMonthNames } from "../calendarUtils/IntlUtils";

export default class GregoryCalendarSystem extends CalendarSystemBase {
constructor(locale = "en") {
super();
this.firstDayOfWeek = 6; // Saturday
this.locale = locale;
this.intlCalendar = "gregory";
this.firstMonthNameEnglish = "January";
this.monthNamesLocalized = generateMonthNames(
locale,
"gregory",
"January"
);
}

convertToJulian(calendarYear, calendarMonth, calendarDay) {
// calendarMonth = calendarMonth+1 because the *_to_jd function month is 1-based
return CalendarUtils.gregorian_to_jd(
Expand Down Expand Up @@ -70,11 +83,4 @@ export default class GregoryCalendarSystem extends CalendarSystemBase {
monthNames(locale = "en", calendar = "gregory", firstMonthName = "January") {
return generateMonthNames(locale, calendar, firstMonthName);
}
// monthNames() {
// return Array.from({ length: 12 }, (_, i) =>
// new Intl.DateTimeFormat("en-US", { month: "long" }).format(
// new Date(1970, i)
// )
// );
// }
}
2 changes: 2 additions & 0 deletions src/calendarSystems/HijriCalendarSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export default class HijriCalendarSystem extends CalendarSystemBase {
super();
this.firstDayOfWeek = 6; // Saturday
this.locale = locale;
this.intlCalendar = "islamic-umalqura";
this.firstMonthNameEnglish = "Muharram";
this.monthNamesLocalized = generateMonthNames(
locale,
"islamic-umalqura",
Expand Down
2 changes: 2 additions & 0 deletions src/calendarSystems/PersianCalendarSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export default class PersianCalendarSystem extends CalendarSystemBase {
super();
this.firstDayOfWeek = 6; // Saturday
this.locale = locale;
this.intlCalendar = "persian";
this.firstMonthNameEnglish = "Farvardin";
this.monthNamesLocalized = generateMonthNames(
locale,
"persian",
Expand Down
53 changes: 36 additions & 17 deletions src/calendarUtils/IntlUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,56 @@
*
*/

const formattersCache = {};
const monthNamesCache = {};
const shiftedSortedMonthNamesCache = {};

/**
* Returns the localized name of a month.
* @param {number} monthIndex - The index of the month (0 = January, 11 = December).
* @param {string} locale - The locale to use.
* @returns {string} The localized name of the month.
*/
export function getLocalizedMonthName(monthIndex, locale = "en") {
return new Intl.DateTimeFormat(locale, { month: "long" }).format(
new Date(2023, monthIndex)
);
if (!formattersCache[locale]) {
formattersCache[locale] = new Intl.DateTimeFormat(locale, {
month: "long",
});
}
return formattersCache[locale].format(new Date(2023, monthIndex));
}

function getMonthNames(locale, calendar = "persian") {
const monthNames = [];
for (let i = 0; i < 12; i++) {
const date = new Date(2023, i, 1);
const formatter = new Intl.DateTimeFormat(`${locale}-u-ca-${calendar}`, {
month: "long",
});
monthNames.push(formatter.format(date));
const cacheKey = `${locale}-${calendar}`;

if (!monthNamesCache[cacheKey]) {
const monthNames = [];
for (let i = 0; i < 12; i++) {
const date = new Date(2023, i, 1);
const formatter = new Intl.DateTimeFormat(`${locale}-u-ca-${calendar}`, {
month: "long",
});
monthNames.push(formatter.format(date));
}
monthNamesCache[cacheKey] = monthNames;
}
return monthNames;

return monthNamesCache[cacheKey];
}

function shiftAndSortMonthNames(locale, firstMonthIndex, calendar = "persian") {
let monthNames = getMonthNames(locale, calendar);
monthNames = [
...monthNames.slice(firstMonthIndex),
...monthNames.slice(0, firstMonthIndex),
];
return monthNames;
const cacheKey = `${locale}-${firstMonthIndex}-${calendar}`;

if (!shiftedSortedMonthNamesCache[cacheKey]) {
let monthNames = getMonthNames(locale, calendar);
monthNames = [
...monthNames.slice(firstMonthIndex),
...monthNames.slice(0, firstMonthIndex),
];
shiftedSortedMonthNamesCache[cacheKey] = monthNames;
}

return shiftedSortedMonthNamesCache[cacheKey];
}

export function generateMonthNames(
Expand Down

0 comments on commit 7f19395

Please sign in to comment.