-
Notifications
You must be signed in to change notification settings - Fork 18
/
index.ts
115 lines (95 loc) · 3.66 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { PluginInterface, TimeFrame } from '@debut/types';
import { date } from '@debut/plugin-utils';
export interface SessionPluginOptions {
interval: TimeFrame;
timezone?: string;
from?: string;
to?: string;
}
export interface SessionPluginExtends {
onDayEnded(): void;
}
interface Methods {
createSessionValidator: typeof createSessionValidator;
}
export interface SessionAPI {
session: Methods;
}
export interface SessionInterface extends PluginInterface {
name: 'stats';
api: Methods;
}
export function sessionPlugin(options: SessionPluginOptions, onDayEnd?: (...args: unknown[]) => void): PluginInterface {
const { from, to, interval, timezone = 'en-US' } = options;
const sessionValidator = createSessionValidator(interval, timezone, from, to);
return {
name: 'session',
api: {
createSessionValidator: createSessionFilter,
},
onBeforeTick(tick) {
const stamp = tick.time;
const result = !!sessionValidator && sessionValidator(stamp);
if (onDayEnd && result.dayChanged) {
onDayEnd();
}
return !result.inSession;
},
};
}
export type SessionValidator = ReturnType<typeof createSessionFilter>;
export type SessionValidatorResult = {
inSession: boolean;
dayChanged: boolean;
};
/**
* Метод создания валидатора из человеко читаемых дат
*/
export function createSessionValidator(
interval: TimeFrame,
timezone: string,
from?: string,
to?: string,
): (stamp: number) => SessionValidatorResult {
let start = 0;
let end = date.DAY;
const intervalMs = date.intervalToMs(interval);
if (from) {
const [fromHour, fromMinute] = from.split(':').map(Number);
start = fromHour * date.HOUR + fromMinute * date.MINUTE;
}
if (to) {
const [toHour, toMinute] = to.split(':').map(Number);
end = toHour * date.HOUR + toMinute * date.MINUTE;
}
return createSessionFilter(intervalMs, timezone, start, end);
}
/**
* Метод создания валидатора сессионного окна по дате, с переходом на зимнее и летнее время
*/
function createSessionFilter(intervalMs: number, timezone: string, start: number, end: number) {
let currentDayMarker = 0;
let marketStart = 0;
let marketEnd = 0;
let timeMode: date.TimeMode;
const getDST = date.getDSTDetector(timezone);
const [summerOffset, winterOffset] = date.getOffsetMs(timezone);
return (stamp: number): SessionValidatorResult => {
const dayChanged = stamp > currentDayMarker;
if (dayChanged) {
timeMode = getDST(stamp);
}
if (dayChanged || currentDayMarker === 0) {
// Если еще нет текущей даты или сменился день, перегенерируем дату
// Коррекция дат, для разных часовых поясов, время старта указывается в летнем времени
const dstOffset = timeMode === date.TimeMode.Summer ? summerOffset : winterOffset;
const currentDay = ~~(stamp / date.DAY) * date.DAY;
currentDayMarker = currentDay + date.DAY - 1;
// Переводич часы и минуты в stamp и прибавляем к дате
marketStart = currentDay + start + dstOffset;
marketEnd = currentDay + end + dstOffset;
}
const stampEnd = stamp + intervalMs;
return { inSession: marketStart <= stamp && stampEnd <= marketEnd, dayChanged };
};
}