mirror of https://github.com/grafana/grafana.git
162 lines
4.6 KiB
TypeScript
162 lines
4.6 KiB
TypeScript
import includes from 'lodash/includes';
|
|
import isDate from 'lodash/isDate';
|
|
import { DateTime, dateTime, dateTimeForTimeZone, ISO_8601, isDateTime, DurationUnit } from './moment_wrapper';
|
|
import { TimeZone } from '../types/index';
|
|
|
|
const units: DurationUnit[] = ['y', 'M', 'w', 'd', 'h', 'm', 's'];
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
export namespace dateMath {
|
|
export function isMathString(text: string | DateTime | Date): boolean {
|
|
if (!text) {
|
|
return false;
|
|
}
|
|
|
|
if (typeof text === 'string' && (text.substring(0, 3) === 'now' || text.includes('||'))) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses different types input to a moment instance. There is a specific formatting language that can be used
|
|
* if text arg is string. See unit tests for examples.
|
|
* @param text
|
|
* @param roundUp See parseDateMath function.
|
|
* @param timezone Only string 'utc' is acceptable here, for anything else, local timezone is used.
|
|
*/
|
|
export function parse(text: string | DateTime | Date, roundUp?: boolean, timezone?: TimeZone): DateTime | undefined {
|
|
if (!text) {
|
|
return undefined;
|
|
}
|
|
|
|
if (typeof text !== 'string') {
|
|
if (isDateTime(text)) {
|
|
return text;
|
|
}
|
|
if (isDate(text)) {
|
|
return dateTime(text);
|
|
}
|
|
// We got some non string which is not a moment nor Date. TS should be able to check for that but not always.
|
|
return undefined;
|
|
} else {
|
|
let time;
|
|
let mathString = '';
|
|
let index;
|
|
let parseString;
|
|
|
|
if (text.substring(0, 3) === 'now') {
|
|
time = dateTimeForTimeZone(timezone);
|
|
mathString = text.substring('now'.length);
|
|
} else {
|
|
index = text.indexOf('||');
|
|
if (index === -1) {
|
|
parseString = text;
|
|
mathString = ''; // nothing else
|
|
} else {
|
|
parseString = text.substring(0, index);
|
|
mathString = text.substring(index + 2);
|
|
}
|
|
// We're going to just require ISO8601 timestamps, k?
|
|
time = dateTime(parseString, ISO_8601);
|
|
}
|
|
|
|
if (!mathString.length) {
|
|
return time;
|
|
}
|
|
|
|
return parseDateMath(mathString, time, roundUp);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if text is a valid date which in this context means that it is either a Moment instance or it can be parsed
|
|
* by parse function. See parse function to see what is considered acceptable.
|
|
* @param text
|
|
*/
|
|
export function isValid(text: string | DateTime): boolean {
|
|
const date = parse(text);
|
|
if (!date) {
|
|
return false;
|
|
}
|
|
|
|
if (isDateTime(date)) {
|
|
return date.isValid();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Parses math part of the time string and shifts supplied time according to that math. See unit tests for examples.
|
|
* @param mathString
|
|
* @param time
|
|
* @param roundUp If true it will round the time to endOf time unit, otherwise to startOf time unit.
|
|
*/
|
|
// TODO: Had to revert Andrejs `time: moment.Moment` to `time: any`
|
|
export function parseDateMath(mathString: string, time: any, roundUp?: boolean): DateTime | undefined {
|
|
const strippedMathString = mathString.replace(/\s/g, '');
|
|
const dateTime = time;
|
|
let i = 0;
|
|
const len = strippedMathString.length;
|
|
|
|
while (i < len) {
|
|
const c = strippedMathString.charAt(i++);
|
|
let type;
|
|
let num;
|
|
let unit;
|
|
|
|
if (c === '/') {
|
|
type = 0;
|
|
} else if (c === '+') {
|
|
type = 1;
|
|
} else if (c === '-') {
|
|
type = 2;
|
|
} else {
|
|
return undefined;
|
|
}
|
|
|
|
if (isNaN(parseInt(strippedMathString.charAt(i), 10))) {
|
|
num = 1;
|
|
} else if (strippedMathString.length === 2) {
|
|
num = strippedMathString.charAt(i);
|
|
} else {
|
|
const numFrom = i;
|
|
while (!isNaN(parseInt(strippedMathString.charAt(i), 10))) {
|
|
i++;
|
|
if (i > 10) {
|
|
return undefined;
|
|
}
|
|
}
|
|
num = parseInt(strippedMathString.substring(numFrom, i), 10);
|
|
}
|
|
|
|
if (type === 0) {
|
|
// rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
|
|
if (num !== 1) {
|
|
return undefined;
|
|
}
|
|
}
|
|
unit = strippedMathString.charAt(i++);
|
|
|
|
if (!includes(units, unit)) {
|
|
return undefined;
|
|
} else {
|
|
if (type === 0) {
|
|
if (roundUp) {
|
|
dateTime.endOf(unit);
|
|
} else {
|
|
dateTime.startOf(unit);
|
|
}
|
|
} else if (type === 1) {
|
|
dateTime.add(num, unit);
|
|
} else if (type === 2) {
|
|
dateTime.subtract(num, unit);
|
|
}
|
|
}
|
|
}
|
|
return dateTime;
|
|
}
|
|
}
|