Reputation: 969
I am importing a CSV file that contains fields that need to be converted as follows:
The default CSV converters don't match the Date and DateTime fields. This method below seems to work, but wonder if there is a better way, possibly by override the matching pattern used by the converters?
require 'csv'
require 'date'
src = <<csv
active,date_created,date_modified
"True","03/12/2012","03/12/2012 2:14:23 PM"
"False","01/25/2011","03/12/2013 3:14:27 AM"
csv
CSV::Converters[:my_converters] = lambda{|field|
begin
case field.to_s
when "True"
true
when "False"
false
when /^\d{2}\/\d{2}\/\d{4}$/
Date.strptime(field,"%m/%d/%Y")
else
DateTime.strptime(field,"%m/%d/%Y %I:%M:%S %p")
end
rescue ArgumentError
field
end
}
csv = CSV(src, :headers => true, :converters => [:my_converters])
csv.each{|row| puts row}
true,2012-03-12,2012-03-12T14:14:23+00:00
false,2011-01-25,2013-03-12T03:14:27+00:00
Upvotes: 10
Views: 2686
Reputation: 506
Convert fields accordingly field's name (header's name)
custom_converter = lambda { |value, field_info|
case field_info.header
when 'OrderUuid', 'Exchange', 'Type', 'OrderType'
value.to_s
when 'Quantity', 'Limit', 'CommissionPaid', 'Price'
value.to_f
when 'Opened', 'Closed'
Time.zone.parse(value)
else
fail("Unknown field name #{field_info.inspect}=#{value}")
end
}
CSV.parse(content, headers: :first_row, converters: [custom_converter]).map(&:to_h)
Upvotes: 13
Reputation: 22325
This is the proper way to do things if the default converters aren't sufficient. My only suggestion would be to separate your converters into different lambdas since the CSV library is already designed to test each field against an array of converters (making your case
redundant).
But if this is just a quick one-off script, what you have is good enough.
Upvotes: 5