Skip to content

Commit 801a8fa

Browse files
demimismopythonicrubyist
authored andcommitted
Fix inconsistent DateTime conversion (#65)
* Always return a Time object for DateTime cells * Fix specs for DateTime parsing
1 parent ce7e21a commit 801a8fa

6 files changed

Lines changed: 62 additions & 24 deletions

File tree

lib/creek/styles/converter.rb

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ def self.call(value, type, style, options = {})
6060
value.to_i
6161
when :float, :percentage
6262
value.to_f
63-
when :date, :time, :date_time
63+
when :date
6464
convert_date(value, options)
65+
when :time, :date_time
66+
convert_datetime(value, options)
6567
when :bignum
6668
convert_bignum(value)
6769

@@ -71,22 +73,17 @@ def self.call(value, type, style, options = {})
7173
end
7274
end
7375

74-
# the trickiest. note that all these formats can vary on
75-
# whether they actually contain a date, time, or datetime.
7676
def self.convert_date(value, options)
77-
value = value.to_f
78-
days_since_date_system_start = value.to_i
79-
fraction_of_24 = value - days_since_date_system_start
77+
date = base_date(options) + value.to_i
78+
yyyy, mm, dd = date.strftime('%Y-%m-%d').split('-')
8079

81-
# http://stackoverflow.com/questions/10559767/how-to-convert-ms-excel-date-from-float-to-date-format-in-ruby
82-
date = options.fetch(:base_date, Date.new(1899, 12, 30)) + days_since_date_system_start
80+
::Date.new(yyyy.to_i, mm.to_i, dd.to_i)
81+
end
8382

84-
if fraction_of_24 > 0 # there is a time associated
85-
seconds = (fraction_of_24 * 86400).round
86-
return Time.utc(date.year, date.month, date.day) + seconds
87-
else
88-
return date
89-
end
83+
def self.convert_datetime(value, options)
84+
date = base_date(options) + value.to_f.round(6)
85+
86+
round_datetime(date.strftime('%Y-%m-%d %H:%M:%S.%N'))
9087
end
9188

9289
def self.convert_bignum(value)
@@ -96,6 +93,18 @@ def self.convert_bignum(value)
9693
value.to_f
9794
end
9895
end
96+
97+
private
98+
99+
def self.base_date(options)
100+
options.fetch(:base_date, Date.new(1899, 12, 30))
101+
end
102+
103+
def self.round_datetime(datetime_string)
104+
/(?<yyyy>\d+)-(?<mm>\d+)-(?<dd>\d+) (?<hh>\d+):(?<mi>\d+):(?<ss>\d+.\d+)/ =~ datetime_string
105+
106+
::Time.new(yyyy.to_i, mm.to_i, dd.to_i, hh.to_i, mi.to_i, ss.to_r).round(0)
107+
end
99108
end
100109
end
101110
end

spec/fixtures/sample_dates.xlsx

9.14 KB
Binary file not shown.
6.34 KB
Binary file not shown.
6.79 KB
Binary file not shown.

spec/styles/converter_spec.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@
33
describe Creek::Styles::Converter do
44

55
describe :call do
6+
67
def convert(value, type, style)
78
Creek::Styles::Converter.call(value, type, style)
89
end
910

11+
describe :date do
12+
it "works" do
13+
expect(convert('41275', 'n', :date)).to eq(Date.new(2013,01,01))
14+
end
15+
end
16+
1017
describe :date_time do
1118
it "works" do
12-
expect(convert('41275', 'n', :date_time)).to eq(Date.new(2013,01,01))
19+
expect(convert('41275', 'n', :date_time)).to eq(Time.new(2013,01,01))
1320
end
1421
end
1522
end

spec/test_spec.rb

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,34 @@
2626
end
2727
end
2828

29+
describe 'Creek parsing dates on a sample XLSX file' do
30+
before(:all) do
31+
@creek = Creek::Book.new 'spec/fixtures/sample_dates.xlsx'
32+
33+
@expected_datetime_rows = [
34+
{'A3' => 'Date', 'B3' => Date.parse('2018-01-01')},
35+
{'A4' => 'Datetime 00:00:00', 'B4' => Time.parse('2018-01-01 00:00:00')},
36+
{'A5' => 'Datetime', 'B5' => Time.parse('2018-01-01 23:59:59')}]
37+
end
38+
39+
after(:all) do
40+
@creek.close
41+
end
42+
43+
it 'parses dates successfully' do
44+
rows = Array.new
45+
row_count = 0
46+
@creek.sheets[0].rows.each do |row|
47+
rows << row
48+
row_count += 1
49+
end
50+
51+
(2..5).each do |number|
52+
expect(rows[number]).to eq(@expected_datetime_rows[number-2])
53+
end
54+
end
55+
end
56+
2957
describe 'Creek parsing a sample XLSX file' do
3058
before(:all) do
3159
@creek = Creek::Book.new 'spec/fixtures/sample.xlsx'
@@ -63,15 +91,9 @@
6391
row_count += 1
6492
end
6593

66-
expect(rows[0]).to eq(@expected_rows[0])
67-
expect(rows[1]).to eq(@expected_rows[1])
68-
expect(rows[2]).to eq(@expected_rows[2])
69-
expect(rows[3]).to eq(@expected_rows[3])
70-
expect(rows[4]).to eq(@expected_rows[4])
71-
expect(rows[5]).to eq(@expected_rows[5])
72-
expect(rows[6]).to eq(@expected_rows[6])
73-
expect(rows[7]).to eq(@expected_rows[7])
74-
expect(rows[8]).to eq(@expected_rows[8])
94+
(0..8).each do |number|
95+
expect(rows[number]).to eq(@expected_rows[number])
96+
end
7597
expect(row_count).to eq(9)
7698
end
7799

0 commit comments

Comments
 (0)