UNPKG

rpg-calendar

Version:

Low level library for working with RPG/Fantasy dates

230 lines 20.4 kB
import { isLeapYearBuilder, getDaysInYearBuilder, getDaysInMonthBuilder, getDaysInWeekBuilder, getYearNameBuilder, getPrevMonthYearBuilder, getNextMonthYearBuilder, getExtraDayBuilder, getNextYearBuilder, getPrevYearBuilder } from './lib'; import { getTimeString } from './lib/time'; export class RPGCalendar { config; // Utility functions isLeapYear; getDaysInYear; getDaysInMonth; getDaysInWeek; getYearName; getDayName; getMonthName; getConfigMonth; getWeekDays; getNextMonthYear; getPrevMonthYear; getNextYear; getPrevYear; getExtraDay; constructor(config) { this.config = config; const { yearNameMap = {} } = config; this.isLeapYear = isLeapYearBuilder(config?.leapYearInterval || 0, config?.hasYear0); this.getDaysInYear = getDaysInYearBuilder(config.months, this.isLeapYear); this.getDaysInMonth = getDaysInMonthBuilder(config.months, this.isLeapYear); this.getDaysInWeek = getDaysInWeekBuilder(config.weekdays); this.getYearName = getYearNameBuilder(yearNameMap); this.getWeekDays = () => this.config.weekdays; this.getDayName = (dayOfWeek) => this.config.weekdays?.[dayOfWeek - 1]?.name || 'Unknown'; this.getMonthName = (month) => this.config.months?.[month - 1]?.name || 'Unknown'; this.getConfigMonth = (month) => this.config.months[month - 1]; this.getPrevMonthYear = getPrevMonthYearBuilder(config?.hasYear0, this.config.months); this.getNextMonthYear = getNextMonthYearBuilder(config?.hasYear0, this.config.months); this.getPrevYear = getPrevYearBuilder(config?.hasYear0); this.getNextYear = getNextYearBuilder(config?.hasYear0); this.getExtraDay = getExtraDayBuilder(this.config.months, this.isLeapYear); } // dateStringToRPGDate accepts the date in a more readable format, parses it and returns an RPGCalendarDate object. // dateString resembles the ISO 8601 format but without the fractional seconds: YYYY-MM-DD hh:mm:ss dateStringToRPGDate(dateString) { const dateAndTime = dateString.split(' '); if (dateAndTime.length !== 2) { throw new Error(`${dateString} is not a valid date time string format`); } const dateParts = dateAndTime[0].split('-'); if (dateParts.length !== 3) { throw new Error(`${dateString} does not contain a valid date part`); } const timeParts = dateAndTime[1].split(':'); if (timeParts.length !== 3) { throw new Error(`${dateString} does not contain a valid time part`); } // Assign known values const time = { hour: parseInt(timeParts[0]), minute: parseInt(timeParts[1]), second: parseInt(timeParts[2]) }; const year = parseInt(dateParts[0]); const monthOfYear = parseInt(dateParts[1]); const dayOfMonth = parseInt(dateParts[2]); // Calculate day of week const daysInWeek = this.getDaysInWeek(); const dayMod = dayOfMonth % daysInWeek; const dayOfWeek = dayMod === 0 ? dayOfMonth / daysInWeek : dayMod; return { time, year, dayOfMonth, monthOfYear, dayOfWeek, dayName: this.getDayName(dayOfWeek), inLeapYear: this.isLeapYear(year), monthName: this.getMonthName(monthOfYear), yearName: this.getYearName(year) }; } // epochToDate accepts both a simple day epoch (number of days) or a complex epoch (number of days with the time) epochToDate(epoch) { let epochDay; let time = { hour: 0, minute: 0, second: 0 }; if (typeof epoch === 'string') { const dateParts = epoch.split('-'); if (dateParts.length !== 2) { throw new Error(`${epoch} is not a valid date time epoch format`); } const timeParts = dateParts[1].split(':'); if (timeParts.length !== 3) { throw new Error(`${epoch} is not a valid time format`); } time = { hour: parseInt(timeParts[0]), minute: parseInt(timeParts[1]), second: parseInt(timeParts[2]) }; epochDay = parseInt(dateParts[0]); } else { epochDay = epoch; } // Calculate the year let year = 0; let dayOfYear = epochDay; while (dayOfYear >= this.getDaysInYear(year)) { dayOfYear = dayOfYear - this.getDaysInYear(year); year++; } // Calculate the month of the year let monthOfYear = 1; let dayOfMonth = dayOfYear; while (dayOfMonth > this.getDaysInMonth(monthOfYear, year)) { dayOfMonth = dayOfMonth - this.getDaysInMonth(monthOfYear, year); monthOfYear++; } // Calculate day of week const daysInWeek = this.getDaysInWeek(); const dayMod = dayOfMonth % daysInWeek; const dayOfWeek = dayMod === 0 ? dayOfMonth / daysInWeek : dayMod; const epochDayTime = `${epochDay}-${getTimeString(time)}`; return { year, epochDay, epochDayTime, monthOfYear, dayOfMonth, dayOfYear, dayOfWeek, dayName: this.getDayName(dayOfWeek), inLeapYear: this.isLeapYear(year), monthName: this.getMonthName(monthOfYear), yearName: this.getYearName(year), time }; } // createDate is a simple interface that lets you construct a date object. Only the year is required, everything else // defaults (first month, first day, and 00:00:00) createDate(year, month = 1, day = 1, hour = 0, minute = 0, second = 0) { const startYear = this.config?.hasYear0 ? 0 : 1; // Count the days up to the year let epochDay = 0; for (let y = startYear; y < year; y++) { epochDay += this.getDaysInYear(y); } // Count the days up to the month let dayOfYear = 0; for (let m = 1; m < month; m++) { epochDay += this.getDaysInMonth(m, year); } // Add in the days epochDay += day; dayOfYear += day; // Calculate day of week const daysInWeek = this.getDaysInWeek(); const dayMod = day % daysInWeek; const dayOfWeek = dayMod === 0 ? day / daysInWeek : dayMod; // Setup time const time = { hour, minute, second }; const epochDayTime = `${epochDay}-${getTimeString(time)}`; return { year, epochDay, epochDayTime, monthOfYear: month, dayOfMonth: day, dayOfYear, dayOfWeek, dayName: this.getDayName(dayOfWeek), inLeapYear: this.isLeapYear(year), monthName: this.getMonthName(month), yearName: this.getYearName(year), time, extraDay: this.getExtraDay(year, month, day) }; } // getDisplayMonth returns a month object based on the month and year getDisplayMonth(mq) { const { year, month } = mq; // Get the month as it's defined in the configuration const configMonth = this.getConfigMonth(month); // Get the first day of the month so that we can pull off all the information that pertains to the entire month. const firstDayOfMonth = this.createDate(year, month, 1); const { yearName } = firstDayOfMonth; const daysInMonth = this.getDaysInMonth(month, year); const daysInWeek = this.getDaysInWeek(); const weeks = []; for (let d = 1; d <= daysInMonth; d++) { const w = Math.floor((d - 1) / daysInWeek); if (!weeks?.[w]) { weeks.push([]); } weeks[w].push(this.createDate(year, month, d)); } return { ...configMonth, weeks, year, yearName, monthOfYear: month, weekdays: this.getWeekDays(), nextMonthQuery: this.getNextMonthYear({ year, month }), prevMonthQuery: this.getPrevMonthYear({ year, month }), nextYearQuery: this.getNextYear({ year, month }), prevYearQuery: this.getPrevYear({ year, month }) }; } // getMonths returns all the months in a year. Useful when displaying a dropdown. getMonths() { return this.config.months; } // getDaySpanFromDate returns a RPGDateSpan with the min and max (start/end) times for the given day. This is useful // when creating queries or defining an event that lasted for an entire day. getDaySpanFromDate(date) { const eh = this.config.hoursInDay - 1; const em = this.config.minutesInHour - 1; const es = this.config.secondsInMinutes - 1; return { start: this.createDate(date.year, date.monthOfYear, date.dayOfMonth), end: this.createDate(date.year, date.monthOfYear, date.dayOfMonth, eh, em, es) }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUlBHQ2FsZW5kYXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvUlBHQ2FsZW5kYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBV0EsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixvQkFBb0IsRUFDcEIscUJBQXFCLEVBQ3JCLG9CQUFvQixFQUNwQixrQkFBa0IsRUFDbEIsdUJBQXVCLEVBQ3ZCLHVCQUF1QixFQUN2QixrQkFBa0IsRUFDbEIsa0JBQWtCLEVBQ2xCLGtCQUFrQixFQUNuQixNQUFNLE9BQU8sQ0FBQztBQUNmLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFM0MsTUFBTSxPQUFPLFdBQVc7SUFpQkY7SUFoQnBCLG9CQUFvQjtJQUNaLFVBQVUsQ0FBNEI7SUFDdEMsYUFBYSxDQUEyQjtJQUN4QyxjQUFjLENBQTBDO0lBQ3hELGFBQWEsQ0FBZTtJQUM1QixXQUFXLENBQTJCO0lBQ3RDLFVBQVUsQ0FBZ0M7SUFDMUMsWUFBWSxDQUE0QjtJQUN4QyxjQUFjLENBQXNDO0lBQ3BELFdBQVcsQ0FBNkI7SUFDeEMsZ0JBQWdCLENBQStEO0lBQy9FLGdCQUFnQixDQUErRDtJQUMvRSxXQUFXLENBQStEO0lBQzFFLFdBQVcsQ0FBK0Q7SUFDMUUsV0FBVyxDQUFnRjtJQUVuRyxZQUFvQixNQUF5QjtRQUF6QixXQUFNLEdBQU4sTUFBTSxDQUFtQjtRQUMzQyxNQUFNLEVBQUUsV0FBVyxHQUFHLEVBQUUsRUFBRSxHQUFHLE1BQU0sQ0FBQztRQUVwQyxJQUFJLENBQUMsVUFBVSxHQUFHLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxnQkFBZ0IsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ3JGLElBQUksQ0FBQyxhQUFhLEdBQUcsb0JBQW9CLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDMUUsSUFBSSxDQUFDLGNBQWMsR0FBRyxxQkFB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