ActiveRecord’s :datetime corresponds to ruby Time class.
But Time class can’t use old timestamps like 0001-01-01 00:00:00.
(ActiveRecord converts 0001-01-01 00:00:00 to 2001:01:01 00:00:00.)
So overwrite ActiveRecord to use DateTime class with :datetime.
Test Environment:
- Ubuntu 9.04
- ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
- rails 2.3.2 – 2.3.4
- mysql Ver 14.12 Distrib 5.0.75, for debian-linux-gnu (i486) using readline 5.2
Just put following code active_record_datetime_ext.rb into RAILS_ROOT/config/initializers
# -*- coding: utf-8 -*- # ActiveRecord column data type :datetime corresponds to ruby Time class. # # class CreateTasks < ActiveRecord::Migration # def self.up # create_table :tasks do |t| # t.column :title, :string, :null => false # t.column :deadline_at, :datetime, :null => false, :default => '0001-01-01 00:00:00' # end # end # end # # if set '0001-01-01 00:00:00' to datetime column, it'll be '2001-01-01 00:00:00' due to Time class. # # DateTime.parse('0001-01-01 00:00:00').strftime('%Y-%m-%d %H:%M:%S') # => 0001-01-01 00:00:00 # Time.parse('0001-01-01 00:00:00').strftime('%Y-%m-%d %H:%M:%S') # => 2001-01-01 00:00:00 # # So change ActiveRecord's :datetime Time to DateTime. unless 2 <= Rails::VERSION::MAJOR and 3 <= Rails::VERSION::MINOR # and 2 <= Rails::VERSION::TINY raise StandardError "required rails version 2.3.x or later but #{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}.#{Rails::VERSION::TINY}" end require 'active_record/connection_adapters/abstract/schema_definitions' module ActiveRecord module ConnectionAdapters class Column alias :klass_org :klass # return DateTime when :datetime, otherwise ActiveRecord default class. def klass if type == :datetime DateTime else klass_org end end alias :type_cast_org :type_cast def type_cast(value) if type == :datetime self.class.string_to_datetime(value) else type_cast_org(value) end end alias :type_cast_code_org :type_cast_code def type_cast_code(var_name) if type == :datetime "#{self.class.name}.string_to_datetime(#{var_name})" else type_cast_code_org(var_name) end end class << self def string_to_datetime(string) return string unless string.is_a?(String) return nil if string.empty? fast_string_to_datetime(string) || fallback_string_to_datetime(string) end protected def new_datetime(year, mon, mday, hour, min, sec, microsec) # Treat 0000-00-00 00:00:00 as nil. offset = Base.default_timezone.to_sym == :local ? local_offset : 0 ::DateTime.civil(year, mon, mday, hour, min, sec, offset) end def fast_string_to_datetime(string) if string =~ Format::ISO_DATETIME microsec = ($7.to_f * 1_000_000).to_i new_datetime $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec end end def fallback_string_to_datetime(string) datetime_hash = DateTime._parse(string) datetime_hash[:sec_fraction] = microseconds(datetime_hash) new_datetime(*datetime_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction)) end end end end end
Related posts:
- [Ruby on Rails] uninitialized constant ActiveSupport::~::ForRspec Today I got an error below with rake. What happened?...
- Lucky Star on Rails A few months ago, suddenly I got a message with...
- [Ruby on Rails] Didn't apply edited view file With Ruby on Rails 2.3.2 Sometimes, edit rails view file...
- [JRuby on Rails on GAE/J] how-to put rubygems into a jar file to get around file limitations GAE (Google App Engine) has a limit number to the...
Related posts brought to you by Yet Another Related Posts Plugin.



英語
日本語
Entries
Comments