retail-calendar
Version:
A configurable retail calendar
202 lines (201 loc) • 10.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var types_1 = require("./types");
var calendar_month_1 = require("./calendar_month");
var calendar_week_1 = require("./calendar_week");
var last_day_before_eom_1 = require("./last_day_before_eom");
var last_day_nearest_eom_1 = require("./last_day_nearest_eom");
var first_bow_of_first_month_1 = require("./first_bow_of_first_month");
var last_day_before_eom_except_leap_year_1 = require("./last_day_before_eom_except_leap_year");
var date_utils_1 = require("./date_utils");
var memoization_1 = require("./utils/memoization");
var penultimate_day_of_week_nearest_eom_1 = require("./penultimate_day_of_week_nearest_eom");
var custom_leap_year_1 = require("./custom_leap_year");
var buildRetailCalendarFactory = memoization_1.memoize(function (retailCalendarOptions, year) {
return new exports.RetailCalendarFactory(retailCalendarOptions, year);
}, function (retailCalendarOptions, year) {
return memoization_1.createMemoizationKeyFromCalendarOptionsAndYear(retailCalendarOptions, year);
});
exports.RetailCalendarFactory = /** @class */ (function () {
function Calendar(calendarOptions, year) {
var _a;
this.year = year;
this.options = calendarOptions;
this.calendarYear = this.getAdjustedGregorianYear(year);
this.addLeapWeekToMonth = (_a = this.options.addLeapWeekToMonth) !== null && _a !== void 0 ? _a : -1;
this.numberOfWeeks = this.calculateNumberOfWeeks();
this.lastDayOfYear = this.calculateLastDayOfYear(this.calendarYear, this.year);
this.firstDayOfYear = date_utils_1.startOfDay(date_utils_1.addDaysToDate(date_utils_1.addWeeksToDate(this.lastDayOfYear, -this.numberOfWeeks), 1));
this.weeks = this.generateWeeks();
this.months = this.generateMonths();
this.days = this.generateDays();
}
Calendar.getRetailCalendar = function (retailCalendarOptions, year) {
return buildRetailCalendarFactory(retailCalendarOptions, year);
};
Calendar.prototype.generateMonths = function () {
var months = [];
var beginningIndex = this.getBeginningOfMonthIndex();
var index = beginningIndex;
for (var _i = 0, _a = this.getWeekDistribution(); _i < _a.length; _i++) {
var numberOfWeeks = _a[_i];
var quarterOfYear = Math.floor((index - beginningIndex) / 3) + 1;
var weeksOfMonth = this.weeks.filter(function (week) { return week.monthOfYear === index; });
var monthStart = new Date(weeksOfMonth[0].gregorianStartDate);
var monthEnd = new Date(weeksOfMonth[weeksOfMonth.length - 1].gregorianEndDate);
months.push(new calendar_month_1.CalendarMonth(index, quarterOfYear, numberOfWeeks, weeksOfMonth, monthStart, monthEnd));
index += 1;
}
return months;
};
Calendar.prototype.generateWeeks = function () {
var weeks = [];
for (var index = 0; index < this.numberOfWeeks; index++) {
var weekIndex = index;
var _a = this.getMonthAndWeekOfMonthOfWeek(weekIndex), monthOfYear = _a[0], weekOfMonth = _a[1], weekOfQuarter = _a[2], quarterOfYear = _a[3];
var start = date_utils_1.addWeeksToDate(this.firstDayOfYear, index);
var end = date_utils_1.endOfDay(date_utils_1.addDaysToDate(date_utils_1.addWeeksToDate(start, 1), -1));
weeks.push(new calendar_week_1.CalendarWeek(weekIndex, weekOfMonth, weekOfQuarter, monthOfYear, quarterOfYear, start, end));
}
return weeks;
};
Calendar.prototype.generateDays = function () {
var _this = this;
var days = [];
var DAYS_IN_WEEK = 7;
var dayOfYear = 1;
this.weeks.forEach(function (week) {
for (var dayIndex = 1; dayIndex < DAYS_IN_WEEK + 1; dayIndex++) {
var gregorianStartDate = date_utils_1.addDaysToDate(week.gregorianStartDate, dayIndex - 1);
var gregorianEndDate = date_utils_1.endOfDay(gregorianStartDate);
var gregorianMonthOfYear = gregorianStartDate.getMonth() + 1; // JS Date is 0 indexed
var gregorianDayOfYear = date_utils_1.getDayOfYear(gregorianStartDate);
var gregorianDayOfMonth = gregorianStartDate.getDate();
var isLeapWeek = _this.isLeapWeek(week.weekOfYear);
days.push({
dayOfYear: dayOfYear,
dayOfWeek: dayIndex,
dayOfMonth: isLeapWeek ? -1 : week.weekOfMonth * 7 + dayIndex,
weekOfYear: week.weekOfYear,
monthOfYear: isLeapWeek ? -1 : week.monthOfYear,
gregorianStartDate: gregorianStartDate,
gregorianEndDate: gregorianEndDate,
gregorianMonthOfYear: gregorianMonthOfYear,
gregorianDayOfYear: gregorianDayOfYear,
gregorianDayOfMonth: gregorianDayOfMonth,
});
dayOfYear += 1;
}
});
return days;
};
Calendar.prototype.isLeapWeek = function (weekIndex) {
if (weekIndex !== 52) {
return false;
}
// If addLeapWeekToMonth is greater than zero, then that month has one additional week.
// As a result, the 52nd week is not a leap week.
return this.addLeapWeekToMonth === -1;
};
Calendar.prototype.getMonthAndWeekOfMonthOfWeek = function (weekIndex) {
var weekDistribution = this.getWeekDistribution();
var monthOffset = this.getBeginningOfMonthIndex();
var weekCount = 0;
var monthOfYear = 0;
var weekInQuarter = 0;
var quarterOfYear = 0;
for (var monthIndex = 0; monthIndex < 12; monthIndex++) {
var weeksInMonth = weekDistribution[monthIndex];
monthOfYear = monthIndex + monthOffset;
if (monthIndex % 3 === 0) {
weekInQuarter = 0;
quarterOfYear = Math.floor(monthIndex / 3) + 1;
}
for (var weekInMonth = 0; weekInMonth < weeksInMonth; weekInMonth++) {
if (weekIndex === weekCount) {
return [monthOfYear, weekInMonth, weekInQuarter, quarterOfYear];
}
weekCount++;
weekInQuarter++;
}
}
return [-1, -1, -1, -1];
};
Calendar.prototype.getBeginningOfMonthIndex = function () {
var optionsIndex = this.options.beginningMonthIndex;
if (optionsIndex !== undefined && optionsIndex !== null) {
return optionsIndex;
}
else {
return 1;
}
};
Calendar.prototype.getWeekDistribution = function () {
var weekDistribution;
switch (this.options.weekGrouping) {
case types_1.WeekGrouping.Group445:
weekDistribution = [4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5];
break;
case types_1.WeekGrouping.Group454:
weekDistribution = [4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4];
break;
case types_1.WeekGrouping.Group544:
weekDistribution = [5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4];
break;
}
if (this.options.addLeapWeekToMonth !== undefined &&
this.options.addLeapWeekToMonth >= 0 &&
this.numberOfWeeks === 53)
weekDistribution[this.options.addLeapWeekToMonth]++;
return weekDistribution;
};
Calendar.prototype.calculateLastDayOfYear = function (year, retailCalendarYear) {
var firstDayOfLastMonthOfYear = date_utils_1.newSafeDate();
firstDayOfLastMonthOfYear.setFullYear(year);
firstDayOfLastMonthOfYear.setMonth(this.options.lastMonthOfYear, 1);
var lastDayOfYear = date_utils_1.endOfMonth(firstDayOfLastMonthOfYear);
var lastIsoWeekDay = this.options.lastDayOfWeek;
var weekCalculation = this.getWeekCalculationStrategy(this.options.weekCalculation);
return weekCalculation.getLastDayForGregorianLastDay(lastDayOfYear, lastIsoWeekDay, retailCalendarYear);
};
Calendar.prototype.calculateNumberOfWeeks = function () {
// Make sure we get whole day difference
// by measuring from the end of current year to start of last year
var lastDayOfYear = date_utils_1.endOfDay(this.calculateLastDayOfYear(this.calendarYear, this.year));
var lastDayOfLastYear = date_utils_1.startOfDay(this.calculateLastDayOfYear(this.calendarYear - 1, this.year - 1));
var numWeeks = date_utils_1.getWeekDifference(lastDayOfYear, lastDayOfLastYear);
return numWeeks;
};
Calendar.prototype.getWeekCalculationStrategy = function (weekCalculation) {
switch (weekCalculation) {
case types_1.WeekCalculation.LastDayBeforeEOM:
return new last_day_before_eom_1.LastDayBeforeEOMStrategy();
case types_1.WeekCalculation.LastDayBeforeEomExceptLeapYear:
return new last_day_before_eom_except_leap_year_1.LastDayBeforeEOMExceptLeapYearStrategy();
case types_1.WeekCalculation.LastDayNearestEOM:
return new last_day_nearest_eom_1.LastDayNearestEOMStrategy();
case types_1.WeekCalculation.FirstBOWOfFirstMonth:
return new first_bow_of_first_month_1.FirstBOWOfFirstMonth();
case types_1.WeekCalculation.PenultimateDayOfWeekNearestEOM:
return new penultimate_day_of_week_nearest_eom_1.PenultimateDayOfWeekNearestEOMStrategy();
case types_1.WeekCalculation.CustomLeapYear: {
var _a = this.options, leapYear = _a.leapYear, leapYearEndDate = _a.leapYearEndDate, leapYearFrequency = _a.leapYearFrequency;
if (leapYear === undefined ||
leapYearEndDate === undefined ||
leapYearFrequency === undefined) {
throw new Error('CustomLeapYear week calculation requires leapYear, leapYearEndDate, and leapYearFrequency to be defined');
}
return new custom_leap_year_1.CustomLeapYearStrategy(leapYear, leapYearEndDate, leapYearFrequency);
}
}
};
Calendar.prototype.getAdjustedGregorianYear = function (year) {
if (this.options.lastMonthOfYear !== types_1.LastMonthOfYear.December) {
return year + 1;
}
else {
return year;
}
};
return Calendar;
}());