Memcached uses local time instead of configured time zone

Hi all,
I noticed a strange behavior with Memcached store.
The first time I store an model object, Memcached correctly store the
timestamps, using the configured time zone (UTC for me).

When I update that object and cache it again, Memcached uses the server
local time for the updated_at attribute, instead of UTC.

comment.updated_at # => "2008-08-25 10:06:09" # UTC
cached_comment.updated_at # => 2008-08-25 12:06:09" # local time

I believe it's a bug, because it doesn't behaves the same with other
caching systems (:file_store and :memory_store). I experienced this
problem with Rails 2.1.0 and current edge.

I already opened a ticket:
http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/900-memcached-uses-local-time-instead-of-configured-time-zone

Luca Guidi wrote:

Hi all,
I noticed a strange behavior with Memcached store.
The first time I store an model object, Memcached correctly store the
timestamps, using the configured time zone (UTC for me).

When I update that object and cache it again, Memcached uses the server
local time for the updated_at attribute, instead of UTC.

comment.updated_at # => "2008-08-25 10:06:09" # UTC
cached_comment.updated_at # => 2008-08-25 12:06:09" # local time

I believe it's a bug, because it doesn't behaves the same with other
caching systems (:file_store and :memory_store). I experienced this
problem with Rails 2.1.0 and current edge.

It seems unlikely to me that the root cause of this bug is in the
memcache store, but rather something not handling marshaling correctly.
Are you using the rails 2.1 timezone functionality? Perhaps the
timezone aware attributes?

Can you reproduce it just by writing the date / time value to memcache
on its own?

It seems like Marshal can't properly (un)serialize models with
@changed_attributes, maybe because timestamps inside that hash, are
instances of Time instead of TimeWithZone.

http://pastie.org/259472

Michael Koziarski wrote:

It seems unlikely to me that the root cause of this bug is in the
memcache store, but rather something not handling marshaling correctly.
Are you using the rails 2.1 timezone functionality? Perhaps the
timezone aware attributes?

Can you reproduce it just by writing the date / time value to memcache
on its own?

We've been exploring this further on the Lighthouse ticket -- indeed,
the problem isn't specific to memcache; it's an issue with marshaling.

The root of the problem is, Ruby's odd/broken marshaling of Time
instances -- it will always return a Time.local instance, even if you
give it a Time.utc instance.

When you marshal and unmarshal an ActiveRecord instance, Time.utc
objects in the attributes hash will be returned as Time.local
instances -- these Time.local instances are equivalent (in seconds
since epoch) to the original Time.utc instances, but they have
different #to_s(:db) outputs, so they'll output the wrong values to
the db.

I'm not sure of the best way to fix this. One idea would be, create
custom marshal behavior for AR instances that keeps track of Time.utc
instances in the attributes hash, and coerces them back to #utc on
unmarshaling.

I attached a patch to the Lighthouse ticket.