Problems with Chronic gem and Daylight savings time

I love the Chronic natural language date parsing gem. I’ve used it in most of my projects. Unfortunately, it has some problems with daylight savings time.

If you haven’t used Chronic before, this is what you expect:

 Chronic.parse("monday 8:00am",:now=>Time.parse("2007-10-12 9:00am"))

When you run that, you get “Mon Oct 15 08:00:00 -0500 2007” just like you would expect” Let’s run it for today!

Chronic.parse("monday 8:00am",:now=>Time.parse("2007-10-29 9:00am"))

Run that and you get back nil! What happened? Internally, Chronic uses a Time object built using Time.construct(year,month,day) to keep track of the start of the day. It iterates over time by adding ` 24 * 60 * 60` seconds to it. Normally that works fine, but it breaks down on November 4th, which has an extra hour due to daylight savings time. Here’s my fix:

class Chronic::RepeaterDayName < Chronic::Repeater
  def next(pointer)
  super
  
  direction = pointer == :future ? 1 : -1
  
    if !@current_date
      @current_date = Date.new(@now.year,@now.month,@now.day)
      @current_date += direction 

      day_num = symbol_to_number(@type)
    
      while @current_date.wday != day_num
        @current_date += direction 
      end
    else
      @current_date += direction * 7 
    end
    next_date = @current_date.succ
    Chronic::Span.new(Time.construct(@current_date.year, @current_date.month, @current_date.day),   Time.construct(next_date.year,next_date.month,next_date.day))
  end
end

I just used a Date instance in place of a time instance. I created a Time instance once the correct date is found. The moral of this story is simple. Dates and times are very different things. While you can sometimes treat them interchangeably, doing so may come back to haunt you.