Ruby strptime не работает при чтении файла
У меня есть следующий код:
require 'date'
f = File.open(filepath)
f.each_with_index do |line, i|
a, b = line.split("\t")
d = DateTime.strptime(a, '%m/%d/%Y %I:%M %p')
puts "#{a} --- #{b}"
break unless i < 100
end
И я получаю следующую ошибку:
c_reader.rb:10:in `strptime': invalid date (ArgumentError)
from c_reader.rb:10:in `block in <main>'
from c_reader.rb:6:in `each'
from c_reader.rb:6:in `each_with_index'
from c_reader.rb:6:in `<main>'
Содержание файла:
30.01.2014 1:00 1251,6 30.01.2014 2:00 AM 1248 30.01.2014 3:00 AM 1246.32 30.01.2014 4:00 AM 1242.96 30.01.2014 5:00 утра 1282.08 30.01.2014 6:00 1293.84 30.01.2014 7:00 1307.04 30.01.2014 8:00 1337,76 30.01.2014 9:00 1357.92
Если я наберу это в IRB, он отлично работает:
DateTime.strptime("1/30/2014 2:00 PM", '%m/%d/%Y %I:%M %p')
Может кто-нибудь, пожалуйста, скажите мне, что здесь происходит?
1 ответ
Данные вашего примера не соответствуют тому, что ваш код пытается обработать, поэтому я настроил это для этого. Кроме того, нужно что-то, чтобы показать, что AM / PM был удостоен чести.
С этими настройками ваш код работает нормально. strptime
возвращает действительные объекты DateTime.
require 'date'
[
"1/30/2014 1:00 AM\t1251.6",
"1/30/2014 2:00 AM\t1248",
"1/30/2014 3:00 PM\t1246.32",
"1/30/2014 4:00 PM\t1242.96",
].each do |line|
a, b = line.split("\t")
puts DateTime.strptime(a, '%m/%d/%Y %I:%M %p')
end
# >> 2014-01-30T01:00:00+00:00
# >> 2014-01-30T02:00:00+00:00
# >> 2014-01-30T15:00:00+00:00
# >> 2014-01-30T16:00:00+00:00
Ваш файл данных имеет спецификацию ("метка порядка следования байтов"). Первые два байта указывают "порядковый номер" порядка байтов в файле. Кроме того, каждый символ фактически занимает два байта. Это файл UTF-16LE, потому что fffe
имеет недостающий бит (0xfe
==0b11111110
) означает, что конец пары байтов меньше первого байта. Если бы это былоfeff
это будет "big-endian":
0000000: коэффициент 3100 2f00 3300 3000 2f00 3200 3000..1./. 3.0./.2.0.
Ruby не знает, что с ними делать, потому что ожидает по умолчанию UTF-8. Чтобы это исправить, нужно указать Ruby, как это интерпретировать. Посмотрите документацию дляIO.new
чтобы увидеть, как определить кодировки. Ruby предполагает, что данные будут в формате UTF-8, поэтому входящие данные должны быть преобразованы из UTF-16LE в UTF-8. Это один из способов сделать это:
require 'date'
File.open(
"test.csv",
"rb:BOM|UTF-16LE:UTF-8"
) do |fi|
fi.each_with_index do |line, i|
a, b = line.split("\t")
d = DateTime.strptime(a, '%m/%d/%Y %I:%M %p')
puts "#{ 1 + i } #{a} --- #{b}"
break unless i < 100
end
end
Запуск, что выводит:
1 30.01.2014 1:00 AM --- 1251,6 2 1/30/2014 2:00 AM --- 1248 3 30.01.2014 3:00 AM --- 1246.32 4 30.01.2014 4: 00:00 --- 1242.96 5 30.01.2014 5:00 AM --- 1282.08 6 1/30/2014 6:00 AM --- 1293.84 7 1/30/2014 7:00 AM --- 1307.04 8 1/30/2014 8:00 AM --- 1337,76 9 1/30/2014 9:00 AM --- 1357,92