I’ve posted a bug report:

<https://github.com/rails/rails/issues/6816>

On Jun 20, 2012, at 5:26 PM, Guyren Howe wrote:

> On Jun 20, 2012, at 1:32 PM, cschulte22 wrote:
> 
>> What version of rails?  Can you post a few lines of the code?  The way that 
>> you're setting your timestamp field may be causing the problem...
> 
> 3.1.3
> 
> I’m not doing anything particularly clever. I’m creating a record based on 
> params. I don’t explicitly set the timestamp, so it’s just being set by Rails 
> automatically.
> 
> I can see in the database that the timestamp is set to local time.
> 
> I read all over the place how Rails will stores all values in UTC, but this 
> just doesn’t appear to be true. The relevant logic is in 
> ActiveRecord::ConnectionAdapters::Quoting:
> 
>      def quoted_date(value)
>        if value.acts_like?(:time)
>          zone_conversion_method = ActiveRecord::Base.default_timezone == :utc 
> ? :getutc : :getlocal
>          value.respond_to?(zone_conversion_method) ? 
> value.send(zone_conversion_method) : value
>        else
>          value
>        end.to_s(:db)
>      end
> 
> On the third line of the above, my ActiveRecord::Base.default_timezone is not 
> :utc, so it does :get local. It’s writing the local time to the column.
> 
> The corresponding logic when reading a timestamp is in 
> ActiveRecord::AttributeMethods::TimeZoneConversion::ClassMethods::define_method_attribute:
> 
>          def define_method_attribute(attr_name)
>            if create_time_zone_conversion_attribute?(attr_name, 
> columns_hash[attr_name])
>              method_body, line = <<-EOV, __LINE__ + 1
>                def _#{attr_name}
>                  cached = @attributes_cache['#{attr_name}']
>                  return cached if cached
>                  time = _read_attribute('#{attr_name}')
>                  @attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? 
> time.in_time_zone : time
>                end
>                alias #{attr_name} _#{attr_name}
>              EOV
>              generated_attribute_methods.module_eval(method_body, __FILE__, 
> line)
>            else
>              super
>            end
>          end
> 
> this calls ActiveRecord::AttributeMethods::Read::ClassMethods:: 
> _read_attribute:
> 
>      def _read_attribute(attr_name)
>        attr_name = attr_name.to_s
>        attr_name = self.class.primary_key if attr_name == 'id'
>        value = @attributes[attr_name]
>        unless value.nil?
>          if column = column_for_attribute(attr_name)
>            if unserializable_attribute?(attr_name, column)
>              unserialize_attribute(attr_name)
>            else
>              column.type_cast(value)
>            end
>          else
>            value
>          end
>        end
>      end
> 
> which trampolines down to fast_string_to_time:
> 
>          # Doesn't handle time zones.
>          def fast_string_to_time(string)
>            if string =~ Format::ISO_DATETIME
>              microsec = ($7.to_f * 1_000_000).to_i
>              new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, 
> microsec
>            end
>          end
> 
> which gets back to define_method_attribute, which then does:
> 
>                  @attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? 
> time.in_time_zone : time
> 
> this pulls the default time zone (Pacific) and converts my value to Pacific. 
> But the value in the database is already in Pacific time, so I’m screwed.
> 
> Is it just me, or is there a bug here? The thing that bothers me is that this 
> seems like a pretty major issue not to have been reported and fixed before 
> now.

-- 
SD Ruby mailing list
[email protected]
http://groups.google.com/group/sdruby

Reply via email to