Archive for March, 2009

Detecting DateTime timespan overlap in Ruby

The Scenario
Let’s say you have an instance of DateTime that represents a starting time, and you have a duration that, when added to the starting time, represents an ending time.

Let’s say you have two such things and you want to know if they overlap (or intersect, or collide). For instance:

  1. March 29, 2009 @ 10:00am; 120 minutes
  2. March 29, 2009 @ 11:00am; 90 minutes

In this example there’s one hour of overlap in which #1 stretches from 10:00am – 12:00pm and #2 stretches from 11:00am – 12:30pm.

How to detect this? I’m sure there’s many clever ways, this way is mine.

We’re Gonna Need More Monkeys
First, we need to monkey-patch some core classes. Monkey-patching is fun, it makes us feel 31337.

As an aside: it’s patently absurd that DateTime doesn’t have a built-in function for converting to a Time instance (which is layered atop the patently absurd need for Ruby to have three unique Date/Time classes… but that’s another rant)….

Anyhow, let’s monkey-patch DateTime so it can return itself as an instance of Time:

class DateTime
  def to_time
    return Time.mktime( year, month, day, hour, min, sec )
  end
end

Now we need to alter Range to detect intersections with other ranges the way Array does with its & operator. We do this with Bill Siggelkow’s clever intersection() method:

class Range
  def intersection(range)
    res = self.to_a & range.to_a
    res.empty? ? nil : (res.first..res.last)
  end
  alias_method :&, :intersection
end

Ta-da; monkey-patching complete.

DateTime is the VB.Net of Date/Time Classes
You’ve likely inferred from the code above that we won’t be using DateTime for this jaunty action, but rather instances of Time. You’d be correct. DateTime is remarkably unsuited for this sort of thing. But since DateTime is so popular and prevalent that’s where we’ll start.

Our first moment of comparison will start right now to 60 minutes in the future:

a = DateTime.now
a_start = a.to_time
a_end = a_start + ( 60 * 60 )

Our second moment in time will start 30 minutes from now to 120 minutes in the future:

b = DateTime.now
b_start = b.to_time
b_start = b_start + ( 30 * 60 )
b_end = b_start + ( 120 * 60 )

Free-range Comparison
Now that we have our times, let’s convert them into ranges:

# Turn these into ranges
a_range = (a_start.to_i..a_end.to_i)
b_range = (b_start.to_i..b_end.to_i)

and compare them:

puts "Result A-B: #{a_range.intersection( b_range )}"

As of this writing the output is:

Result A-B: 1238340860..1238342660

which indicates an overlap/intersection/collision between the two timespans, displayed as seconds. Had there been no collision, nil would have been returned instead.

2 Comments »

chris on March 29th 2009 in /dev/random

Where’d the Comments Go?

After much consideration I’ve decided to close comments on all posts on this blog. I do this for a number of reasons:

  1. Once again dealing with the comment spam has become far too annoying. Akismet has been great but enough spam was slipping through that it had become a chore to manage each morning. Under different circumstances I might continue to put up with it but…
  2. The nature of this blog is such that for the most part the posts don’t generate comments-based discussion. I use it place primarily as a storage device for things I think might be useful later and often, via Google, other people find these posts and find them useful as well. Thus, most of the comments are of the “thank you” nature, which is immensely gratifying and I thoroughly enjoy them but massaging my own ego is not a good enough reason to wade through the spam each morning!
  3. And on the few posts that do warrant discussion or criticism I’m very much on board with reading your responses on your blogs (and thus I’ve left open trackback and pingback). It seems that people do tend to write more thoughtfully when writing from their own pulpit so if you’re so inclined then link back to me and let’s run discussions that way. It’ll be fun!

All that said, whether or not you’ve ever left a comment, thanks for reading!

Comments Off

chris on March 2nd 2009 in /dev/random

mysql2sqlite.rb

Introducing mysql2sqlite.rb, a Ruby script for converting MySQL databases into Sqlite databases.

Based on my googling of the web, I figure I’m one of perhaps five people in the world who’ve ever wanted to do this conversion but in case you’re number six, here you go.

Usage is pretty straight-forward. It can either be configured via command-line parameters or via a specified YAML file:

./mysql2sqlite.rb database_name database_user database_password
./mysql2sqlite.rb config.yaml

and it will spit out two files: one of the raw, converted SQL and one that is the Sqlite database. For instance, if your MySQL database was called ‘clients’ you’d end up with clients.sql and clients.sqlite.

For more details and source code see the mysql2sqlite.rb project on github.

Comments Off

chris on March 2nd 2009 in /dev/ruby