class SmartDateFormat { constructor(format) { this._day = null; this._month = null; this._year = null; this.loadFormat(format); this._parseState = new SmartDateParseState(); } loadFormat(format) { let index = 0; let lowFormat = format.toLowerCase(); this._format = format; this._parts = []; while (index < format.length) { index = this._scanPart(index, format, lowFormat); } } _scanPart(index, format, lowFormat) { switch (lowFormat[index]) { case SmartDateFormat.DAY_ANCHOR: return this._scanDay(index, lowFormat); case SmartDateFormat.MONTH_ANCHOR: return this._scanMonth(index, lowFormat); case SmartDateFormat.YEAR_ANCHOR: return this._scanYear(index, lowFormat); } return this._scanStatic(index, format, lowFormat); } _scanDay(startIndex, lowFormat) { this._checkLastIsStatic(); this._day = new SmartDateDayPart(); this._parts.push(this._day); return this._avoidAnchor(SmartDateFormat.DAY_ANCHOR, startIndex, lowFormat); } _scanMonth(startIndex, lowFormat) { this._checkLastIsStatic(); this._month = new SmartDateMonthPart(); this._parts.push(this._month); return this._avoidAnchor(SmartDateFormat.MONTH_ANCHOR, startIndex, lowFormat); } _scanYear(startIndex, lowFormat) { this._checkLastIsStatic(); this._year = new SmartDateYearPart(); this._parts.push(this._year); return this._avoidAnchor(SmartDateFormat.YEAR_ANCHOR, startIndex, lowFormat); } _avoidAnchor(anchor, startIndex, lowFormat) { let endingIndex = startIndex; while (endingIndex < lowFormat.length && lowFormat[endingIndex] === anchor) { endingIndex++; } return endingIndex; } _checkLastIsStatic() { if (this._parts.length === 0) { return; } if (!this._parts[this._parts.length - 1].isStatic()) { throw new Error('Dynamic date parts must be separated by static substrings'); } } _scanStatic(startIndex, format, lowFormat) { let endingIndex = startIndex; while (endingIndex < format.length && this._isStaticAnchorSymbol(lowFormat[endingIndex])) { endingIndex++; } this._parts.push(new SmartDateStaticPart(format.substring(startIndex, endingIndex))); return endingIndex; } _isStaticAnchorSymbol(symbol) { return symbol !== SmartDateFormat.DAY_ANCHOR && symbol !== SmartDateFormat.MONTH_ANCHOR && symbol !== SmartDateFormat.YEAR_ANCHOR; } getPlaceHolder() { let placeHolder = ''; for (let i = 0; i < this._parts.length; i++) { placeHolder += this._parts[i].placeHolder(); } return placeHolder; } /** * @param {Date} date * @returns {String} */ formatDate(date) { var formattedDate = ''; for (let i = 0; i < this._parts.length; i++) { if (this._parts[i].isStatic()) { formattedDate += this._parts[i].placeHolder(); } else { formattedDate += this._parts[i].formatDate(date); } } return formattedDate; } parse(value, autocomplete) { this._resetParseState(); this._parseState.start(value); this._parseParts(autocomplete); this._correctDate(); } _resetParseState() { for (let i = 0; i < this._parts.length; i++) { this._parts[i].resetState(); } } _parseParts(autocomplete) { let index = 0; while (index < this._parts.length && (autocomplete || !this._parseState.isOver())) { this._parts[index].parse(this._parseState); if (!this._parts[index].isComplete()) { return; } index++; } } _correctDate() { if (!this._day.isComplete() || !this._month.isComplete()) { return; } this._day.setMaximalValue(this._getMonthSize(this._month.numericValue() - 1, !this._year.isComplete() || this._isLeaPYear(this._year.numericValue()))); } getParsedDate() { if (!this.isComplete()) { return null; } return new Date(this._year.numericValue(), this._month.numericValue() - 1, this._day.numericValue()); } _getMonthSize(monthIndex, isLeapYear) { if (monthIndex < 0 || monthIndex >= SmartDateMonthPart.MAXIMAL_VALUE) { return SmartDateMonthPart.MAXIMAL_VALUE; } if (monthIndex === 1 && isLeapYear) { // February return SmartDateFormat.BASIC_MONTH_SIZES[monthIndex] + 1; } return SmartDateFormat.BASIC_MONTH_SIZES[monthIndex]; } _isLeaPYear(year) { return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); } getCorrectedValue() { let index = 0; let value = ''; while (index < this._parts.length && !this._parts[index].isNoState()) { value += this._parts[index].cleanedValue(); index++; } return value; } isComplete() { return this._parts[this._parts.length - 1].isComplete(); } } SmartDateFormat.DAY_ANCHOR = 'd'; SmartDateFormat.DAY_PLACEHOLDER = 'ДД'; SmartDateFormat.MONTH_ANCHOR = 'm'; SmartDateFormat.MONTH_PLACEHOLDER = 'ММ'; SmartDateFormat.YEAR_ANCHOR = 'y'; SmartDateFormat.YEAR_PLACEHOLDER = 'ГГГГ'; SmartDateFormat.BASIC_MONTH_SIZES = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];