Complex Range Reference: Determine Available Time Ranges Based on Schedules and Required Times

So I am trying to create a booking app and am running into some problems.

Basically I have a set of Assignments for a client:

appointments = [
    Mon, 29 Dec 2014 11:00:00 PST -08:00..Mon, 29 Dec 2014 12:30:00 PST -08:00,
    Mon, 29 Dec 2014 09:00:00 PST -08:00..Mon, 29 Dec 2014 10:30:00 PST -08:00,
    Mon, 29 Dec 2014 14:00:00 PST -08:00..Mon, 29 Dec 2014 15:30:00 PST -08:00
]

      

and then I will book this time:

Mon, 29 Dec 2014 14:00:00 PST -08:00

      

who is looking for a proposed service that takes an hour and 30 minutes, so the time range I want to book is:

requested_time_range = Mon, 29 Dec 2014 14:00:00 PST -08:00..Mon, 29 Dec 2014 15:30:00 PST -08:00

      

and available time for the day:

full_time_range = Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 16:00:00 PST -08:00

      

Using the range_operators gem parameter ( https://github.com/monocle/range_operators ), I can do this:

a1 = full_time_range - appointments.first

      

which will result in (range operation -

will result in an array of ranges):

[
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 10:59:59 PST -08:00,
    Mon, 29 Dec 2014 12:30:01 PST -08:00..Mon, 29 Dec 2014 15:00:00 PST -08:00
]

      

so looping through all the appointments and subtracting them from full_time_range and then formatting the array so that we have a flat array, I come up with:

available_times = [
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 10:59:59 PST -08:00,
    Mon, 29 Dec 2014 12:30:01 PST -08:00..Mon, 29 Dec 2014 15:00:00 PST -08:00,
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 08:59:59 PST -08:00,
    Mon, 29 Dec 2014 10:30:01 PST -08:00..Mon, 29 Dec 2014 15:00:00 PST -08:00,
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 13:59:59 PST -08:00,
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 08:59:59 PST -08:00,
    Mon, 29 Dec 2014 10:30:01 PST -08:00..Mon, 29 Dec 2014 15:00:00 PST -08:00,
    Mon, 29 Dec 2014 07:30:00 PST -08:00..Mon, 29 Dec 2014 13:59:59 PST -08:00 
]

      

Now I cannot figure out how to find requested_time_range

in available_times

. In most cases, this is not true, because request_time_range is sometimes inside one element of the available_times array, sometimes not.

Is there an exact way to find out if it is available requested_time_range

in my case? (I think I need to do something with accessible_names, but I don't know what

+3


source to share


3 answers


You need to change request_time_range to max

be 1 second (or more) less than currently.

booking_time = some_time # "Mon, 29 Dec 2014 14:00:00 PST -08:00" in your case
# 5399.seconds equals (1.5.hours - 1.second )
request_time_range = booking_time..(booking_time + 5399.seconds)

      



Then the work should :

available_times.any? do |time_range|
  (time_range.min <= requested_time_range.min) &&
  (time_range.max >= requested_time_range.max)
end

      

+1


source


I had fun doing it my own way ... it may or may not be for you, and there is room for improvement in speed, but here's what I came up with. You can integrate it into your situation however you want.

EDIT: I also haven't tested this for all scenarios ...




range_comparison.rb

####
## Use case: Are you available between Nov 19th and 30th?
## No, I'm only available between Dec 1st and 2nd
## 
## requested_dates = DateTime.parse("Nov 19, 2014")..DateTime.parse("Nov 30, 2014")
## available_dates = DateTime.parse("Dec 1, 2014")..DateTime.parse("Dec 2, 2014")
## p 'Dates intersect on: '
## p requested_dates.first_coincide_with(available_dates)
####

class Range
  def first_coincide_with(compared_range)
    # Barf if it anything other than a Range
    raise(ArgumentError, 'Only Ranges are permitted!') unless compared_range.kind_of?(Range)
    # Find the closest starting point for searching
    min = [self.min, compared_range.min].max
    # Find the end time
    max = [self.max, compared_range.max].min
    # Quickly exit if they are completely out of bounds to one another
    return if min > max

    # Now start searching for first available unit
    # Hopefully they know to use this in a strictly Integer Range... :)
    pos = min
    until pos > max
      return pos if pos >= min
      pos += 1
    end
    nil
  end
end

      

+1


source


The problem is that the assignment is not comprehensive. End times should be excluded, so when plotting ranges use ...

instead ..

.

Imagine that you also have 9 to 10:30

a 10:30 to 12

. With the ranges included, you end up with a graph that looks like this:

|------|
       |------|

      

Instead of excluding the last value:

|------|------

      

Without overlap, when checking that the range array does not contain a new range, ensure that no range contains the beginning or end of a new range.

def include?(ranges, range)
  ranges.any?{ |r| r.cover?(range.begin) || r.cover?(range.end) }
end

def valid?(appointments, appointment)
  !include?(appointments, appointment)
end

      

Note the difference between Range # include? and Range Cover #? ... You want cover?

.

EDIT . To find available times, sort the ranges and take non-zero gaps.

def available_ranges(ranges)
  pairs = ranges.sort_by(&:begin).each_cons(2)
  new_ranges = pairs.map do |r1, r2|
    r1.end...r2.begin
  end
  new_ranges.reject{ |r| r.begin == r.end }
end

      

0


source







All Articles