UNPKG

calcdate

Version:

Evalate a date expression calc`now + 3 days`)!

311 lines (302 loc) 8.91 kB
export const datefns = /*#__PURE__*/ datefnslib => { const { parseISO, isValid, differenceInMilliseconds, isDate, toDate, addMilliseconds, addSeconds, addMinutes, addHours, addBusinessDays, addDays, addWeeks, addMonths, addQuarters, addYears, subMilliseconds, subSeconds, subMinutes, subHours, subBusinessDays, subDays, subWeeks, subMonths, subQuarters, subYears } = datefnslib; const divTable = { milliseconds: 1, seconds: 1000, minutes: 1000 * 60, hours: 1000 * 60 * 60, days: 1000 * 60 * 60 * 24, weekdays: 1000 * 60 * 60 * 24, weeks: 1000 * 60 * 60 * 24 * 7, months: 1000 * 60 * 60 * 24 * 30.436875, quarters: 1000 * 60 * 60 * 24 * 91.310625, years: 1000 * 60 * 60 * 24 * 365.2425 }; Object.fromEntries = Object.fromEntries || (arr => [...arr].reduce((obj, [key, val]) => { obj[key] = val; return obj; }, {})); const ops = Object.fromEntries( Object.entries({ addMilliseconds, addSeconds, addMinutes, addHours, addWeekDays: addBusinessDays, addDays, addWeeks, addMonths, addQuarters, addYears, subMilliseconds, subSeconds, subMinutes, subHours, subWeekDays: subBusinessDays, subDays, subWeeks, subMonths, subQuarters, subYears, addUnitless: addMilliseconds, subUnitless: subMilliseconds }).map(([k, v]) => [k.toLowerCase(), v]) ); return ( { NATIVEDATE, DATEXPRESION, DURATIONEXPRESSION, DURATIONOBJECT }, { console } ) => { const tostring = { configurable: false, enumerable: false, writable: false, value: function() { return JSON.stringify(this); } }; const isDurationConfig = { configurable: false, enumerable: false, writable: false, value: true }; const isDurationSymbol = Symbol("isDuration"); const newDuration = () => Object.defineProperty( Object.defineProperty({}, isDurationSymbol, isDurationConfig), "toString", tostring ); const isDuration = x => x[isDurationSymbol] === true; function makeDuration(arg) { const isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/; const match = isoRegex.exec(arg); if (match) { const sign = match[1] === "-" ? -1 : 1; const parseFloatInIso = mat => { const res = mat && parseFloat(mat.replace(",", ".")); return (isNaN(res) ? 0 : res) * sign; }; return Object.assign(newDuration(), { years: parseFloatInIso(match[2]), months: parseFloatInIso(match[3]), weeks: parseFloatInIso(match[4]), days: parseFloatInIso(match[5]), hours: parseFloatInIso(match[6]), minutes: parseFloatInIso(match[7]), seconds: parseFloatInIso(match[8]) }); } try { return Object.assign(newDuration(), JSON.parse(arg)); } catch (e) { throw new Error("Found invalid duration " + arg); } } const getType = arg => { if (isValid(arg)) return "DATE"; if (isDuration(arg)) return "DURATION"; if (isDate(toDate(arg)) && !isValid(arg)) return "INVALID DATE"; return typeof arg; }; const isUnitless = a => { const keys = Object.keys(a); return keys.length === 1 && keys[0] === "unitless"; }; return { makeDuration: (duration, { type }) => { return { [DURATIONEXPRESSION]: makeDuration, [DURATIONOBJECT]: a => Object.assign(newDuration(), a) }[type](duration); }, makeDate: (date, { type }) => { return { [DATEXPRESION]: parseISO, [NATIVEDATE]: d => d }[type](date); }, add: (a, b) => { if (isUnitless(a) && isUnitless(b)) { return { unitless: a.unitless + b.unitless }; } if (isDuration(a) && isDuration(b)) { return Object.entries(a).reduce( (p, [k, v]) => Object.assign(p, { [k]: (p[k] || 0) + v }), b ); } if (isValid(a) && isValid(b)) { throw new Error("Can't add dates to each other!"); } if (isValid(a) && isDuration(b)) { // b is duratoin return Object.entries(b).reduce( (date, [k, v]) => ops[`add${k}`](date, v), a ); } if (isValid(b) && isDuration(a)) { // a is duratoin return Object.entries(a).reduce( (date, [k, v]) => ops[`add${k}`](date, v), b ); } const e = `Invalid arguments for 'add', expected (date, duration), (duration, date), (duration, duration) but found (${getType( a )}, ${getType(b)})`; console.error(e, a, b); throw new Error(e); }, subtract: (a, b) => { if (isUnitless(a) && isUnitless(b)) { return { unitless: a.unitless - b.unitless }; } if (isDuration(a) && isDuration(b)) { return Object.entries(a).reduce( (p, [k, v]) => Object.assign(p, { [k]: (p[k] || 0) - v }), b ); } if (isValid(a) && isValid(b)) { console.warn( "subtracting two dates from each other is potentially unsafe as a loss of information occurs!" ); return Object.assign(newDuration(), { milliseconds: differenceInMilliseconds(a, b) }); } if (isValid(a) && isDuration(b)) { // b is duratoin return Object.entries(b).reduce( (date, [k, v]) => ops[`sub${k}`](date, v), a ); } if (isValid(b) && isDuration(a)) { // a is duratoin return Object.entries(a).reduce( (date, [k, v]) => ops[`sub${k}`](date, v), b ); } const e = `Invalid arguments for 'subtract', expected (date, duration), (duration, date), (duration, duration) but found (${getType( a )}, ${getType(b)})`; console.error(e, a, b); throw new Error(e); }, multiply: (a, b) => { if (isUnitless(a) && isUnitless(b)) { return { unitless: a.unitless * b.unitless }; } if (isDuration(a) && isUnitless(b)) { return Object.entries(a).reduce( (p, [k, v]) => Object.assign(p, { [k]: v * b.unitless }), newDuration() ); } if (isDuration(b) && isUnitless(a)) { return Object.entries(b).reduce( (p, [k, v]) => Object.assign(p, { [k]: v * a.unitless }), newDuration() ); } const e = `Invalid arguments for multiply, expected (duration, unitless) or (unitless, duration) but found (${getType( a )}, ${getType(b)})`; console.error(e, a, b); throw new Error(e); }, divide: (a, b) => { if (isUnitless(a) && isUnitless(b)) { return { unitless: a.unitless / b.unitless }; } if (isDuration(a) && isUnitless(b)) { return Object.entries(a).reduce( (p, [k, v]) => Object.assign(p, { [k]: v / b.unitless }), newDuration() ); } if (isDuration(b) && isUnitless(a)) { return Object.entries(b).reduce( (p, [k, v]) => Object.assign(p, { [k]: a.unitless / v }), newDuration() ); } if (isDuration(a) && isDuration(b)) { console.warn( `Dividing one duration by another is potentially unsafe! Assuming conversion table ${JSON.stringify( divTable, null, " " )}!` ); const bInMs = Object.entries(b).reduce( (p, [k, v]) => p + divTable[k] * v, 0 ); const aInMs = Object.entries(a).reduce( (p, [k, v]) => p + divTable[k] * v, 0 ); return { unitless: aInMs / bInMs }; } const e = `Invalid arguments for divide, expected (duration, unitless) or (unitless, duration) but found (${getType( a )}, ${getType(b)})`; console.error(e, a, b); throw new Error(e); } }; }; } export default datefns;