working with UTC and datamapper
February 23rd, 2009 • Uncategorized
# stick this in the before_app_loads block in init.rb
# if this maybe finds its way into dm-more, this wouldn't be necessary anymore
module DataMapper
module Types
class UtcDateTime < DataMapper::Type
primitive DateTime
def self.load(v, property)
if v.nil?
nil
elsif v.is_a?(DateTime)
::DateTime.new(v.year, v.month, v.day, v.hour, v.min, v.sec, 0)
else
raise ArgumentError.new("+value+ must be nil or a DateTime")
end
end
def self.dump(v, property)
if v.nil?
nil
elsif v.is_a?(String)
Time.parse(v).utc.to_datetime
elsif v.is_a?(DateTime)
Time.parse(v.to_s).utc.to_datetime
else
raise ArgumentError.new("+value+ must be nil or a String or a DateTime")
end
end
end # class UtcDateTime
UTCDateTime = UtcDateTime
end # module Types
end # module DataMapper
module DataMapper
module Timestamp
def set_timestamps
return unless dirty? || new_record?
TIMESTAMP_PROPERTIES.each do |name,(_type,proc)|
if model.properties.has_property?(name)
self.send("#{name}=", proc.call(self, model.properties[name]))
end
end
end
def utc_timestamped?
self.class.utc_timestamped?
end
module ClassMethods
def timestamps(*names)
raise ArgumentError, 'You need to pass at least one argument' if names.empty?
# if the last element in names is a Hash:
# extract this hash and look for a :utc key
opts = names.last.is_a?(Hash) ? names.pop : nil
utc_possible = names.include?(:created_at) || names.include?(:updated_at)
@utc = opts && opts[:utc] && utc_possible
names.each do |name|
case name
when *TIMESTAMP_PROPERTIES.keys
type = TIMESTAMP_PROPERTIES[name].first
property name, type, :nullable => false, :auto_validation => false
if type == DateTime && @utc # UTC makes no sense for Date
define_method "#{name}=", UTC::PROPERTY_WRITER.call(name, type)
define_method "#{name}", UTC::PROPERTY_READER.call(name, type)
end
when :at
timestamps(:created_at, :updated_at, :utc => @utc)
when :on
timestamps(:created_on, :updated_on) # UTC makes no sense for Date
else
raise InvalidTimestampName, "Invalid timestamp property name '#{name}'"
end
end
end
def utc_timestamped?
!!@utc
end
end
module UTC
PROPERTY_WRITER = lambda { |name, type|
typecast = "to_#{type.name.downcase}"
lambda { |dt| attribute_set(name, Time.parse(dt.to_s).utc.send(typecast)) }
}
PROPERTY_READER = lambda { |name, type|
lambda {
return nil unless dt = attribute_get(name)
if type == Date
Date.new(dt.year, dt.month, dt.day, 0)
elsif type == DateTime
DateTime.new(dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec, 0)
else
nil
end
}
}
end
end
end
3 Responses (Add Your Comment)
-
-
Oh hey, you have a typo on line #26. “value” should just be “v”
Thank you for this! I was just in the process of writing something similar myself to make DM work with my rails app smoothly