UNPKG

nhb-toolbox

Version:

A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.

296 lines (295 loc) 10.9 kB
var _a; import { isObjectWithKeys } from '../guards/non-primitives.js'; import { isInteger, isNonEmptyString, isNumber } from '../guards/primitives.js'; import { isDateString } from '../guards/specials.js'; import { banglaToDigit, digitToBangla } from '../number/convert.js'; import { BN_DAYS, BN_MONTH_TABLES, BN_MONTHS, BN_YEAR_OFFSET, MS_PER_DAY } from './constants.js'; import { _bnDaysMonthIdx, _extractDateUnits, _formatDateCore, _getBnSeason, _getBnYear, _isBnLeapYear, _padShunno, } from './helpers.js'; export class BanglaCalendar { variant; year; month; date; gregorian; weekDay; isoWeekDay; constructor(dateBnYrOrCfg, bnMonthOrCfg, bnDateOrCfg, config) { this.variant = this.#processVariants(dateBnYrOrCfg, bnMonthOrCfg, bnDateOrCfg, config); let date = dateBnYrOrCfg instanceof Date ? dateBnYrOrCfg : new Date(isDateString(dateBnYrOrCfg) && !_a.isBanglaDateString(dateBnYrOrCfg) ? dateBnYrOrCfg : isNumber(dateBnYrOrCfg) && !_a.isBanglaYearEn(dateBnYrOrCfg) ? dateBnYrOrCfg : Date.now()); if (Number.isNaN(date.getTime())) { date = new Date(); } const { year, month, monthDate } = this.#processDate(date); let bnYear = _a.isBanglaYear(dateBnYrOrCfg) ? banglaToDigit(dateBnYrOrCfg) : isNumber(dateBnYrOrCfg) && _a.isBanglaYearEn(dateBnYrOrCfg) ? dateBnYrOrCfg : year; let bnMonth = _a.isBanglaMonth(bnMonthOrCfg) ? banglaToDigit(bnMonthOrCfg) : _a.isBanglaMonthEn(bnMonthOrCfg) ? bnMonthOrCfg : month; let bnDate = _a.isBanglaDate(bnDateOrCfg) ? banglaToDigit(bnDateOrCfg) : _a.isBanglaDateEn(bnDateOrCfg) ? bnDateOrCfg : monthDate; if (_a.isBanglaDateString(dateBnYrOrCfg)) { const parts = dateBnYrOrCfg.replace(/['"]/g, '').split('-'); bnYear = banglaToDigit(parts[0]); bnMonth = banglaToDigit(parts[1]); bnDate = banglaToDigit(parts[2]); } const { gregYear } = this.#processGregYear(bnYear, bnMonth); const { bnMonthTable } = this.#getBnMonthTableLeap(gregYear, bnYear); const monthRange = bnMonthTable[bnMonth - 1]; if (bnDate > monthRange) { bnDate -= monthRange; if (bnMonth === 12) { bnMonth = 1; bnYear += 1; } else { bnMonth += 1; } } this.year = { bn: digitToBangla(bnYear), en: bnYear, }; this.month = { bn: digitToBangla(bnMonth), en: bnMonth, }; this.date = { bn: digitToBangla(bnDate), en: bnDate, }; const { gy, gm, gd, wd } = _extractDateUnits(this.toDate()); this.gregorian = { year: gy, month: gm, date: gd }; this.weekDay = wd; this.isoWeekDay = wd === 0 ? 7 : wd; } [Symbol.toPrimitive](hint) { if (hint === 'number') return this.valueOf(); return this.toJSON(); } get [Symbol.toStringTag]() { return this.toJSON(); } valueOf() { return this.toDate().getTime(); } toJSON() { const { year, month, date } = this; return `${_padShunno(year.bn, 4)}-${_padShunno(month.bn)}-${_padShunno(date.bn)}`; } isLeapYear() { const { gregYear } = this.#processGregYear(); return this.#getBnMonthTableLeap(gregYear).isBnLeapYear; } toDate() { const { baseGregYear, gregYear } = this.#processGregYear(); const { bnMonthTable } = this.#getBnMonthTableLeap(gregYear); const epoch = Date.UTC(baseGregYear, 3, 13); let days = this.date.en; for (let i = 0; i < this.month.en - 1; i++) { days += bnMonthTable[i]; } return new Date(days * MS_PER_DAY + epoch); } getSeasonName(locale) { return _getBnSeason(this.month.en - 1, locale); } getMonthName(locale) { const MONTH = BN_MONTHS[this.month.en - 1]; return (locale === 'en' ? MONTH.en : MONTH.bn); } getDayName(locale) { const DAY = BN_DAYS[this.weekDay]; return (locale === 'en' ? DAY.en : DAY.bn); } addDays(days) { const date = this.toDate(); return new _a(date.setDate(date.getDate() + days), { variant: this.variant, }); } addWeeks(weeks) { const date = this.toDate(); return new _a(date.setDate(date.getDate() + weeks * 7), { variant: this.variant, }); } addMonths(months, overflow = true) { if (overflow) { const current = this.toDate(); return new _a(current.setMonth(current.getMonth() + months), { variant: this.variant, }); } else { const { variant, year, month, date } = this; let targetMonth = month.en + months; let targetYear = year.en; while (targetMonth > 12) { targetMonth -= 12; targetYear += 1; } while (targetMonth < 1) { targetMonth += 12; targetYear -= 1; } return this.#getClampedBnCal(targetYear, targetMonth, date.en, variant); } } addYears(years, overflow = true) { const { variant, year, month, date } = this; const targetYear = year.en + years; if (overflow) { return new _a(targetYear, month.en, date.en, { variant }); } else { return this.#getClampedBnCal(targetYear, month.en, date.en, variant); } } startOfMonth() { const { year, month, variant } = this; return new _a(year.en, month.en, 1, { variant }); } endOfMonth() { const { year, month, variant } = this; return new _a(year.en, month.en, this.daysInMonth(), { variant }); } startOfYear() { const { year, variant } = this; return new _a(year.en, 1, 1, { variant }); } endOfYear() { const { year, variant } = this; return new _a(year.en, 12, 30, { variant }); } daysInMonth(month) { const { gregYear } = this.#processGregYear(); const { bnMonthTable } = this.#getBnMonthTableLeap(gregYear); return bnMonthTable[(month ?? this.month.en) - 1]; } toString() { return this.#toString('bn'); } toStringEn() { return this.#toString('en'); } format(format) { const { year, month, date, weekDay } = this; const seasonName = this.getSeasonName(); const M_NAME = BN_MONTHS[month.en - 1]; const D_NAME = BN_DAYS[weekDay]; const paddedYear = _padShunno(year.bn, 4); const dateComponents = { YYYY: paddedYear, YY: paddedYear.slice(-2), yyyy: paddedYear, yy: paddedYear.slice(-2), M: month.bn, MM: _padShunno(month.bn), mmm: M_NAME.short, mmmm: M_NAME.bn, d: D_NAME.short, dd: D_NAME.bn.replace('বার', ''), ddd: D_NAME.bn, D: date.bn, DD: _padShunno(date.bn), Do: date.bn, S: seasonName, SS: seasonName + 'কাল', }; return _formatDateCore(format || 'ddd, DD mmmm (SS), YYYY বঙ্গাব্দ', dateComponents); } #processGregYear(bnYear, bnMonth) { const baseGregYear = (bnYear ?? this.year.en) + BN_YEAR_OFFSET; const gregYear = (bnMonth ?? this.month.en) > 10 ? baseGregYear + 1 : baseGregYear; return { baseGregYear, gregYear }; } #getBnMonthTableLeap(gregYear, bnYear) { const isBnLeapYear = _isBnLeapYear(bnYear ?? this.year.en, gregYear, this.variant); const bnMonthTable = isBnLeapYear ? BN_MONTH_TABLES?.[this.variant].leap : BN_MONTH_TABLES?.[this.variant].normal; return { bnMonthTable, isBnLeapYear }; } #getClampedBnCal(tyBn, tmBn, cdBn, variant) { const { gregYear } = this.#processGregYear(tyBn, tmBn); const { bnMonthTable } = this.#getBnMonthTableLeap(gregYear, tyBn); const tdBn = Math.min(cdBn, bnMonthTable[tmBn - 1]); return new _a(tyBn, tmBn, tdBn, { variant }); } #processVariants(v1, v2, v3, v4) { return this.$hasVariantConfig(v1) ? v1.variant : this.$hasVariantConfig(v2) ? v2.variant : this.$hasVariantConfig(v3) ? v3.variant : this.$hasVariantConfig(v4) ? v4.variant : 'revised-2019'; } #processDate(date) { const bnYear = _getBnYear(date); const { days, monthIdx } = _bnDaysMonthIdx(date, this.variant); return { year: bnYear, month: (monthIdx + 1), monthDate: (days + 1), }; } #toString(lcl = 'bn') { const { year, date } = this; return `${this.getDayName(lcl)}, ${date[lcl]} ${this.getMonthName(lcl)}, ${year[lcl]} [${this.getSeasonName(lcl)}]`; } $hasVariantConfig(value) { return (isObjectWithKeys(value, ['variant']) && isNonEmptyString(value.variant) && (value.variant === 'revised-1966' || value.variant === 'revised-2019')); } static isBanglaYear(value) { return isNonEmptyString(value) && /^(?:০{0,3}[১-৯][০-৯]{0,3}|০)$/.test(value.trim()); } static isBanglaYearEn(value) { return isInteger(value) && value >= 0 && value <= 9999; } static isBanglaMonth(value) { return isNonEmptyString(value) && /^(?:০?[১-৯]|১০|১১|১২)$/.test(value.trim()); } static isBanglaMonthEn(value) { return isInteger(value) && value >= 1 && value <= 12; } static isBanglaDate(value) { return isNonEmptyString(value) && /^(?:০?[১-৯]|[১২][০-৯]|৩০|৩১)$/.test(value.trim()); } static isBanglaDateEn(value) { return isInteger(value) && value >= 1 && value <= 31; } static isBanglaDateString(value) { if (isNonEmptyString(value) && value.includes('-')) { const [year, month, date] = value.replace(/['"]/g, '').split('-'); return (_a.isBanglaYear(year) && _a.isBanglaMonth(month) && _a.isBanglaDate(date)); } return false; } } _a = BanglaCalendar; export { BanglaCalendar as BnCalendar, BanglaCalendar as Bongabdo };