Доступные помощники / классы для разбора диапазонов между двумя значениями времени - PullRequest
1 голос
/ 17 февраля 2020

Я пытался решить проблему, над которой я работаю, и не уверен, есть ли какие-либо инструменты / помощники, которые мне не хватает, чтобы помочь мне найти решение / указать мне правильное направление.

Я пытаюсь прочитать два значения времени: начало и конец. Оттуда мне нужно создать две новые переменные, одна из которых содержит минуты, которые находятся внутри временного диапазона, а другая - минуты вне диапазона.

Я пробовал несколько подходов, но, похоже, не могу следовать правильный путь или найти какие-либо полезные методы.

# Range to check between: (1pm - 7pm)(13 - 19)

@begin_time # Sun, 16 Feb 2020 05:11:33 UTC +00:00
@end_time   # Sun, 16 Feb 2020 19:43:42 UTC +00:00

#inital check to see if there are any values inside the range
@begin_time <= 13 && @end_time <= 17

# create an array containing all of the minutes between the two points, but not sure
# how I can compare these against the two times, as I don't believe you can create a static Time value
# total_range --> ["05:11", "05:12"... etc]
total_range = begin_time.strftime('%H:%M')..end_time.strftime('%H:%M').to_a

# could possibly generate the minutes in between the 1pm & 7pm values like above, compare the
# values - where the ones which exist = inside_values & the ones which don't = outside_values

# this would theoretically give me a basis of what I need, but doesn't look to be possible outside of the console
(@begin_time - CONST_ONE_PM_TIME) / 60
(CONST_SEVEN_PM_TIME - @end_time) / 60 

Если у кого-то есть какие-либо идеи или подсказки относительно того, что я мог бы ожидать в будущем, это будет с благодарностью:)

1 Ответ

0 голосов
/ 18 февраля 2020

Я расскажу о том, что по сути является той же проблемой, что и в вопросе, но структурирована по-другому. Не должно быть сложным изменить приведенный ниже код в соответствии с требованиями ОП.

Данные

Предположим, нам даны следующие данные.

require 'time'

SECS_PER_30_MINS = 1800
TIME_FMT = '%H:%M'

Временной интервал начинается с '9:00' и заканчивается '16:59:59', охватывая 16 30-минутные интервалы. Слот 0 от '9:00:00' до '9:29:59', слот 1 от '9:30:00' до '9:59:59' и т. Д.

start_time = Time.strptime('9:00', TIME_FMT)
  #=> 2020-02-17 09:00:00 -0800

slots = 16.times.map { |i| (start_time + i*SECS_PER_30_MINS)...
  (start_time + (i+1)*SECS_PER_30_MINS) }
  #=> [2020-02-17 09:00:00 -0800...2020-02-17 09:30:00 -0800,
  #    2020-02-17 09:30:00 -0800...2020-02-17 10:00:00 -0800,
  #    2020-02-17 10:00:00 -0800...2020-02-17 10:30:00 -0800,
  #    ...
  #    2020-02-17 16:30:00 -0800...2020-02-17 17:00:00 -0800] 

Обратите внимание, что это трехточечные диапазоны, поэтому правая конечная точка каждого диапазона не включена в диапазон.

Предположим, у нас есть пять событий со временем начала и окончания следующим образом:

event_times = [['08:00', '09:45'], ['08:30', '10:15'], ['12:34', '14:15'],
               ['11:30', '14:31'], ['15:30', '16:15']]

event_ranges = event_times.map do |s,e|
  Time.strptime(s, TIME_FMT)..Time.strptime(e, TIME_FMT)
end
  #=> [2020-02-17 08:00:00 -0800..2020-02-17 09:45:00 -0800,
  #    2020-02-17 08:30:00 -0800..2020-02-17 10:15:00 -0800,
  #    2020-02-17 12:34:00 -0800..2020-02-17 14:15:00 -0800,
  #    2020-02-17 11:30:00 -0800..2020-02-17 14:31:00 -0800,
  #    2020-02-17 15:30:00 -0800..2020-02-17 16:15:00 -0800] 

Код

def slot_availability(slots, event_ranges)
  event_ranges.each_with_object([true]*slots.size) do |er,slot_avail|
  slots.each_with_index do |s,i|
    slot_avail[i] = false if s.cover?(er.begin) || s.cover?(er.end) ||
      er.cover?(s)
    end 
  end
end

Пример

Для массивов slots и event_ranges, определенных ранее, получаем:

slot_availability(slots, event_ranges)
  #     9:00-  9:30- 10:00- 10:30- 11:00- 11:30- 12:00- 12:30-
  #=> [false, false, false,  true,  true, false, false, false,       
  #    false, false, false, false,  true, false, false,  true] 
  #    13:00- 13:30- 14:00- 14:30- 15:00- 15:30- 16:00- 16:30-

Пояснение

Я определил 16-элементный массив slot_avail, где slot_avail[i] равно true (иначе false), если слот i не покрыт каким-либо событием. Все эти значения инициализируются как true.

Затем метод перечисляет события для каждого вопроса о том, попадает ли какая-либо часть события в каждый слот i. Существует три модели, в которых событие может вмешиваться в слот:

eeeeeeee
    ssssssss  

    eeeeeeee
ssssssss  

eeeeeeeeeeee
  ssssssss  

См. Range # cover? .

Альтернатива использованию Time objects.

Использование Time объектов на самом деле стоит здесь очень мало. Ниже показано, как slots и event_ranges могут быть определены без использования Time объектов. Каждый из этих массивов содержит диапазоны, конечными точками которых являются номера минут с предыдущей полуночи. Метод slot_availability используется без изменений.

Мы начнем с создания простого вспомогательного метода.

def mins_since_midnight(str)
  str.split(':').map(&:to_i).zip([60, 1]).map { |a,x| a*x }.sum
end

mins_since_midnight('09:30')
  #=> 570 

event_times = [['08:00', '09:45'], ['08:30', '10:15'], ['12:34', '14:15'],
               ['11:30', '14:31'], ['15:30', '16:15']]

event_ranges = event_times.map do |b,e|
  mins_since_midnight(b)..mins_since_midnight(e)
end
  #=> [480..585, 510..615, 754..855, 690..871, 930..975]

start_time = mins_since_midnight('9:00')
  #=> 540

slots = 16.times.map do |i|
  start_time + 30*i...start_time + 30*(i+1)
end
  #=> [540...570, 570...600, 600...630,..., 990...1020]

slot_availability(slots, event_ranges)
  #=> [false, false, false, true,  true, false, false, false,
  #    false, false, false, false, true, false, false, true]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...