UNPKG

qenjs.js

Version:

A library to convert and format Ethiopian and Gregorian dates

503 lines (436 loc) 13.4 kB
const GregorianDateFormatter = require("./GregorianDateFormatter"); const dateUtils = require("./gregorian-date-diff-utils"); class GregorianDate { $d; $y; $M; $D; $W; $H; $m; $s; $ms; $DWM; $DWY; $isGregorianDateObject = true; constructor(input) { const setToNaN = (obj) => { obj.$y = NaN; obj.$M = NaN; obj.$D = NaN; obj.$W = NaN; obj.$H = NaN; obj.$m = NaN; obj.$s = NaN; obj.$ms = NaN; obj.$DWM = NaN; obj.$DWY = NaN; obj.$d = new Date(NaN); }; try { if (input instanceof Date) { this.$d = input; this.$y = input.getFullYear(); this.$M = input.getMonth(); this.$D = input.getDate(); this.$W = input.getDay(); this.$H = input.getHours(); this.$m = input.getMinutes(); this.$s = input.getSeconds(); this.$ms = input.getMilliseconds(); this.$DWM = this.getWeekOfMonth(); this.$DWY = this.getWeekOfYear(); } else if (input && typeof input === "object" && input.year) { this.$y = input.year; this.$M = input.month; this.$D = input.day; this.$H = input.hours; this.$m = input.minutes; this.$s = input.seconds; this.$ms = input.milliseconds; this.$d = this.getGregorianDateTime(); this.$W = this.$d.getDay(); this.$DWM = this.getWeekOfMonth(); this.$DWY = this.getWeekOfYear(); } else { throw new Error("Invalid Date"); } } catch (error) { setToNaN(this); } } get Year() { return this.$y; } get Month() { return this.$M; } get Day() { return this.$D; } get Hours() { return this.$H; } get Minutes() { return this.$m; } get Seconds() { return this.$s; } get Milliseconds() { return this.$ms; } get DayOfWeek() { return this.$W; // 0 to 6 (Sunday to Saturday) } get DateTime() { return new Date(this.$d); } get getDayWeekInMonth() { return this.getWeekOfMonth(); } get getDayWeekInYear() { return this.getWeekOfYear(); } // getWeekOfMonth() { // return Math.ceil(this.$D / 7); // } getWeekOfMonth() { const firstDayOfMonth = new Date(this.$y, this.$M, 1); const firstDayOfWeek = firstDayOfMonth.getDay(); // 0 (Sunday) to 6 (Saturday) const offset = (this.$D + firstDayOfWeek - 1) / 7; return Math.ceil(offset); } getWeekOfYear() { const startDate = new Date(this.$y, 0, 1); const diff = this.$d - startDate; const days = Math.floor(diff / (1000 * 60 * 60 * 24)); return Math.ceil((days + 1) / 7); } getGregorianDateTime() { const datetime = new Date(this.$y, this.$M, this.$D); datetime.setHours(this.$H, this.$m, this.$s, this.$ms); return datetime; } static diff(date1, date2, unit = "") { date1 = date1 instanceof GregorianDate ? date1.$d : date1; date2 = date2 instanceof GregorianDate ? date2.$d : date2; return dateUtils.difference(date1, date2, unit); } static diffString(date1, date2, unit) { const result = GregorianDate.diff(date1, date2, "all"); if (typeof result === "string") { return result; } const timeUnitMapping = { year: result.full, month: result.byMonths, week: result.byWeeks, }; if (timeUnitMapping[unit]) { return dateUtils.formatTimeParts(timeUnitMapping[unit]); } return result.full ? dateUtils.formatTimeParts(result.full) : result; } fromNow(withoutSuffix) { return dateUtils.toRelativeTime(this.$d, new Date(), withoutSuffix); } from(date, withoutSuffix) { date = date instanceof GregorianDate ? date.$d : date; return dateUtils.toRelativeTime(this.$d, date, withoutSuffix); } to(date, withoutSuffix) { date = date instanceof GregorianDate ? date.$d : date; return dateUtils.toRelativeTime(date, this.$d, withoutSuffix); } toNow(withoutSuffix) { return dateUtils.toRelativeTime(new Date(), this.$d, withoutSuffix); } // Add / Subtract Years, Months, Days addYears(years) { const date = { year: this.$y + years, month: this.$M, day: this.$D, hours: this.$H, minutes: this.$m, seconds: this.$s, milliseconds: this.$ms, }; return new GregorianDate(date); } addMonths(months) { let newMonth = this.$M + months; let newYear = this.$y; while (newMonth > 12) { newYear += Math.floor(newMonth / 12); newMonth = newMonth % 12; } const date = { year: newYear, month: newMonth, day: this.$D, hours: this.$H, minutes: this.$m, seconds: this.$s, milliseconds: this.$ms, }; return new GregorianDate(date); } addDays(days) { const gregorianDate = this.$d; gregorianDate.setDate(gregorianDate.getDate() + days); return new GregorianDate(gregorianDate); } addHours(hours) { const gregorianDate = this.$d; gregorianDate.setHours(gregorianDate.getHours() + hours); return new GregorianDate(gregorianDate); } addMinutes(minutes) { const gregorianDate = this.$d; gregorianDate.setMinutes(gregorianDate.getMinutes() + minutes); return new GregorianDate(gregorianDate); } addSeconds(seconds) { const gregorianDate = this.$d; gregorianDate.setSeconds(gregorianDate.getSeconds() + seconds); return new GregorianDate(gregorianDate); } addMilliseconds(milliseconds) { const gregorianDate = this.$d; gregorianDate.setMilliseconds( gregorianDate.getMilliseconds() + milliseconds ); return new GregorianDate(gregorianDate); } add(amount, unit) { if (!Number.isInteger(amount)) { return "Invalid amount"; } const normalizedUnit = unit?.toLowerCase().replace(/s$/, ""); const unitActions = { day: this.addDays, month: this.addMonths, year: this.addYears, hour: this.addHours, minute: this.addMinutes, second: this.addSeconds, millisecond: this.addMilliseconds, }; const action = unitActions[normalizedUnit]; if (action) { return action.call(this, amount); } else { return "Invalid Unit"; } } subtractYears(years) { return this.addYears(-years); } subtractMonths(months) { return this.addMonths(-months); } subtractDays(days) { return this.addDays(-days); } subtractHours(hours) { return this.addHours(-hours); } subtractMinutes(minutes) { return this.addMinutes(-minutes); } subtractSeconds(seconds) { return this.addSeconds(-seconds); } subtract(amount, unit) { return this.add(-amount, unit); } // Start of the day (00:00:00.000) startOfDay() { const startOfDayDate = new Date(this.$d); startOfDayDate.setHours(0, 0, 0, 0); return new GregorianDate(startOfDayDate); } // End of the day (23:59:59.999) endOfDay() { const endOfDayDate = new Date(this.$d); endOfDayDate.setHours(23, 59, 59, 999); return new GregorianDate(endOfDayDate); } _getTimestamp(date) { if (date instanceof Date) { return date.getTime(); } else if (date instanceof GregorianDate) { return date.$d.getTime(); } else { return null; // Indicates invalid date } } // Comparison Methods isBefore(date) { const compareTimestamp = this._getTimestamp(date); if (compareTimestamp === null) return false; return this.$d.getTime() < compareTimestamp; } isAfter(date) { const compareTimestamp = this._getTimestamp(date); if (compareTimestamp === null) return false; return this.$d.getTime() > compareTimestamp; } isSame(date) { const compareTimestamp = this._getTimestamp(date); if (compareTimestamp === null) return false; return this.$d.getTime() === compareTimestamp; } isToday() { const today = new Date(); return ( this.$y === today.getFullYear() && this.$M === today.getMonth() && this.$D === today.getDate() ); } isBetween(startDate, endDate) { const startTimestamp = this._getTimestamp(startDate); const endTimestamp = this._getTimestamp(endDate); if (startTimestamp === null || endTimestamp === null) return false; return ( this.$d.getTime() > startTimestamp && this.$d.getTime() < endTimestamp ); } // Format Date (to simple string format) toString(format = "dd/MM/YYYY") { return GregorianDateFormatter.format(this, format); } format(template) { return GregorianDateFormatter.format(this, template); } toTimezone(timezone) { const dateTime = DateTime.fromJSDate(this.$d).setZone(timezone); return new GregorianDate(dateTime.toJSDate()); } toUTC() { const dateTime = DateTime.fromJSDate(this.$d).toUTC(); return new GregorianDate(dateTime.toJSDate()); } toLocaleString(locale, options = {}) { return new Intl.DateTimeFormat(locale, options).format(this.$d); } getLocalizedMonth(locale) { return new Intl.DateTimeFormat(locale, { month: "long" }).format(this.$d); } getLocalizedWeekday(locale) { return new Intl.DateTimeFormat(locale, { weekday: "long" }).format(this.$d); } isValid() { return !isNaN(this.$d.getTime()); } isLeapYear() { return (this.$y % 4 === 0 && this.$y % 100 !== 0) || this.$y % 400 === 0; } toRelativeTime(referenceDate = new Date()) { const diffInMs = referenceDate - this.$d; const isFuture = diffInMs < 0; const absDiffInMs = Math.abs(diffInMs); const MS_PER_SECOND = 1000; const MS_PER_MINUTE = MS_PER_SECOND * 60; const MS_PER_HOUR = MS_PER_MINUTE * 60; const MS_PER_DAY = MS_PER_HOUR * 24; const MS_PER_MONTH = MS_PER_DAY * 30.44; const MS_PER_YEAR = MS_PER_DAY * 365.25; const years = Math.floor(absDiffInMs / MS_PER_YEAR); const months = Math.floor(absDiffInMs / MS_PER_MONTH); const days = Math.floor(absDiffInMs / MS_PER_DAY); const hours = Math.floor(absDiffInMs / MS_PER_HOUR); const minutes = Math.floor(absDiffInMs / MS_PER_MINUTE); const seconds = Math.floor(absDiffInMs / MS_PER_SECOND); if (years > 0) { return isFuture ? `in ${years} year${years > 1 ? "s" : ""}` : `${years} year${years > 1 ? "s" : ""} ago`; } else if (months > 0) { return isFuture ? `in ${months} month${months > 1 ? "s" : ""}` : `${months} month${months > 1 ? "s" : ""} ago`; } else if (days > 0) { return isFuture ? `in ${days} day${days > 1 ? "s" : ""}` : `${days} day${days > 1 ? "s" : ""} ago`; } else if (hours > 0) { return isFuture ? `in ${hours} hour${hours > 1 ? "s" : ""}` : `${hours} hour${hours > 1 ? "s" : ""} ago`; } else if (minutes > 0) { return isFuture ? `in ${minutes} minute${minutes > 1 ? "s" : ""}` : `${minutes} minute${minutes > 1 ? "s" : ""} ago`; } else { return isFuture ? `in ${seconds} second${seconds > 1 ? "s" : ""}` : `${seconds} second${seconds > 1 ? "s" : ""} ago`; } } fromNow() { return this.toRelativeTime(new Date()); } static now() { return new GregorianDate(new Date()); } toISOString() { return this.$d.toISOString(); } toJSON() { return this.toISOString(); } clone() { return new GregorianDate(this.$d); } startOf(unit) { const normalizedUnit = unit.toLowerCase().replace(/s$/, ""); switch (normalizedUnit) { case "year": return new GregorianDate(new Date(this.$y, 0, 1)); case "month": return new GregorianDate(new Date(this.$y, this.$M, 1)); case "day": return this.startOfDay(); default: throw new Error(`Invalid unit: ${unit}`); } } endOf(unit) { const normalizedUnit = unit.toLowerCase().replace(/s$/, ""); switch (normalizedUnit) { case "year": return new GregorianDate(new Date(this.$y, 11, 31, 23, 59, 59, 999)); case "month": return new GregorianDate( new Date(this.$y, this.$M + 1, 0, 23, 59, 59, 999) ); case "day": return this.endOfDay(); default: throw new Error(`Invalid unit: ${unit}`); } } getQuarter() { return Math.ceil((this.$M + 1) / 3); } startOfQuarter() { const quarterStartMonth = Math.floor(this.$M / 3) * 3; return new GregorianDate(new Date(this.$y, quarterStartMonth, 1)); } endOfQuarter() { const quarterEndMonth = Math.floor(this.$M / 3) * 3 + 2; return new GregorianDate( new Date(this.$y, quarterEndMonth + 1, 0, 23, 59, 59, 999) ); } isDST() { const jan = new Date(this.$y, 0, 1).getTimezoneOffset(); const jul = new Date(this.$y, 6, 1).getTimezoneOffset(); return Math.max(jan, jul) !== this.$d.getTimezoneOffset(); } } module.exports = GregorianDate;