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.