Как написать генератор time_range
Всем привет! Помогите пожалуйста разобраться. Изучаю генераторы. Стоит задача Написать генератор time_range, который принимает два аргумента, время начала и время окончания: time_start, time_end - кортежи с тремя целыми числами hours, minutes, seconds.
На первой итерации time_range должен возвращать начальное время time_start, на каждой последующей итерации он возвращает предыдущее значение, увеличенное на одну секунду. Время окончания time_end не должно возвращаться.
Время окончания может быть меньше времени начала Пример.
t_range = time_range(time_start=(23, 59, 59),
time_end=(0, 0, 3))
next(t_range) == (0, 0, 0)
next(t_range) == (0, 0, 1)
next(t_range) == (0, 0, 2)
next(t_range)
# Error: StopIteration
Мой код
def time_range(time_start: tuple, time_end: tuple) -> tuple:
h_s, m_s, s_s = list(time_start)
while time_start != time_end:
s_s = s_s + 1
m_s = m_s + 1
q = h_s, m_s, s_s
yield tuple(q)
if h_s == 23:
h_s = 0
if m_s == 59:
m_s = 0
h_s += 1
if s_s == 59:
s_s = 0
m_s += 1
Код написал но чувствую что написал чушь, да и неработает корректно. Помогите пожалуйста. По возможности комментируя код
Ответы (4 шт):
Предлагаю следующий алгоритм:
- Примем момент
00:00:00дня, которому принадлежитstartTimeза X - Теперь переведем наше время
startTimeиз кортежа в число. Для этого нужно подсчитать количество секунд, прошедших с момента X. Получаем:startTimeSeconds = h * 3600 + m * 60 + s. - Также переведем в секунды
endTime. Теперь один нюанс: еслиendTimeпопал на день, следующий послеstartTime, тоendTimeSecondsокажется меньшеstartTimeSeconds. Но мы понимаем, что моментendTimeпроизошел через сутки + некоторое время (указанное вendTime) после момента X. Поэтому мы можем просто прибавить сутки (86400 секунд) кendTimeSecondsи исправить проблему. - Используем обычный
range(startTimeSeconds, endTimeSeconds), переводим каждое его значение из секунд в кортеж и возвращаем из генератора.
Реализация:
def timeRange(startTime: tuple, endTime: tuple) -> tuple:
def timeToSeconds(time_) -> int:
h, m, s = time_
return h * 3600 + m * 60 + s
def secondsToTime(seconds: int) -> tuple:
h = seconds // 3600 % 24 #добавил %, чтобы переводить 24 часа в 0 часов
m = seconds % 3600 // 60
s = seconds % 60
return (h, m, s)
startTimeSeconds = timeToSeconds(startTime)
endTimeSeconds = timeToSeconds(endTime)
if endTimeSeconds < startTimeSeconds:
endTimeSeconds += 86400
for secs in range(startTimeSeconds, endTimeSeconds):
yield secondsToTime(secs)
for t in timeRange((23, 59, 59), (0, 0, 3)):
print(t, end="; ")
Вывод:
(23, 59, 59); (0, 0, 0); (0, 0, 1); (0, 0, 2);
def time_range(time_start: tuple, time_end: tuple) -> tuple:
h_s, m_s, s_s = list(time_start)
while time_end != time_start:
q = h_s, m_s, s_s
yield tuple(q)
if h_s == 23 and m_s == 59 and s_s == 59:
h_s = 0
m_s = 0
s_s = -1
if m_s == 59 and s_s == 59:
h_s + 1
if s_s == 59:
h_s + 1
else:
s_s += 1
Вот еще вариант решения предложили. Довольно приммитивный но тоже рабочий
Функция next_second выдаёт время - секунду следующую за данной. Обычные счётчики с переносами:
def next_second(time_: tuple) -> tuple:
h, m, s = time_
if s < 59:
return h, m, s + 1 # same day, hour, minute, next second
if m < 59:
return h, m + 1, 0 # same day, hour, next minute
if h < 23:
return h + 1, 0, 0 # same day, next hour
return 0, 0, 0 # next day
time_range вызывает её в цикле:
def time_range(time_start: tuple, time_end: tuple) -> tuple:
t = time_start
while t != time_end:
yield t
t = next_second(t)
вы можете упростить свой код используя функцию divmod, примерно так:
def time_range(time_start,time_end):
while time_start!=time_end:
yield time_start
h,m,s = time_start
cm,s = divmod(s+1,60)
ch,m = divmod(m+cm,60)
h = (h+ch)%24
time_start = (h,m,s)
t_range = time_range((23, 59, 59),(0, 0, 3))
>>> [*t_range] # [(23, 59, 59), (0, 0, 0), (0, 0, 1), (0, 0, 2)]