# Re: Time Window (#144)

**URL:** <https://www.ruby-forum.com/t/re-time-window-144/118126>\
**Category:** Ruby\
**Created:** [October 24, 2007, 3:06am UTC](https://www.ruby-forum.com/t/re-time-window-144/118126 "2007-10-24T03:06:03Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![jameskelly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/3ab097/32.png) [@jameskelly](https://www.ruby-forum.com/u/jameskelly)\
**Post date:** [October 24, 2007, 3:06am UTC](https://www.ruby-forum.com/t/re-time-window-144/118126/1 "2007-10-24T03:06:03Z")

</div>

Here’s my solution. It converts a time window into an array of arrays of  
ranges. Each range matches an interval of time (e.g.: 500…1700); each  
subarray contains all the ranges for a given day. I then wrote the  
simple Array#some method that returns true if the given predicate  
returns true for at least one of its elements, which I used to write  
TimeWindow#incude?.

$days = {“Sun”=\>0,  
“Mon”=\>1,  
“Tue”=\>2,  
“Wed”=\>3,  
“Thu”=\>4,  
“Fri”=\>5,  
“Sat”=\>6}

class Array  
def some  
each {|el| return true if yield el}  
false  
end  
end

class TimeWindow  
def initialize(win\_str)  
@times = ([nil]_7).map{[]}  
win\_str \<\< " " #In case of empty  
win\_str.split(/;/).each do |win|  
days\_str = win.match(/(((#{$days.keys.join(‘|’)}|)(  
|-)?)_)/)[0]…strip  
days = []  
days\_str.scan(/#{$days.keys.join(‘|’)}/) do |day|  
days \<\< $days[day]  
end  
days\_str.scan(/(#{$days.keys.join(‘|’)})-(#{$days.keys.join(‘|’)})/)  
do  
a = $days[$1]  
b = $days[$2]  
days += (a…(b \> a ? b : b+7))…to\_a.map{|d|d%7}  
end  
days = (0…6).to\_a if days.empty?

```
  times = []
  win.scan(/(\d{4})-(\d{4})/) do
    times << (($1.to_i)...($2.to_i))
  end
  times = [0..2400] if times.empty?

  days.each do |d|
    times.each do |t|
      @times[d] << t
    end
  end
end

def include?(time)
  @times[time.wday].some{|trange| trange === 

```

(time.hour\*100+time.min)}  
end  
end  
end

----- Original Message ----  
From: Ruby Q. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
To: ruby-talk ML [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
Sent: Friday, October 19, 2007 7:14:00 AM  
Subject: [QUIZ] Time Window (#144)

The three rules of Ruby Q.:

1. Please do not post any solutions or spoiler discussion for this  
quiz until  
48 hours have passed from the time on this message.

2… Support Ruby Q. by submitting ideas as often as you can:

[http://www.rubyquiz.com/](http://www.rubyquiz.com/)

1. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps  
everyone  
on Ruby T. follow the discussion. Please reply to the original quiz  
message,  
if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Brian C.

Write a Ruby class which can tell you whether the current time (or any  
given  
time) is within a particular “time window”. Time windows are defined by  
strings  
in the following format:

```
# 0700-0900 # every day between these times
# Sat Sun # all day Sat and Sun, no other

```

times  
# Sat Sun 0700-0900 # 0700-0900 on Sat and Sun only  
# Mon-Fri 0700-0900 # 0700-0900 on Monday to Friday  
only  
# Mon-Fri 0700-0900; Sat Sun # ditto plus all day Sat and Sun  
# Fri-Mon 0700-0900 # 0700-0900 on Fri Sat Sun Mon  
# Sat 0700-0800; Sun 0800-0900 # 0700-0800 on Sat, plus  
0800-0900 on Sun

Time ranges should exclude the upper bound, i.e. 0700-0900 is 07:00:00  
to  
08:59:59. An empty time window means “all times everyday”. Here are  
some test  
cases to make it clearer:

```
class TestTimeWindow < Test::Unit::TestCase
  def test_window_1
    w = TimeWindow.new("Sat-Sun; Mon Wed 0700-0900; Thu 0700-0900

```

1000-1200")

```
    assert ! w.include?(Time.mktime(2007,9,25,8,0,0)) # Tue
    assert w.include?(Time.mktime(2007,9,26,8,0,0)) # Wed
    assert ! w.include?(Time.mktime(2007,9,26,11,0,0))
    assert ! w.include?(Time.mktime(2007,9,27,6,59,59)) # Thu
    assert w.include?(Time.mktime(2007,9,27,7,0,0))
    assert w.include?(Time.mktime(2007,9,27,8,59,59))
    assert ! w.include?(Time.mktime(2007,9,27,9,0,0))
    assert w.include?(Time.mktime(2007,9,27,11,0,0))
    assert w.include?(Time.mktime(2007,9,29,11,0,0)) # Sat
    assert w.include?(Time.mktime(2007,9,29,0,0,0))
    assert w.include?(Time.mktime(2007,9,29,23,59,59))
  end

  def test_window_2
    w = TimeWindow.new("Fri-Mon")
    assert ! w.include?(Time.mktime(2007,9,27)) # Thu
    assert w.include?(Time.mktime(2007,9,28))
    assert w.include?(Time.mktime(2007,9,29))
    assert w.include?(Time.mktime(2007,9,30))
    assert w.include?(Time.mktime(2007,10,1))
    assert ! w.include?(Time.mktime(2007,10,2)) # Tue
  end

  def test_window_nil
    w = RDS::TimeWindow.new("")
    assert w.include?(Time.mktime(2007,9,25,1,2,3)) # all times
  end
end

```

---

<div class="post-metadata">

**Author:** ![jameskelly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/3ab097/32.png) [@jameskelly](https://www.ruby-forum.com/u/jameskelly)\
**Post date:** [October 24, 2007, 9:17am UTC](https://www.ruby-forum.com/t/re-time-window-144/118126/2 "2007-10-24T09:17:04Z")

</div>

On 10/24/07, James K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I then wrote the simple Array#some method that returns true if the given  
> predicate returns true for at least one of its elements, which I used to write  
> TimeWindow#incude?.

> class Array  
> def some  
> each {|el| return true if yield el}  
> false  
> end  
> end

Isn’t this the same as Enumerable#any?

Jesus.

---

<div class="post-metadata">

**Author:** ![jameskelly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/3ab097/32.png) [@jameskelly](https://www.ruby-forum.com/u/jameskelly)\
**Post date:** [October 24, 2007, 10:05am UTC](https://www.ruby-forum.com/t/re-time-window-144/118126/3 "2007-10-24T10:05:01Z")

</div>

That’s the same thought that I had. Assuming that any? didn’t exist,  
I am still fearful of adding methods to core classes. I think core  
classes should only be modified in special cases, like building a  
framework.

How do the rest of us feel about this?

- Philip

---

<div class="post-metadata">

**Author:** ![jameskelly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/3ab097/32.png) [@jameskelly](https://www.ruby-forum.com/u/jameskelly)\
**Post date:** [October 24, 2007, 2:15pm UTC](https://www.ruby-forum.com/t/re-time-window-144/118126/4 "2007-10-24T14:15:08Z")

</div>

On Oct 24, 2007, at 2:16 AM, Jesús Gabriel y Galán wrote:

> > ```
> > false
> > 
> > ```
> > 
> > end  
> > end
> 
> Isn’t this the same as Enumerable#any?

It sure is.

James Edward G. II

---

<div class="post-metadata">

**Author:** ![jameskelly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/3ab097/32.png) [@jameskelly](https://www.ruby-forum.com/u/jameskelly)\
**Post date:** [October 24, 2007, 2:18pm UTC](https://www.ruby-forum.com/t/re-time-window-144/118126/5 "2007-10-24T14:18:38Z")

</div>

On Oct 24, 2007, at 3:04 AM, Philip G. wrote:

> That’s the same thought that I had. Assuming that any? didn’t  
> exist, I am still fearful of adding methods to core classes. I  
> think core classes should only be modified in special cases, like  
> building a framework.
> 
> How do the rest of us feel about this?

Like most things, it’s just another tool in your belt. You’ll need  
to consider when to use it and when not to.

On the plus side, slowly transforming Ruby into the language of a  
problem is a powerful way to work. The minus is that you can make it  
hard to use your code with other Ruby solutions in the process.

You will need to decide when that’s a good trade-off and when it’s  
not. Ruby trusts you to make the choice.

James Edward G. II

---

<div class="post-metadata">

**Author:** ![jameskelly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/3ab097/32.png) [@jameskelly](https://www.ruby-forum.com/u/jameskelly)\
**Post date:** [October 24, 2007, 10:24am UTC](https://www.ruby-forum.com/t/re-time-window-144/118126/6 "2007-10-24T10:24:21Z")

</div>

On 10/24/07, Philip G. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> That’s the same thought that I had. Assuming that any? didn’t exist,  
> I am still fearful of adding methods to core classes. I think core  
> classes should only be modified in special cases, like building a  
> framework.
> 
> How do the rest of us feel about this?

Well, first of all it depends if you are building a library that  
someone will use, or just a program that will run independently. If  
it’s the former, even then I would think that just adding methods is  
OK, as long as the method makes sense. What should be done with really  
great care (or not at all) is modifying existing methods. But I’m  
fairly new to Ruby so take my opinion with a grain of salt.

Jesus.

---

<div class="post-metadata">

**Author:** ![jameskelly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/3ab097/32.png) [@jameskelly](https://www.ruby-forum.com/u/jameskelly)\
**Post date:** [October 24, 2007, 4:16pm UTC](https://www.ruby-forum.com/t/re-time-window-144/118126/7 "2007-10-24T16:16:56Z")

</div>

On Oct 24, 2007, at 9:10 AM, Ken B. wrote:

> > $days = {“Sun”=\>0,  
> > “Mon”=\>1,  
> > “Tue”=\>2,  
> > “Wed”=\>3,  
> > “Thu”=\>4,  
> > “Fri”=\>5,  
> > “Sat”=\>6}
> 
> I suggest using a constant rather than a global variable for this. You  
> can put the constant in the TimeWindow class.

This is also just an Array disguised as a Hash.

James Edward G. II

---

<div class="post-metadata">

**Author:** ![jameskelly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/3ab097/32.png) [@jameskelly](https://www.ruby-forum.com/u/jameskelly)\
**Post date:** [October 24, 2007, 4:11pm UTC](https://www.ruby-forum.com/t/re-time-window-144/118126/8 "2007-10-24T16:11:04Z")

</div>

On Wed, 24 Oct 2007 10:04:56 +0900, James K. wrote:

> ```
> "Wed"=>3,
> "Thu"=>4,
> "Fri"=>5,
> "Sat"=>6}
> 
> ```

I suggest using a constant rather than a global variable for this. You  
can put the constant in the TimeWindow class.

> class Array  
> def some  
> each {|el| return true if yield el}  
> false  
> end  
> end

This has already been discussed as being equal to Enumerable#any?

> class TimeWindow  
> def initialize(win\_str)  
> @times = ([nil]\*7).map{[]}

This is the same as Array.new(7){[]}, which is a more usual way to  
express this.

> ```
> win_str << " " #In case of empty
> win_str.split(/;/).each do |win|
> days_str = win.match(/(((#{$days.keys.join('|')}|)(
> |-)?)*)/)[0].strip days = []
> days_str.scan(/#{$days.keys.join('|')}/) do |day|
> days << $days[day]
> end
> days_str.scan(/(#{$days.keys.join('|')})-(#{$days.keys.join
> 
> ```

(’|’)})/)

> ```
> end
> @times[time.wday].some{|trange| trange ===
> (time.hour*100+time.min)}
> end
> 
> ```
> 
> end  
> end

Looks generally like my solution.

–Ken

---

<div class="post-metadata">

**Author:** ![jameskelly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/3ab097/32.png) [@jameskelly](https://www.ruby-forum.com/u/jameskelly)\
**Post date:** [October 25, 2007, 4:26am UTC](https://www.ruby-forum.com/t/re-time-window-144/118126/9 "2007-10-25T04:26:14Z")

</div>

On Oct 24, 9:16 am, James Edward G. II [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> > > subarray contains all the ranges for a given day. I then wrote the  
> > > “Sat”=\>6}
> 
> > I suggest using a constant rather than a global variable for this. You  
> > can put the constant in the TimeWindow class.
> 
> This is also just an Array disguised as a Hash.
> 
> James Edward G. II

It could be a lot worse. Which of us hasn’t run across something like  
this?

days = {  
0 =\> ‘Sun’,  
1 =\> ‘Mon’,  
2 =\> ‘Tue’,  
3 =\> ‘Wed’,  
4 =\> ‘Thu’,  
5 =\> ‘Fri’,  
6 =\> ‘Sat’,  
}
