grafana/public/app/core/utils/timeRegions.ts
Leon Sorokin faad4b92ad
GrafanaDS: Add support for annotation time regions (#65462)
Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
Co-authored-by: Adela Almasan <adela.almasan@grafana.com>
2023-04-21 23:25:50 +03:00

173 lines
4.1 KiB
TypeScript

import { AbsoluteTimeRange, dateTime, TimeRange } from '@grafana/data';
export interface TimeRegionConfig {
from?: string;
fromDayOfWeek?: number; // 1-7
to?: string;
toDayOfWeek?: number; // 1-7
timezone?: string;
}
interface ParsedTime {
dayOfWeek?: number; // 1-7
h?: number; // 0-23
m?: number; // 0-59
s?: number; // 0-59
}
export function calculateTimesWithin(cfg: TimeRegionConfig, tRange: TimeRange): AbsoluteTimeRange[] {
if (!(cfg.fromDayOfWeek || cfg.from) && !(cfg.toDayOfWeek || cfg.to)) {
return [];
}
// So we can mutate
const timeRegion = { ...cfg };
if (timeRegion.from && !timeRegion.to) {
timeRegion.to = timeRegion.from;
}
if (!timeRegion.from && timeRegion.to) {
timeRegion.from = timeRegion.to;
}
const hRange = {
from: parseTimeOfDay(timeRegion.from),
to: parseTimeOfDay(timeRegion.to),
};
if (!timeRegion.fromDayOfWeek && timeRegion.toDayOfWeek) {
timeRegion.fromDayOfWeek = timeRegion.toDayOfWeek;
}
if (!timeRegion.toDayOfWeek && timeRegion.fromDayOfWeek) {
timeRegion.toDayOfWeek = timeRegion.fromDayOfWeek;
}
if (timeRegion.fromDayOfWeek) {
hRange.from.dayOfWeek = Number(timeRegion.fromDayOfWeek);
}
if (timeRegion.toDayOfWeek) {
hRange.to.dayOfWeek = Number(timeRegion.toDayOfWeek);
}
if (hRange.from.dayOfWeek && hRange.from.h == null && hRange.from.m == null) {
hRange.from.h = 0;
hRange.from.m = 0;
hRange.from.s = 0;
}
if (hRange.to.dayOfWeek && hRange.to.h == null && hRange.to.m == null) {
hRange.to.h = 23;
hRange.to.m = 59;
hRange.to.s = 59;
}
if (!hRange.from || !hRange.to) {
return [];
}
if (hRange.from.h == null) {
hRange.from.h = 0;
}
if (hRange.to.h == null) {
hRange.to.h = 23;
}
const regions: AbsoluteTimeRange[] = [];
const fromStart = dateTime(tRange.from).utc();
fromStart.set('hour', 0);
fromStart.set('minute', 0);
fromStart.set('second', 0);
fromStart.set('millisecond', 0);
fromStart.add(hRange.from.h, 'hours');
fromStart.add(hRange.from.m, 'minutes');
fromStart.add(hRange.from.s, 'seconds');
while (fromStart.unix() <= tRange.to.unix()) {
while (hRange.from.dayOfWeek && hRange.from.dayOfWeek !== fromStart.isoWeekday()) {
fromStart.add(24, 'hours');
}
if (fromStart.unix() > tRange.to.unix()) {
break;
}
const fromEnd = dateTime(fromStart).utc();
if (fromEnd.hour) {
if (hRange.from.h <= hRange.to.h) {
fromEnd.add(hRange.to.h - hRange.from.h, 'hours');
} else if (hRange.from.h > hRange.to.h) {
while (fromEnd.hour() !== hRange.to.h) {
fromEnd.add(1, 'hours');
}
} else {
fromEnd.add(24 - hRange.from.h, 'hours');
while (fromEnd.hour() !== hRange.to.h) {
fromEnd.add(1, 'hours');
}
}
}
fromEnd.set('minute', hRange.to.m ?? 0);
fromEnd.set('second', hRange.to.s ?? 0);
while (hRange.to.dayOfWeek && hRange.to.dayOfWeek !== fromEnd.isoWeekday()) {
fromEnd.add(24, 'hours');
}
const outsideRange =
(fromStart.unix() < tRange.from.unix() && fromEnd.unix() < tRange.from.unix()) ||
(fromStart.unix() > tRange.to.unix() && fromEnd.unix() > tRange.to.unix());
if (!outsideRange) {
regions.push({ from: fromStart.valueOf(), to: fromEnd.valueOf() });
}
fromStart.add(24, 'hours');
}
return regions;
}
export function parseTimeOfDay(str?: string): ParsedTime {
const result: ParsedTime = {};
if (!str?.length) {
return result;
}
const match = str.split(':');
if (!match?.length) {
return result;
}
result.h = Math.min(23, Math.max(0, Number(match[0])));
if (match.length > 1) {
result.m = Math.min(60, Math.max(0, Number(match[1])));
if (match.length > 2) {
result.s = Math.min(60, Math.max(0, Number(match[2])));
}
}
return result;
}
export function formatTimeOfDayString(t?: ParsedTime): string {
if (!t || (t.h == null && t.m == null && t.s == null)) {
return '';
}
let str = String(t.h ?? 0).padStart(2, '0') + ':' + String(t.m ?? 0).padStart(2, '0');
if (t.s != null) {
str += String(t.s ?? 0).padStart(2, '0');
}
return str;
}