Benjamin DigeonMy personal websitehttp://benjamindigeon.github.io/blog2016-07-06T22:00:00+00:00Benjamin DigeonNew blog and websitehttp://benjamindigeon.github.io/blog/2016-07-07-new-blog-and-website/2016-07-06T22:00:00+00:002023-04-12T11:38:23+00:00Benjamin Digeon<p>After many years with a old <a href="https://github.com/octopress/octopress">Octopress</a> blog who had only one post published Apr 27th, 2012.</p>
<p>I decided to redo entirely my blog and my website with <a href="https://middlemanapp.com/">Middleman</a>.</p>
<p>So what’s new since 2012 in my life, a few things actualy :</p>
<ul>
<li>The end of the world did not happen, but a good film was <a href="http://www.imdb.com/title/tt1213663/">released on the subject</a>.</li>
<li>I finished my studies.</li>
<li>I become a Freelance.</li>
<li>And i’m also a teacher at <a href="https://www.lewagon.com/fr/lille">Le Wagon</a>.</li>
</ul>
<p>I’ll try to do more blog post this year with more technical topics.</p>
<p>You can check some of <a href="/work">my work</a> as a Freelance, check <a href="/talks">my talks</a>, learn a <a href="/about">little more about myself</a> or just <a href="/contact">contact me</a>.</p>
<p>See you soon !</p>
Overlapping issues with time slots in Rubyhttp://benjamindigeon.github.io/blog/2016-01-29-overlapping-issues-with-time-slots-in-ruby/2016-01-28T23:00:00+00:002023-04-12T11:38:23+00:00Benjamin Digeon<p>When i was working for a client on a Ruby on Rails application dealing with multiples time slots,
i find myself with a rather complex problem.</p>
<h2>Time Slots</h2>
<p>To manage user schedules, the application has an object <code>TimeSlot</code> which represents a period of time between <code>start_date</code> and <code>end_date</code>.</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="k">class</span> <span class="nc">TimeSlot</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
<span class="n">belongs_to</span> <span class="ss">:user</span>
<span class="n">attr_accessible</span> <span class="ss">:end_date</span><span class="p">,</span> <span class="ss">:start_date</span>
<span class="k">end</span>
</code></pre></div>
<p>Simple enough right ? But the user can have several <code>TimeSlot</code> at the same time, and of course it can midway between two days.</p>
<p>And i need to calculate the number of hours used by days.</p>
<p>But i have a main problem : Overlapping time slots.</p>
<h2>Overlapping Issue</h2>
<h3>Range of DateTime</h3>
<p>Luckily we can solve this rather complex problem using the ruby
<a href="http://ruby-doc.org/core-1.9.3/Range.html">Range</a> class.</p>
<blockquote>
<p>A Range represents an interval—a set of values with a start and an end.</p>
<p>Ranges can be constructed using objects of any type, as long as the objects
can be compared using their <=> operator and they support the succ method
to return the next object in sequence.</p>
</blockquote>
<p>So we can convert all ours <code>TimeSlot</code> objects into <code>Range</code> of <code>DateTime</code> with a little helper.</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="k">def</span> <span class="nf">to_time_range</span>
<span class="p">(</span><span class="nb">self</span><span class="p">.</span><span class="nf">start_date</span><span class="o">..</span><span class="nb">self</span><span class="p">.</span><span class="nf">end_date</span><span class="p">)</span>
<span class="k">end</span>
</code></pre></div>
<p>We’re going to need some utility methods for check if a range overlap another
and for merging two range together.</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="k">def</span> <span class="nf">ranges_overlap?</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="n">a</span><span class="p">.</span><span class="nf">cover?</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="nf">begin</span><span class="p">)</span> <span class="o">||</span> <span class="n">b</span><span class="p">.</span><span class="nf">cover?</span><span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="nf">begin</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">merge_ranges</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="p">[</span><span class="n">a</span><span class="p">.</span><span class="nf">begin</span><span class="p">,</span> <span class="n">b</span><span class="p">.</span><span class="nf">begin</span><span class="p">].</span><span class="nf">min</span><span class="o">..</span><span class="p">[</span><span class="n">a</span><span class="p">.</span><span class="nf">end</span><span class="p">,</span> <span class="n">b</span><span class="p">.</span><span class="nf">end</span><span class="p">].</span><span class="nf">max</span>
<span class="k">end</span>
</code></pre></div>
<p>Now we just need to check inside the array of ranges, if some range overlap another and merge it.</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="k">def</span> <span class="nf">merge_overlapping_ranges</span><span class="p">(</span><span class="n">ranges</span><span class="p">)</span>
<span class="n">ranges</span><span class="p">.</span><span class="nf">sort_by</span><span class="p">(</span><span class="o">&</span><span class="ss">:begin</span><span class="p">).</span><span class="nf">inject</span><span class="p">([])</span> <span class="k">do</span> <span class="o">|</span><span class="n">ranges</span><span class="p">,</span> <span class="n">range</span><span class="o">|</span>
<span class="k">if</span> <span class="o">!</span><span class="n">ranges</span><span class="p">.</span><span class="nf">empty?</span> <span class="o">&&</span> <span class="n">ranges_overlap?</span><span class="p">(</span><span class="n">ranges</span><span class="p">.</span><span class="nf">last</span><span class="p">,</span> <span class="n">range</span><span class="p">)</span>
<span class="n">ranges</span><span class="p">[</span><span class="mi">0</span><span class="o">...-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="p">[</span><span class="n">merge_ranges</span><span class="p">(</span><span class="n">ranges</span><span class="p">.</span><span class="nf">last</span><span class="p">,</span> <span class="n">range</span><span class="p">)]</span>
<span class="k">else</span>
<span class="n">ranges</span> <span class="o">+</span> <span class="p">[</span><span class="n">range</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div>
<p>Thank to this <a href="http://stackoverflow.com/a/6018744/1361310">thread on Stackoverflow</a>.</p>