views:

876

answers:

4

I have strings like "84", "03" etc. that I want to convert to Date objects, but Date.new only takes the expanded 4-digit year as a parameter. I know it's simple to do, but I don't want to reinvent this wheel. Is there something that does this already? Either in standard Ruby or in ActiveSupport.

A: 

I don't know of such a component, and I don't know how you'd write one; how would it decide which two-digit prefix to use? Picking a single one blindly has certain demonstrated issues.

Depending on your application, you can probably find a reasonable heuristic to pick between 19 and 20 for a prefix, but the problem isn't solvable in general; there's not enough information.

David Seiler
A: 

Does doing this really make sense? When should you stop considering 19xx dates? There's no good way to get a 4-digit year from the last 2-digits of the year.

Stefan Kendall
If the string represented a birthday, just entered on a form, and you didn't care about people older than 99...yeah. There are cases where it isn't entirely crazy, I guess, but it's the sort of thing where you want to stop and say "am I solving the right problem here?"
David Seiler
That's an application-specific question. For example, if your application deals with records only going back to 1980, then you can use that as your cutoff. Or if it only does past data, or future, or...
derobert
Requirements change. Any solution to this problem would almost certainly break within a year.
Stefan Kendall
... or at least within a hundred years :-)
Jörg W Mittag
+3  A: 

Pick a cutoff date.

if year < cutoff, then year4 = "20" + year
else year4 = "19" + year

Also, fix the cause of the two digit year, or else your system won't be Y2K+cutoff compliant.

Steven
Yeah, that's what I ended up doing. I just wanted to know if there was some convenience method for this in some library. As a cutoff, I used 70, because 1970 is the Unix epoch (http://en.wikipedia.org/wiki/Unix_time).
obvio171
+1  A: 

Most 2 digit years are in the past, so a good cutoff to use is 30. For example, if someone types '66, they most likely mean 1966. In fact, this is also the cutoff that Excel uses when a two digit date is passed to a date cell.

I had an application that accepted tab delimited files from excel spreadsheets, and they often came with two-digit years. I wrote this ActiveRecord monkey patch to allow ActiveRecord to handle the two digit years for date fields:

class ActiveRecord::ConnectionAdapters::Column
  class << self
    protected
    # If a year comes in with two digits, let's try to guess whether it's in the
    # 20th or 21st century.  Typically, Ruby pivots this decision around the
    # year '69, but this is a bad guess.  Since most of our dates will arrive in
    # two digit format because of an Excel import, we should use the same pivot
    # value that Excel uses.  Excel pivots the decision around the year '30
    # which seems to be a better guess anyway.
    def new_date_with_two_digit_year_support(year, mon, mday)
      year += 2000 if (0..29).include? year
      year += 1900 if (30..99).include? year
      new_date_without_two_digit_year_support(year, mon, mday)
    end
    alias_method_chain :new_date, :two_digit_year_support
  end
end

This isn't exactly as generic as what the question asked for, but hopefully, it helps.

Ryan McGeary