tynder
Version:
TypeScript friendly Data validator for JavaScript.
320 lines • 15.2 kB
JavaScript
// Copyright (c) 2020 Shellyl_N and Authors
// license: ISC
// https://github.com/shellyln
import { DatePattern, DateTimePattern, DateTimeNoTzPattern } from '../lib/util';
const FyPattern = /^first-date-of-fy\(([0-9]+)\)$/;
const FormulaPattern = /^([-+@])([0-9]+)(yr|mo|day|days|hr|min|sec|ms)$/;
class UtcDate extends Date {
constructor(year, month, date, hours, minutes, seconds, ms) {
super();
if (year === void 0) {
return;
}
if (typeof year === 'string') {
if (DateTimePattern.test(year)) {
// string parameter is expected to be treated as specified TZ
this.setTime(Date.parse(year)); // returns date in specified TZ
}
else if (DatePattern.test(year)) {
// string parameter is expected to be treated as UTC
const d = new Date(year); // returns date in UTC TZ (getUTC??? returns string parameter's date & time digits)
this.setTime(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
}
else if (DateTimeNoTzPattern.test(year)) {
// string parameter is expected to be treated as UTC
const d = new Date(year); // returns date in local TZ (get??? returns string parameter's date & time digits)
this.setTime(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds()));
}
else {
this.setTime(NaN);
}
return;
}
this.setUTCDate(1);
this.setUTCFullYear(year);
this.setUTCMonth(typeof month === 'number' ? month : 0);
this.setUTCDate(typeof date === 'number' ? date : 1);
this.setUTCHours(typeof hours === 'number' ? hours : 0);
this.setUTCMinutes(typeof minutes === 'number' ? minutes : 0);
this.setUTCSeconds(typeof seconds === 'number' ? seconds : 0);
this.setUTCMilliseconds(typeof ms === 'number' ? ms : 0);
}
getFullYear() {
return this.getUTCFullYear();
}
getMonth() {
return this.getUTCMonth();
}
getDate() {
return this.getUTCDate();
}
getHours() {
return this.getUTCHours();
}
getMinutes() {
return this.getUTCMinutes();
}
getSeconds() {
return this.getUTCSeconds();
}
getMilliseconds() {
return this.getUTCMilliseconds();
}
}
class LcDate extends Date {
constructor(year, month, date, hours, minutes, seconds, ms) {
super();
if (year === void 0) {
return;
}
if (typeof year === 'string') {
if (DateTimePattern.test(year)) {
// string parameter is expected to be treated as specified TZ
this.setTime(Date.parse(year)); // returns date in specified TZ
}
else if (DatePattern.test(year)) {
// string parameter is expected to be treated as local TZ
const d = new Date(year); // returns date in UTC TZ (getUTC??? returns string parameter's date & time digits)
const l = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
this.setTime(l.getTime());
}
else if (DateTimeNoTzPattern.test(year)) {
// string parameter is expected to be treated as local TZ
const d = new Date(year); // returns date in local TZ (get??? returns string parameter's date & time digits)
this.setTime(d.getTime());
}
else {
this.setTime(NaN);
}
return;
}
this.setDate(1);
this.setFullYear(year);
this.setMonth(typeof month === 'number' ? month : 0);
this.setDate(typeof date === 'number' ? date : 1);
this.setHours(typeof hours === 'number' ? hours : 0);
this.setMinutes(typeof minutes === 'number' ? minutes : 0);
this.setSeconds(typeof seconds === 'number' ? seconds : 0);
this.setMilliseconds(typeof ms === 'number' ? ms : 0);
}
}
function evaluateFormulaBase(dateCtor, valueOrFormula) {
const errMsg = `evaluateFormula: invalid parameter ${valueOrFormula}`;
if (typeof valueOrFormula !== 'string') {
throw new Error(errMsg);
}
if (valueOrFormula.startsWith('=')) {
const formula = valueOrFormula.slice(1).split(' ');
let d = new dateCtor();
const now = new dateCtor(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes());
const today = new dateCtor(d.getFullYear(), d.getMonth(), d.getDate());
d = now;
for (const f of formula) {
switch (f) {
case 'current':
case 'now':
d = now;
break;
case 'today':
d = today;
break;
case 'first-date-of-yr':
case 'first-date-of-fy(1)':
d = new dateCtor(d.getFullYear(), 0, 1);
break;
case 'last-date-of-yr':
d = new dateCtor(d.getFullYear(), 11, 31);
break;
case 'first-date-of-mo':
d = new dateCtor(d.getFullYear(), d.getMonth(), 1);
break;
case 'last-date-of-mo':
d = new dateCtor(d.getFullYear(), d.getMonth() + 1, 0);
break;
default:
if (f.startsWith('first-date-of-fy(')) {
const m = FyPattern.exec(f);
if (m) {
const n = Number.parseInt(m[1], 10);
if (0 < n && n <= 12) {
const mo = d.getMonth() + 1;
let yr = d.getFullYear();
if (mo < n) {
yr--;
}
d = new dateCtor(yr, n - 1, 1);
}
else {
throw new Error(errMsg);
}
}
else {
throw new Error(errMsg);
}
}
else {
const m = FormulaPattern.exec(f);
if (m) {
let n = Number.parseInt(m[2], 10);
switch (m[3]) {
case 'yr':
switch (m[1]) {
case '@':
break;
case '+':
n = d.getFullYear() + n;
break;
case '-':
n = d.getFullYear() - n;
break;
}
d = new dateCtor(n, d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
break;
case 'mo':
switch (m[1]) {
case '@':
n -= 1;
break;
case '+':
n = d.getMonth() + n;
break;
case '-':
n = d.getMonth() - n;
break;
}
d = new dateCtor(d.getFullYear(), n, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
break;
case 'day':
case 'days':
switch (m[1]) {
case '@':
break;
case '+':
n = d.getDate() + n;
break;
case '-':
n = d.getDate() - n;
break;
}
d = new dateCtor(d.getFullYear(), d.getMonth(), n, d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
break;
case 'hr':
switch (m[1]) {
case '@':
break;
case '+':
n = d.getHours() + n;
break;
case '-':
n = d.getHours() - n;
break;
}
d = new dateCtor(d.getFullYear(), d.getMonth(), d.getDate(), n, d.getMinutes(), d.getSeconds(), d.getMilliseconds());
break;
case 'min':
switch (m[1]) {
case '@':
break;
case '+':
n = d.getMinutes() + n;
break;
case '-':
n = d.getMinutes() - n;
break;
}
d = new dateCtor(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), n, d.getSeconds(), d.getMilliseconds());
break;
case 'sec':
switch (m[1]) {
case '@':
break;
case '+':
n = d.getSeconds() + n;
break;
case '-':
n = d.getSeconds() - n;
break;
}
d = new dateCtor(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), n, d.getMilliseconds());
break;
case 'ms':
switch (m[1]) {
case '@':
break;
case '+':
n = d.getMilliseconds() + n;
break;
case '-':
n = d.getMilliseconds() - n;
break;
}
d = new dateCtor(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), n);
break;
default:
throw new Error(errMsg);
}
}
else {
if (!(DatePattern.test(f) || DateTimePattern.test(f) || DateTimeNoTzPattern.test(f))) {
throw new Error(errMsg);
}
d = new dateCtor(f);
}
}
}
}
return d;
}
else {
if (!DatePattern.test(valueOrFormula)) {
throw new Error(errMsg);
}
return new dateCtor(valueOrFormula);
}
}
export const dateStereotype = {
tryParse: (value) => {
return (typeof value === 'string' && DatePattern.test(value)
? { value: (new UtcDate(value)).getTime() }
: null);
},
evaluateFormula: valueOrFormula => {
const d = evaluateFormulaBase(UtcDate, valueOrFormula);
return (new UtcDate(d.getFullYear(), d.getMonth(), d.getDate())).getTime();
},
compare: (a, b) => a - b,
doCast: false,
};
export const lcDateStereotype = Object.assign(Object.assign({}, dateStereotype), { tryParse: (value) => {
if (typeof value === 'string' && DatePattern.test(value)) {
return ({ value: (new LcDate(value)).getTime() });
}
else {
return null;
}
}, evaluateFormula: valueOrFormula => {
const d = evaluateFormulaBase(LcDate, valueOrFormula);
return (new LcDate(d.getFullYear(), d.getMonth(), d.getDate())).getTime();
} });
export const datetimeStereotype = {
tryParse: (value) => {
return (typeof value === 'string' && (DateTimePattern.test(value) || DateTimeNoTzPattern.test(value))
? { value: (new UtcDate(value)).getTime() } // If timezone is not specified, it is local time
: null);
},
evaluateFormula: valueOrFormula => evaluateFormulaBase(UtcDate, valueOrFormula).getTime(),
compare: (a, b) => a - b,
doCast: false,
};
export const lcDatetimeStereotype = Object.assign(Object.assign({}, datetimeStereotype), { tryParse: (value) => {
return (typeof value === 'string' && (DateTimePattern.test(value) || DateTimeNoTzPattern.test(value))
? { value: (new LcDate(value)).getTime() }
: null);
}, evaluateFormula: valueOrFormula => evaluateFormulaBase(LcDate, valueOrFormula).getTime() });
export const stereotypes = [
['date', dateStereotype],
['lcdate', lcDateStereotype],
['datetime', datetimeStereotype],
['lcdatetime', lcDatetimeStereotype],
];
//# sourceMappingURL=date.js.map