views:

575

answers:

3

Environment: Rails 2.2.2, Oracle 10g

Most of the columns declared "date" in my ActiveRecord models are exactly that: dates: they don't care about time at all.

So with a model declared thus:#

class MyDateOnlyModel < ActiveRecord::Migration
  def self.up
    create_table :my_date_only_model do |t|
      t.date :effective_date
      t.timestamps
    end
  end
end

writing a test like this:

test_date = Date.new(2008,12,05)
MyDateOnlyModel.create!(:effective_date => test_date)
assert_equal test_date, MyDateOnlyModel.find(:first).effective_date

should pass, shouldn't it? (Assuming I didn't mess anything up transcribing the above, of course)

But it doesn't - not quite. I get this:

<Fri, 05 Dec 2008> expected but was
<Fri, 05 Dec 2008 00:00:00 UTC +00:00>.

So I put a date into the database and got ... well what did I get?

puts MyDateOnlyModel.find(:first).eff_date.class

tells me I actually got a ActiveSupport::TimeWithZone. Which wasn't what I wanted at all.

Is there a simple way to tell ActiveRecord that some (not all) columns are Dates and only Dates?

UPDATE: more complaining...

Yes, I could use to_date:

assert_equal test_date, MyDateOnlyModel.find(:first).effective_date.to_date

works fine. But that's what I'm trying to avoid. I asked AR to make me a date, I want a date back.

And I could add a method to my class, effective_date_as_date - that works too. But surely it's not impossible to just get a date, dagnabbit.

PRE-ACCEPTANCE UPDATE

Eventually I realised why this was a particular problem with Oracle: there is no distinction between DATE and DATETIME, so ActiveRecord can't figure out unaided whether a time of zero means midnight (possibly with time zone corrections) or just the date. Bah. Stupid Oracle. So I'm going to have either to go down the plugin route, change my database (tempting, so very tempting) or continue with the to_date/to_time mess I have at present.

+1  A: 

Have you tried casting your attribute to a Date type?

The API describes to_date as follows:

Converts self to a Ruby Date object; time portion is discarded

test_date = Date.new(2008,12,05)
MyDateOnlyModel.create!(:effective_date => test_date)
assert_equal test_date, MyDateOnlyModel.find(:first).effective_date.to_date

Update:

Enhanced Oracle Adapter

It looks like this adapter might have a fix for your problem...

Set the option below and as a result columns with DATE in their name will be emulated as Date (and not as Time which is default for DATE columns in database)

ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
mwilliams
Yes. And yuck. Really, really yuck.I'm specifically trying to avoid having to write to_date all over my code. DRY and all that... I could override the accessor in my models where necessary, but yuck again.
Mike Woodhouse
What database are you using? There could be the possibility that the column type that a Date object gets mapped to is not what you think in your database. Very doubtful, but possible.
mwilliams
Oracle: it's a DATE column, which can take a time value as well. I seem to suffer unduly with dates and times whatever the DB, which makes me think I'm missing something... :)
Mike Woodhouse
Have you tried the Enhanced Oracle Adapter for ActiveRecord? I've used Rails with Oracle in the past and it's an interesting mix. It looks like though it may fix your problem! See my answer for link.
mwilliams
Months later: I'm using Oracle enhanced and having a better time of it.
Mike Woodhouse
A: 

I'm curious about why you need a Date object. If it quacks like a Date, does it matter? Or is there some issue with the ActiveSupport::TimeWithZone that is causing a bug?

nakajima
Yes, but it doesn't always quack exactly like a duck! Summer time offsets, for example, have a +0100 time on them, so they don't match a Date object without tedious conversion. Anyway, I specified :date as the type, and darn it, I want a Date!
Mike Woodhouse
+1  A: 

I have discovered a bug: you can't compare TimWithZone with a Date. Comparison fails, ruby tells me.

You're absolutely right: that's why there's all this horrid to_date/to_time stuff going on. I just can't believe I'm the only one who's feeling the pain, nor does it seem likely that it hasn't been addressed. But perhaps I'm wrong.
Mike Woodhouse