mirror of https://github.com/grafana/grafana
Graph: move time region calculation to a utility function (#51413)
parent
7bb644d910
commit
ededf1dd6f
@ -0,0 +1,43 @@ |
||||
import { dateTime, TimeRange } from '@grafana/data'; |
||||
|
||||
import { calculateTimesWithin, TimeRegionConfig } from './timeRegions'; |
||||
|
||||
describe('timeRegions', () => { |
||||
describe('day of week', () => { |
||||
it('4 sundays in january 2021', () => { |
||||
const cfg: TimeRegionConfig = { |
||||
fromDayOfWeek: 1, |
||||
from: '12:00', |
||||
}; |
||||
const tr: TimeRange = { |
||||
from: dateTime('2021-01-00', 'YYYY-MM-dd'), |
||||
to: dateTime('2021-02-00', 'YYYY-MM-dd'), |
||||
raw: { |
||||
to: '', |
||||
from: '', |
||||
}, |
||||
}; |
||||
const regions = calculateTimesWithin(cfg, tr); |
||||
expect(regions).toMatchInlineSnapshot(` |
||||
Array [ |
||||
Object { |
||||
"from": 1609779600000, |
||||
"to": 1609779600000, |
||||
}, |
||||
Object { |
||||
"from": 1610384400000, |
||||
"to": 1610384400000, |
||||
}, |
||||
Object { |
||||
"from": 1610989200000, |
||||
"to": 1610989200000, |
||||
}, |
||||
Object { |
||||
"from": 1611594000000, |
||||
"to": 1611594000000, |
||||
}, |
||||
] |
||||
`);
|
||||
}); |
||||
}); |
||||
}); |
@ -0,0 +1,168 @@ |
||||
import { AbsoluteTimeRange, dateTime, TimeRange } from '@grafana/data'; |
||||
|
||||
export interface TimeRegionConfig { |
||||
from?: string; |
||||
fromDayOfWeek?: number; // 1-7
|
||||
|
||||
to?: string; |
||||
toDayOfWeek?: number; // 1-7
|
||||
} |
||||
|
||||
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: parseTimeRange(timeRegion.from), |
||||
to: parseTimeRange(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); |
||||
fromStart.set('hour', 0); |
||||
fromStart.set('minute', 0); |
||||
fromStart.set('second', 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); |
||||
|
||||
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; |
||||
} |
||||
|
||||
function parseTimeRange(str?: string): ParsedTime { |
||||
const result: ParsedTime = {}; |
||||
if (!str?.length) { |
||||
return result; |
||||
} |
||||
|
||||
const timeRegex = /^([\d]+):?(\d{2})?/; |
||||
const match = timeRegex.exec(str); |
||||
|
||||
if (!match) { |
||||
return result; |
||||
} |
||||
|
||||
if (match.length > 1) { |
||||
result.h = Number(match[1]); |
||||
result.m = 0; |
||||
|
||||
if (match.length > 2 && match[2] !== undefined) { |
||||
result.m = Number(match[2]); |
||||
} |
||||
|
||||
if (result.h > 23) { |
||||
result.h = 23; |
||||
} |
||||
|
||||
if (result.m > 59) { |
||||
result.m = 59; |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
Loading…
Reference in new issue