10

I am importing a CSV file that contains fields that need to be converted as follows:

  • "True" (string) -> true (boolean)
  • "False" (string) -> false (boolean)
  • "%m/%d/%Y" (string format) -> Date object
  • "%m/%d/%Y %I:%M:%S %p" (string format) -> DateTime object

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

2 Answers 2

13

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)
Sign up to request clarification or add additional context in comments.

1 Comment

If you use header_converters: :symbol, the case tests have to look like when :OrderUuid, :Exchange etc.
5

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.