Алгоритм получения дат в временном промежутке
Необходима реализация алгоритма который бы мог выполнить следующее:
Есть две даты: start_time , end_time
Число определяющее кол-во необходимых дат: number (1-90)
Нужно сгенерировать number дат примерно равноотдаленных от друг друга в промежутке дат между start_time и end_time. То насколько сгенерированные даты отдалены от друг друга нужно сделать рандомным но при этом примерно одинаковым.
Пример:
start_time = '2021-02-26 12:00:00',
end_time = '2021-02-27 01:00:00',
number = 13
На выходе нужно 13 таймстепмов, к примеру:
2021-02-26 12:00:00
2021-02-26 13:25:00
2021-02-26 14:55:00
2021-02-26 15:45:00
2021-02-26 16:25:00
2021-02-26 17:30:00
2021-02-26 18:40:00
2021-02-26 19:35:00
2021-02-26 20:30:00
2021-02-26 21:55:00
2021-02-26 22:45:00
2021-02-26 23:25:00
2021-02-27 00:45:00
У меня есть наброски но хотелось бы услышать чужие идеи, возможно будет лучше решение.
Мой вариант: так как number фиксированный от 1 до 90, и минимальный отрезок 2ч между стартом и ендом можно заранее написать функцию что отдает массив с кол-во минут для каждых number (штук 5-8) и рандомить их. Но я сразу вижу проблему в том что эти числа не могут быть статическими ведь мы заранее не знаем сколько будет промежуток между start_time, end_time. Можно к примеру считать кол-во минут между концом и началом, делить на number и формировать +-1 +-2 +-3 к этому числу, но не очень красиво. Основная задача сгенерировать именно указанное number дат, чтобы они все были внутри указаных промежутков и разница между ними не была слишком разной (например где-то пару минут, где то час).
Язык не важен. Спасибо
Ответы (1 шт):
Случайный интервал пусть будет иметь длину в промежутке [1, 1 + v), где v определяет насколько разными могут быть интервалы. Для пяти интервалов и v = 2 получим (округление моё):
1.9 1.2 1.8 2.8 2.3
Сложим чтобы получились накопительные суммы (круглая сумма - случайность):
0 1.9 3.1 4.9 7.7 10
Разделим на последний элемент:
0 0.19 0.31 0.49 0.77 1
Линейно отобразим на интервал дат выраженный в секундах:
2021-02-26 12:00:00 -> 1614330000
2021-02-27 01:00:00 -> 1614376800
1614330000 1614338892 1614344508 1614352932 1614366036 1614376800
Значения в секундах округлим до ближайшего целого кратного 300 секундам:
1614330000 1614339000 1614344400 1614352800 1614366000 1614376800
Переведём во временные отметки:
2021-02-26 12:00:00
2021-02-26 14:30:00
2021-02-26 16:00:00
2021-02-26 18:20:00
2021-02-26 22:00:00
2021-02-27 01:00:00
Ниже пример кода на Питоне, который реализует этот алгоритм. Единственное отличие от примера - из списка удалёно последнее значение:
import datetime
import random
def accumulate(seq):
s = 0
yield s
for v in seq:
s += v
yield s
def round_to_grid(seq, origin, step):
return (origin + round((v - origin) / step) * step for v in seq)
def random_dts(start_time, end_time, step_time, rel_variance, n_intervals):
start = round(start_time.timestamp())
end = round(end_time.timestamp())
step = step_time.total_seconds()
duration = end - start
points = tuple(accumulate(1 + rel_variance * random.random() for _ in range(n_intervals)))
tss = tuple(start + p / points[-1] * duration for p in points[:-1])
return tuple(map(datetime.datetime.fromtimestamp, round_to_grid(tss, start, step)))
start_time = datetime.datetime(2021, 2, 26, 12)
end_time = datetime.datetime(2021, 2, 27, 1)
step_time = datetime.timedelta(minutes=5)
rel_variance = 1
n_intervals = 13
print(start_time, '-', end_time)
print()
for dt in random_dts(start_time, end_time, step_time, rel_variance, n_intervals):
print(dt)
$ python random-intervals.py 2021-02-26 12:00:00 - 2021-02-27 01:00:00 2021-02-26 12:00:00 2021-02-26 13:05:00 2021-02-26 14:00:00 2021-02-26 15:05:00 2021-02-26 16:15:00 2021-02-26 17:00:00 2021-02-26 18:10:00 2021-02-26 19:25:00 2021-02-26 20:10:00 2021-02-26 21:25:00 2021-02-26 22:05:00 2021-02-26 22:50:00 2021-02-26 23:50:00