Suppose you have the following file:
textfield,datetimefield,numfield
foo,2008-07-01 17:50:55.004688,1
bar,2008-07-02 17:50:55.004688,2
The Rub
You are asking how to use converters.
My example defines the usage of a new converter mytime
.
The converter my_time tries to build a time object if possible.
#Define test data
src = <<csv
textfield,datetimefield,numfield
foo,2008-07-01 17:50:55.004688,1
bar,2008-07-02 17:50:55.004688,2
csv
require 'csv'
require 'time'
CSV::Converters[:mytime] = lambda{|s|
begin
Time.parse(s)
rescue ArgumentError
s
end
}
csv = CSV(src, :headers => true, :converters => [:mytime])
csv.each do |row|
print "#{row}"
the_date = row['datetimefield'].to_date
end
Using this technique, you may also define a converter to create a date from time-like strings. This solution also keeps all other converters.
#define test data
src = <<csv
textfield,datetimefield,numfield
foo,2008-07-01 17:50:55.004688,1
bar,2008-07-02 17:50:55.004688,2
csv
require 'csv'
require 'time'
CSV::Converters[:time2date] = lambda{|s|
begin
Time.parse(s).to_date
rescue ArgumentError
s
end
}
csv = CSV(src, :headers => true, :converters => CSV::Converters.keys + [:time2date])
csv.each do |row|
print "#{row}"
p row['datetimefield'] #Date-field
end
Works!!! Executable version of code:
#Define test data
src =
"textfield,datetimefield,numfield\n" +
"foo,2008-07-01 17:50:55.004688,1\n" +
"bar,2008-07-02 17:50:55.004688,2"
require 'csv'
require 'time'
CSV::Converters[:mytime] = lambda{|s|
begin
Time.parse(s)
rescue ArgumentError
s
end
}
csv = CSV(src, :headers => true, :converters => [:mytime])
array_of_hash_objects = csv.to_a.map {|row| row.to_hash }
array_of_hash_objects.each do |row|
print "#{row}"
the_date = row['datetimefield'].to_date
puts
print the_date
puts
end
CSV::Converters[:time2date] = lambda{|s|
begin
Time.parse(s).to_date
rescue ArgumentError
s
end
}
csv = CSV(src, :headers => true, :converters => CSV::Converters.keys + [:time2date])
array_of_hash_objects = csv.to_a.map {|row| row.to_hash }
array_of_hash_objects.each do |row|
print "#{row}"
puts
p row['datetimefield'] #Date-field
end
=============
{"textfield"=>"foo", "datetimefield"=>2008-07-01 17:50:55 -0400, "numfield"=>"1"}
2008-07-01
{"textfield"=>"bar", "datetimefield"=>2008-07-02 17:50:55 -0400, "numfield"=>"2"}
2008-07-02
{"textfield"=>"foo", "datetimefield"=>2008-07-01 17:50:55 -0400, "numfield"=>1}
2008-07-01 17:50:55 -0400
{"textfield"=>"bar", "datetimefield"=>2008-07-02 17:50:55 -0400, "numfield"=>2}
2008-07-02 17:50:55 -0400
Your date times don't match the CSV::DateTimeMatcher
regexp that CSV uses to decide whether it should attempt a date time conversion. By the looks of it it's doing so because of the fractional seconds you've got.
You could either overwrite that constant or write your own converter (DateTime.parse
seems happy with your strings)