RangeUtils: migrate logic from kbn to grafana/data (#27347)

This commit is contained in:
Ryan McKinley
2020-09-02 23:54:06 -07:00
committed by GitHub
parent 6c5a0421fe
commit febbc60e8b
21 changed files with 322 additions and 229 deletions
@@ -0,0 +1,43 @@
import { rangeUtil } from './index';
describe('Range Utils', () => {
describe('relative time', () => {
it('should identify absolute vs relative', () => {
expect(
rangeUtil.isRelativeTimeRange({
from: '1234',
to: '4567',
})
).toBe(false);
expect(
rangeUtil.isRelativeTimeRange({
from: 'now-5',
to: 'now',
})
).toBe(true);
});
});
describe('describe_interval', () => {
it('falls back to seconds if input is a number', () => {
expect(rangeUtil.describeInterval('123')).toEqual({
sec: 1,
type: 's',
count: 123,
});
});
it('parses a valid time unt string correctly', () => {
expect(rangeUtil.describeInterval('123h')).toEqual({
sec: 3600,
type: 'h',
count: 123,
});
});
it('fails if input is invalid', () => {
expect(() => rangeUtil.describeInterval('123xyz')).toThrow();
expect(() => rangeUtil.describeInterval('xyz')).toThrow();
});
});
});
+198 -2
View File
@@ -1,10 +1,11 @@
import each from 'lodash/each';
import groupBy from 'lodash/groupBy';
import has from 'lodash/has';
import { RawTimeRange, TimeRange, TimeZone } from '../types/time';
import { RawTimeRange, TimeRange, TimeZone, IntervalValues } from '../types/time';
import * as dateMath from './datemath';
import { isDateTime } from './moment_wrapper';
import { isDateTime, DateTime } from './moment_wrapper';
import { timeZoneAbbrevation, dateTimeFormat, dateTimeFormatTimeAgo } from './formatter';
import { dateTimeParse } from './parser';
@@ -221,3 +222,198 @@ export const convertRawToRange = (raw: RawTimeRange, timeZone?: TimeZone): TimeR
return { from, to, raw: { from, to } };
};
function isRelativeTime(v: DateTime | string) {
if (typeof v === 'string') {
return (v as string).indexOf('now') >= 0;
}
return false;
}
export function isRelativeTimeRange(raw: RawTimeRange): boolean {
return isRelativeTime(raw.from) || isRelativeTime(raw.to);
}
export function secondsToHms(seconds: number): string {
const numYears = Math.floor(seconds / 31536000);
if (numYears) {
return numYears + 'y';
}
const numDays = Math.floor((seconds % 31536000) / 86400);
if (numDays) {
return numDays + 'd';
}
const numHours = Math.floor(((seconds % 31536000) % 86400) / 3600);
if (numHours) {
return numHours + 'h';
}
const numMinutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
if (numMinutes) {
return numMinutes + 'm';
}
const numSeconds = Math.floor((((seconds % 31536000) % 86400) % 3600) % 60);
if (numSeconds) {
return numSeconds + 's';
}
const numMilliseconds = Math.floor(seconds * 1000.0);
if (numMilliseconds) {
return numMilliseconds + 'ms';
}
return 'less than a millisecond'; //'just now' //or other string you like;
}
export function calculateInterval(range: TimeRange, resolution: number, lowLimitInterval?: string): IntervalValues {
let lowLimitMs = 1; // 1 millisecond default low limit
if (lowLimitInterval) {
lowLimitMs = intervalToMs(lowLimitInterval);
}
let intervalMs = roundInterval((range.to.valueOf() - range.from.valueOf()) / resolution);
if (lowLimitMs > intervalMs) {
intervalMs = lowLimitMs;
}
return {
intervalMs: intervalMs,
interval: secondsToHms(intervalMs / 1000),
};
}
const interval_regex = /(\d+(?:\.\d+)?)(ms|[Mwdhmsy])/;
// histogram & trends
const intervals_in_seconds = {
y: 31536000,
M: 2592000,
w: 604800,
d: 86400,
h: 3600,
m: 60,
s: 1,
ms: 0.001,
};
export function describeInterval(str: string) {
// Default to seconds if no unit is provided
if (Number(str)) {
return {
sec: intervals_in_seconds.s,
type: 's',
count: parseInt(str, 10),
};
}
const matches = str.match(interval_regex);
if (!matches || !has(intervals_in_seconds, matches[2])) {
throw new Error(
`Invalid interval string, has to be either unit-less or end with one of the following units: "${Object.keys(
intervals_in_seconds
).join(', ')}"`
);
}
return {
sec: (intervals_in_seconds as any)[matches[2]] as number,
type: matches[2],
count: parseInt(matches[1], 10),
};
}
export function intervalToSeconds(str: string): number {
const info = describeInterval(str);
return info.sec * info.count;
}
export function intervalToMs(str: string): number {
const info = describeInterval(str);
return info.sec * 1000 * info.count;
}
export function roundInterval(interval: number) {
switch (true) {
// 0.015s
case interval < 15:
return 10; // 0.01s
// 0.035s
case interval < 35:
return 20; // 0.02s
// 0.075s
case interval < 75:
return 50; // 0.05s
// 0.15s
case interval < 150:
return 100; // 0.1s
// 0.35s
case interval < 350:
return 200; // 0.2s
// 0.75s
case interval < 750:
return 500; // 0.5s
// 1.5s
case interval < 1500:
return 1000; // 1s
// 3.5s
case interval < 3500:
return 2000; // 2s
// 7.5s
case interval < 7500:
return 5000; // 5s
// 12.5s
case interval < 12500:
return 10000; // 10s
// 17.5s
case interval < 17500:
return 15000; // 15s
// 25s
case interval < 25000:
return 20000; // 20s
// 45s
case interval < 45000:
return 30000; // 30s
// 1.5m
case interval < 90000:
return 60000; // 1m
// 3.5m
case interval < 210000:
return 120000; // 2m
// 7.5m
case interval < 450000:
return 300000; // 5m
// 12.5m
case interval < 750000:
return 600000; // 10m
// 12.5m
case interval < 1050000:
return 900000; // 15m
// 25m
case interval < 1500000:
return 1200000; // 20m
// 45m
case interval < 2700000:
return 1800000; // 30m
// 1.5h
case interval < 5400000:
return 3600000; // 1h
// 2.5h
case interval < 9000000:
return 7200000; // 2h
// 4.5h
case interval < 16200000:
return 10800000; // 3h
// 9h
case interval < 32400000:
return 21600000; // 6h
// 1d
case interval < 86400000:
return 43200000; // 12h
// 1w
case interval < 604800000:
return 86400000; // 1d
// 3w
case interval < 1814400000:
return 604800000; // 1w
// 6w
case interval < 3628800000:
return 2592000000; // 30d
default:
return 31536000000; // 1y
}
}