rubychronic

Using Ruby Chronic To Calculate Offset Of Date


I use chronic to return parsed date objects like so:

last_pay_date = Date.parse(Chronic.parse('2011-11-04').strftime("%Y-%m-%d"))
two_weeks_ago = Date.parse(Chronic.parse("two weeks ago").strftime("%Y-%m-%d"))

puts last_pay_date # 2011-11-04
puts last_pay_date.class # Date
puts two_weeks_ago # 2011-10-24
puts two_weeks_ago.class # Date

But what I really want to do is date a date object like last_day_date and have the date two weeks before returned, like so:

two_weeks_ago = Date.parse(Chronic.parse("two weeks before #{last_pay_date}").strftime("%Y-%m-%d"))

This returns nil, as other attempts, both with variables and hard coded:

last_pay_date = Date.parse(Chronic.parse('2011-11-04').strftime("%Y-%m-%d"))
two_weeks_ago = Chronic.parse("two weeks before #{last_pay_date}")
puts two_weeks_ago.class #NilClass
puts two_weeks_ago.nil? #true

two_weeks_ago = Chronic.parse("2 weeks before 2011-11-04 05:00:00")
puts two_weeks_ago.class #NilClass
puts two_weeks_ago.nil?  #true

Questions:

  1. Can I use chronic to parse offsets of existing date objects? (eg. 14 days before this date instead of just +14 days).

  2. Can I use chronic to parse offsets of existing dates at all?

  3. How is this best accomplished, even if the solution is outside of chronic?

Edit: I am running Ruby 1.9.2 without rails. These are strait up ruby scripts, though I'll happily include any gems needed to do the job.


Solution

  • First off, is this Ruby 1.8 or 1.9? If 1.9, you have the Date#strptime method available, which makes parsing dates from strings pretty easy.

    Once you have your pay date, getting two weeks earlier from it is pretty easy, even without Chronic.

    Date.strptime("11/7/2011", "%m/%d/%Y").next_day(-14)

    If this is Ruby 1.8, then if ActiveSupport is available (ie, if this is a Rails app), there are Fixnum extensions that make this trivial.

    last_pay_date - 2.weeks

    However, I suspect that it is not available. In Ruby 1.8.7, Date#next_day is private, so you can't invoke it directly, but you can still invoke it if you really want to.

    Date.parse("11/7/2011").send(:next_day, -14)

    If you don't mind bypassing the private protection, this works just fine.