@devexpress/utils
Version:
DevExpress utils
522 lines (521 loc) • 20 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DateFormatter = void 0;
var string_1 = require("../utils/map/string");
var string_2 = require("../utils/string");
var date_utils_1 = require("./date-utils");
var DateFormatter = (function () {
function DateFormatter(options) {
this.date = new Date(2000, 0, 1);
this.mask = '';
this.specifiers = {};
this.spPositions = [];
this.parserKeys = [];
this.savedYear = -1;
this.isYearParsed = false;
this.parsedMonth = -1;
this.knownSpecifiers = ['d', 'M', 'y', 'H', 'h', 'm', 's', 'f', 'F', 'g', 't'];
this.replacers = {
'd': this.replaceDay,
'M': this.replaceMonth,
'y': this.replaceYear,
'H': this.replaceHours23,
'h': this.replaceHours12,
'm': this.replaceMinutes,
's': this.replaceSeconds,
'F': this.replaceMsTrimmed,
'f': this.replaceMs,
'g': this.replaceEra,
't': this.replaceAmPm
};
this.parsers = {
'd': this.parseDay,
'M': this.parseMonth,
'y': this.parseYear,
'H': this.parseHours,
'h': this.parseHours,
'm': this.parseMinutes,
's': this.parseSeconds,
'F': this.parseMs,
'f': this.parseMs,
'g': this.parseEra,
't': this.parseAmPm
};
this.options = options;
}
DateFormatter.prototype.setFormatString = function (mask) {
if (mask.length === 2 && mask.charAt(0) === '%')
mask = mask.charAt(1);
var stringContainsDateSeparator = !!mask && (mask.indexOf(this.options.ds) !== -1);
this.specifiers = {};
this.spPositions = [];
this.mask = '';
var subt = 0;
var startPos = 0;
var skip = false;
var backslash = false;
var sp = '';
var prevCh = '';
for (var pos = 0; true; pos++) {
var ch = mask.charAt(pos);
if (ch === '') {
if (sp.length > 0)
this.registerSpecifier(startPos, sp, stringContainsDateSeparator);
break;
}
if (ch === '\\' && !backslash) {
backslash = true;
subt++;
}
else {
if (!backslash && (ch === '\'' || ch === '"')) {
skip = !skip;
subt++;
}
else {
if (!skip) {
if (ch === '/')
ch = this.options.ds;
else if (ch === ':')
ch = this.options.ts;
else if (this.isKnownSpecifier(ch)) {
if (prevCh.length === 0)
prevCh = ch;
if (ch === prevCh)
sp += ch;
else {
if (sp.length > 0)
this.registerSpecifier(startPos, sp, stringContainsDateSeparator);
sp = ch;
startPos = pos - subt;
}
}
}
this.mask += ch;
}
backslash = false;
}
prevCh = ch;
}
this.spPositions.reverse();
};
DateFormatter.prototype.format = function (date) {
this.date = date;
var result = this.mask;
for (var _i = 0, _a = this.spPositions; _i < _a.length; _i++) {
var pos = _a[_i];
var sp = this.specifiers[pos];
var replacerKey = sp.substr(0, 1);
if (this.replacers[replacerKey])
result = result.substr(0, pos) + this.replacers[replacerKey].call(this, sp.length) + result.substr(pos + sp.length);
}
return result;
};
DateFormatter.prototype.parse = function (str, rememberParserKeys) {
var now = new Date();
this.savedYear = now.getFullYear();
this.isYearParsed = false;
this.parsedMonth = -1;
this.date = new Date(2000, 0, now.getDate());
this.strToParse = str;
this.catchNumbers(str);
this.hasAmPm = false;
for (var _i = 0, _a = this.spPositions; _i < _a.length; _i++) {
var pos = _a[_i];
var sp = this.specifiers[pos];
var parserKey = sp.substr(0, 1);
if (this.parsers[parserKey]) {
if (rememberParserKeys)
this.parserKeys.push(parserKey);
if (!this.parsers[parserKey].call(this, sp.length))
return false;
}
}
if (this.hasAmPm) {
if (!this.fixHours())
return false;
}
if (!this.isYearParsed)
this.date.setFullYear(this.savedYear);
if (this.parsedMonth < 0)
this.parsedMonth = now.getMonth();
this.applyMonth();
return this.date;
};
DateFormatter.prototype.hasYear = function () {
return this.hasParserKey('y');
};
DateFormatter.prototype.hasMonth = function () {
return this.hasParserKey('M');
};
DateFormatter.prototype.hasDay = function () {
return this.hasParserKey('d');
};
DateFormatter.prototype.hasHours = function () {
return this.hasParserKey('h') || this.hasParserKey('H');
};
DateFormatter.prototype.hasMinutes = function () {
return this.hasParserKey('m');
};
DateFormatter.prototype.hasSeconds = function () {
return this.hasParserKey('s');
};
DateFormatter.prototype.hasMilliseconds = function () {
return this.hasParserKey('f') || this.hasParserKey('F');
};
DateFormatter.prototype.hasParserKey = function (key) {
return this.parserKeys.indexOf(key) !== -1;
};
DateFormatter.expandPredefinedFormat = function (format, options) {
switch (format) {
case 'd':
return options.shortDate;
case 'D':
return options.longDate;
case 't':
return options.shortTime;
case 'T':
return options.longTime;
case 'g':
return options.shortDate + ' ' + options.shortTime;
case 'f':
return options.longDate + ' ' + options.shortTime;
case 'G':
return options.shortDate + ' ' + options.longTime;
case 'F':
case 'U':
return options.longDate + ' ' + options.longTime;
case 'M':
case 'm':
return options.monthDay;
case 'Y':
case 'y':
return options.yearMonth;
case 'O':
case 'o':
return 'yyyy\'-\'MM\'-\'dd\'T\'HH\':\'mm\':\'ss.fffffff';
case 'R':
case 'r':
return 'ddd, dd MMM yyyy HH\':\'mm\':\'ss \'GMT\'';
case 's':
return 'yyyy\'-\'MM\'-\'dd\'T\'HH\':\'mm\':\'ss';
case 'u':
return 'yyyy\'-\'MM\'-\'dd HH\':\'mm\':\'ss\'Z\'';
}
return format;
};
DateFormatter.prototype.applyMonth = function () {
var trial;
var day = this.date.getDate();
while (true) {
trial = new Date();
trial.setTime(this.date.getTime());
trial.setMonth(this.parsedMonth);
if (trial.getMonth() === this.parsedMonth)
break;
--day;
this.date.setDate(day);
}
date_utils_1.DateUtils.fixTimezoneGap(this.date, trial);
this.date = trial;
};
DateFormatter.prototype.registerSpecifier = function (pos, sp, stringContainsDateSeparator) {
if (this.options.ds.length > 1 && this.mask && !stringContainsDateSeparator) {
var dateParts = this.mask.split(this.options.ds);
if (dateParts) {
if (dateParts.length > 0 && dateParts[dateParts.length - 1] === '')
dateParts.pop();
pos += (dateParts.length - 1) * (this.options.ds.length - 1);
}
}
this.spPositions.push(pos);
this.specifiers[pos] = sp;
};
DateFormatter.prototype.replaceDay = function (length) {
if (length < 3) {
var value = this.date.getDate().toString();
return length === 2 ? this.padLeft(value, 2) : value;
}
else if (length === 3)
return this.options.abbrDayNames[this.date.getDay()];
else
return this.options.dayNames[this.date.getDay()];
};
DateFormatter.prototype.replaceMonth = function (length) {
var value = 1 + this.date.getMonth();
switch (length) {
case 1:
return value.toString();
case 2:
return this.padLeft(value.toString(), 2);
case 3:
return this.options.abbrMonthNames[value - 1];
default:
for (var i in this.specifiers) {
if (Object.prototype.hasOwnProperty.call(this.specifiers, i)) {
var spec = this.specifiers[i];
if (spec === 'd' || spec === 'dd')
return this.options.genMonthNames[value - 1];
}
}
return this.options.monthNames[value - 1];
}
};
DateFormatter.prototype.replaceYear = function (length) {
var value = this.date.getFullYear();
if (length <= 2)
value = value % 100;
return this.padLeft(value.toString(), length);
};
DateFormatter.prototype.replaceHours23 = function (length) {
var value = this.date.getHours().toString();
return length > 1 ? this.padLeft(value, 2) : value;
};
DateFormatter.prototype.replaceHours12 = function (length) {
var value = this.date.getHours() % 12;
if (value === 0)
value = 12;
var strValue = value.toString();
return length > 1 ? this.padLeft(strValue, 2) : strValue;
};
DateFormatter.prototype.replaceMinutes = function (length) {
var value = this.date.getMinutes().toString();
return length > 1 ? this.padLeft(value, 2) : value;
};
DateFormatter.prototype.replaceSeconds = function (length) {
var value = this.date.getSeconds().toString();
return length > 1 ? this.padLeft(value, 2) : value;
};
DateFormatter.prototype.replaceMsTrimmed = function (length) {
return this.formatMs(length, true);
};
DateFormatter.prototype.replaceMs = function (length) {
return this.formatMs(length, false);
};
DateFormatter.prototype.replaceEra = function (_length) {
return 'A.D.';
};
DateFormatter.prototype.replaceAmPm = function (length) {
var value = this.date.getHours() < 12 ? this.options.am : this.options.pm;
return length < 2 ? value.charAt(0) : value;
};
DateFormatter.prototype.catchNumbers = function (str) {
var _this = this;
this.parseNumbers = [];
var regex = /\d+/g;
var match;
while (true) {
match = regex.exec(str);
if (!match)
break;
this.parseNumbers.push(this.parseDecInt(match[0]));
}
var spCount = 0;
var now = new Date();
string_1.StringMapUtils.forEach(this.specifiers, function (sp) {
if (typeof (sp) !== 'string' || !_this.isNumericSpecifier(sp))
return;
spCount++;
if (_this.parseNumbers.length < spCount) {
var defaultValue = 0;
if (sp.charAt(0) === 'y')
defaultValue = now.getFullYear();
_this.parseNumbers.push(defaultValue);
}
});
var excess = this.parseNumbers.length - spCount;
if (excess > 0)
this.parseNumbers.splice(spCount, excess);
this.currentParseNumber = this.parseNumbers.length - 1;
};
DateFormatter.prototype.popParseNumber = function () {
return this.parseNumbers[this.currentParseNumber--];
};
DateFormatter.prototype.findAbbrMonth = function () {
return this.findMonthCore(this.options.abbrMonthNames);
};
DateFormatter.prototype.findFullMonth = function () {
return this.findMonthCore(this.options.genMonthNames);
};
DateFormatter.prototype.findMonthCore = function (monthNames) {
var inputLower = this.strToParse.toLowerCase();
for (var i = 0; i < monthNames.length; i++) {
var monthName = monthNames[i].toLowerCase();
if (monthName.length > 0 && inputLower.indexOf(monthName) > -1) {
this.strToParse = this.strToParse.replace(new RegExp(monthName, 'gi'), string_2.StringUtils.repeat(' ', monthName.length));
return 1 + i;
}
}
return false;
};
DateFormatter.prototype.parseDay = function (length) {
if (length < 3) {
var value = this.popParseNumber();
if (value < 1 || value > 31)
return false;
this.date.setDate(value);
}
return true;
};
DateFormatter.prototype.parseMonth = function (length) {
var value;
switch (length) {
case 1:
case 2:
value = this.popParseNumber();
break;
case 3:
value = this.findAbbrMonth();
break;
default:
value = this.findFullMonth();
break;
}
if (value === false || value < 1 || value > 12)
return false;
this.parsedMonth = value - 1;
return true;
};
DateFormatter.prototype.parseYear = function (_length) {
var value = this.popParseNumber();
if (value > 9999)
return false;
if (value < 100)
value = date_utils_1.DateUtils.expandTwoDigitYear(value, this.options);
this.date.setFullYear(value);
this.isYearParsed = true;
return true;
};
DateFormatter.prototype.parseHours = function (_length) {
var value = this.popParseNumber();
if (value > 23)
return false;
this.date.setHours(value);
return true;
};
DateFormatter.prototype.parseMinutes = function (_length) {
var value = this.parseMinSecCore();
if (value === -1)
return false;
this.date.setMinutes(value);
return true;
};
DateFormatter.prototype.parseSeconds = function (_length) {
var value = this.parseMinSecCore();
if (value === -1)
return false;
this.date.setSeconds(value);
return true;
};
DateFormatter.prototype.parseMs = function (length) {
if (length > 3)
length = 3;
var thr = 1;
for (var i = 0; i < length; i++)
thr *= 10;
thr -= 1;
var value = this.popParseNumber();
while (value > thr)
value /= 10;
this.date.setMilliseconds(Math.round(value));
return true;
};
DateFormatter.prototype.parseEra = function (_length) {
return true;
};
DateFormatter.prototype.parseAmPm = function (_length) {
this.hasAmPm = this.options.am.length > 0 && this.options.pm.length > 0;
return true;
};
DateFormatter.prototype.parseDecInt = function (str) {
return parseInt(str, 10);
};
DateFormatter.prototype.padLeft = function (str, length) {
while (str.length < length)
str = '0' + str;
return str;
};
DateFormatter.prototype.formatMs = function (length, trim) {
var numVal = Math.floor(this.date.getMilliseconds() * Math.pow(10, length - 3));
var value = this.padLeft(numVal.toString(), length);
if (trim) {
var pos = value.length - 1;
var req = false;
while (value.charAt(pos) === '0') {
req = true;
pos--;
}
if (req)
value = value.substring(0, pos + 1);
}
return value;
};
DateFormatter.prototype.parseMinSecCore = function () {
var value = this.popParseNumber();
return value > 59 ? -1 : value;
};
DateFormatter.prototype.fixHours = function () {
var state = this.getAmPmState(this.strToParse, false);
if (!state)
return true;
var h = this.date.getHours();
switch (state) {
case 'P':
if (h > 12)
return false;
if (h < 12)
this.date.setHours(12 + h);
break;
case 'A':
if (h === 12)
this.date.setHours(0);
}
return true;
};
DateFormatter.prototype.getAmPmState = function (str, skipCorrection) {
var am = this.options.am.charAt(0).toLowerCase();
var pm = this.options.pm.charAt(0).toLowerCase();
var amMatches = new RegExp(am, 'gi').exec(str);
var pmMatches = new RegExp(pm, 'gi').exec(str);
var amCount = amMatches ? amMatches.length : 0;
var pmCount = pmMatches ? pmMatches.length : 0;
var hasAm = amCount > 0;
var hasPm = pmCount > 0;
if (hasAm !== hasPm && amCount < 2 && pmCount < 2)
return hasAm ? 'A' : 'P';
if (!skipCorrection) {
str = str.replace(new RegExp(this.getDayMonthNameReplacePattern(), 'gi'), '');
return this.getAmPmState(str, true);
}
return null;
};
DateFormatter.prototype.getDayMonthNameReplacePattern = function () {
if (!this.dayMonthNameReplacePattern)
return this.createDayMonthNameReplacePattern();
return this.dayMonthNameReplacePattern;
};
DateFormatter.prototype.createDayMonthNameReplacePattern = function () {
var parts = [];
parts.push('(?:');
parts.push(this.createReplacePattern(this.options.monthNames));
parts.push(this.createReplacePattern(this.options.genMonthNames));
parts.push(this.createReplacePattern(this.options.abbrMonthNames));
parts.push(this.createReplacePattern(this.options.abbrDayNames));
parts.push(this.createReplacePattern(this.options.dayNames));
parts.push(')');
return parts.join('');
};
DateFormatter.prototype.createReplacePattern = function (names) {
return names && names.length > 0 ? '\\b' + names.join('\\b|\\b') + '\\b' : '';
};
DateFormatter.prototype.isNumericSpecifier = function (sp) {
var ch = sp.charAt(0);
return !(ch === 'g' || ch === 't' || ((ch === 'M' || ch === 'd') && sp.length > 2));
};
DateFormatter.prototype.isKnownSpecifier = function (sp) {
sp = sp.charAt(0);
return this.knownSpecifiers.indexOf(sp) !== -1;
};
return DateFormatter;
}());
exports.DateFormatter = DateFormatter;