UNPKG

faerun-date

Version:

Convert real-world dates into the Forgotten Realms (Faerûn) calendar format

114 lines (95 loc) 4 kB
// FaerunDate is a utility class to convert real-world dates into the Faerûn calendar format // from the Forgotten Realms setting in Dungeons & Dragons. It includes support for months, seasons, // holidays, weekdays, and event management. class FaerunDate { static MONTH_NAMES = [ "Hammer", "Alturiak", "Ches", "Tarsakh", "Mirtul", "Kythorn", "Flamerule", "Eleasis", "Eleint", "Marpenoth", "Uktar", "Nightal" ]; static FESTIVALS = [ { name: "Midwinter", day: 1, month: 2 }, { name: "Greengrass", day: 1, month: 4 }, { name: "Midsummer", day: 1, month: 7 }, { name: "Highharvestide", day: 27, month: 9 }, { name: "Feast of the Moon", day: 1, month: 11 }, { name: "Shieldmeet", day: 2, month: 7, leapYearOnly: true } ]; static SEASONS = [ { name: "Deepwinter", months: [1, 2] }, { name: "Spring", months: [3, 4, 5] }, { name: "Summer", months: [6, 7, 8] }, { name: "Autumn", months: [9, 10] }, { name: "Winter", months: [11, 12] } ]; static WEEKDAYS = [ "Sul", "Far", "Tar", "Sar", "Rai", "Zor", "Kyth", "Hamar", "Ith", "Alt" ]; constructor(date, options = {}) { const inputDate = date instanceof Date ? date : new Date(); // const day = String(inputDate.getDate()).padStart(2, '0'); const day = inputDate.getDate(); const month = inputDate.getMonth() + 1; const year = inputDate.getFullYear(); this.realDate = { day, month, year }; this.faerunMonth = FaerunDate.MONTH_NAMES[month - 1]; this.customFaerunYear = options.faerunYear; } static isLeapYear(year) { return year % 4 === 0; } getFestival() { const { day, month, year } = this.realDate; const leap = FaerunDate.isLeapYear(year); return FaerunDate.FESTIVALS.find(f => f.day === day && f.month === month && (!f.leapYearOnly || leap))?.name ?? null; } getSeason() { const m = this.realDate.month; return FaerunDate.SEASONS.find(season => season.months.includes(m))?.name ?? "Unknown"; } getWeekday() { const { day, month } = this.realDate; const dayOfYear = (month - 1) * 30 + day; return FaerunDate.WEEKDAYS[dayOfYear % 10]; } getMonth() { return this.faerunMonth; } getFaerunDateString() { const festival = this.getFestival(); const formattedDay = String(this.realDate.day).padStart(2, '0'); return festival ? `[Festival] ${festival}` : `${formattedDay} ${this.faerunMonth}`; } getFaerunYear() { return this.customFaerunYear ?? null; } getWeekOfYear() { const { day, month, year } = this.realDate; const leap = FaerunDate.isLeapYear(year); const daysFromMonths = (month - 1) * 30; const festivalsBefore = FaerunDate.FESTIVALS .filter(f => f.month < month || (f.month === month && parseInt(f.day) < day) ) .filter(f => !f.leapYearOnly || leap) .length; const dayOfYear = daysFromMonths + day + festivalsBefore; // Faerûn weeks are 10-day units (Tendays) return Math.floor((dayOfYear - 1) / 10) + 1; } toLocaleString() { const festival = this.getFestival(); const weekday = festival ? festival : this.getWeekday(); const yearPart = this.getFaerunYear() ? ` ${this.getFaerunYear()} DR` : ""; const week = this.getWeekOfYear(); const formattedDay = String(this.realDate.day).padStart(2, '0'); return `${weekday}, ${formattedDay} ${this.faerunMonth}${yearPart} – Season: ${this.getSeason()} – Week ${week}`; } static parse(dateString, options = {}) { const date = new Date(dateString); return new FaerunDate(date, options); } static toString(faerunDate) { return faerunDate.toLocaleString(); } } export default FaerunDate;