我有一个Excel电子表格,其中包含一个包含小的%f.2值的字段,例如1.2,1.07,2.3等,由于某种原因,openpyxl将这些单元格读取为1900日期。我已经多次看到这个问题已被提出,但通常这些用户期待约会,并且正在获得虚假日期。我期待一个值,通常x <10.0并且我得到大约30-40%'坏'数据(读作时间日期),而另一次将其作为数值读取。
我正在使用迭代器,所以我做了一个简单的ws.iter_rows()调用来一次拉一行数据。我试图将此“强制转换”为先前创建的包含数值的变量,但这并没有太大的好处。
有没有人建议如何克服这个零星的问题。如果这是一个已知的错误,是否有任何已知的解决方法?
我发现如果我将文件存储为csv,并将其重新打开为csv,然后将其重新存储为xlsx,我将得到一个可以正确读取的文件。虽然这有助于调试代码,但我需要一个我的客户可以使用的解决方案,而无需跳过这些环节。
我认为如果列格式不正确,它将适用于所有元素,因此间歇性地发生这种情况会令人困惑。
import openpyxl
from openpyxl import load_workbook
# Source workbook - wb
wb = load_workbook(filename = r'C:\data\TEST.xlsx' , use_iterators = True)
ws = wb.get_sheet_by_name(name ='QuoteFile ')
for row in ws.iter_rows():
print(row[0].internal_value ,row[3].internal_value ,row[4].internal_value ,row[5].internal_value)
print('Done')
这是我从excel表中看到的输入
20015 2.13 1.2 08/01/11
20015 5.03 1.2 08/01/11
20015 5.03 1.2 08/01/11
20015 5.51 1.2 08/01/11
20015 8.13 1.2 08/01/11
20015 5.60 1.2 08/01/11
20015 5.03 1.2 08/01/11
20015 1.50 1.2 08/01/11
20015 1.50 1.2 08/01/11
20015 1.50 1.2 08/01/11
20015 1.50 1.2 08/01/11
20015 1.50 1.2 08/01/11
20015 1.50 1.2 08/01/11
这是我的输出,你可以看到前七行表示第二个字段是1900年的日期,而行8-13正确地将字段显示为数字字段:
20015.0 1900-01-02 03:07:12 1.2 2011-08-01 00:00:00
20015.0 1900-01-05 00:43:12 1.2 2011-08-01 00:00:00
20015.0 1900-01-05 00:43:12 1.2 2011-08-01 00:00:00
20015.0 1900-01-05 12:14:24 1.2 2011-08-01 00:00:00
20015.0 1900-01-08 03:07:12 1.2 2011-08-01 00:00:00
20015.0 1900-01-05 14:24:00 1.2 2011-08-01 00:00:00
20015.0 1900-01-05 00:43:12 1.2 2011-08-01 00:00:00
20015.0 1.5 1.2 2011-08-01 00:00:00
20015.0 1.5 1.2 2011-08-01 00:00:00
20015.0 1.5 1.2 2011-08-01 00:00:00
20015.0 1.5 1.2 2011-08-01 00:00:00
20015.0 1.5 1.2 2011-08-01 00:00:00
20015.0 1.5 1.2 2011-08-01 00:00:00
使用python 3.3和openpyxl 1.6.2
答案 0 :(得分:2)
免责声明:我不知道如何使用openpyxl。但是,您大多只需要担心datetime
模块。
如果您知道哪些行应该是数字,您可以尝试这样的代码将Excel日期格式转换为浮点数,如果它是数字则忽略它:
import datetime
import openpyxl
from openpyxl import load_workbook
# Source workbook - wb
wb = load_workbook(filename = r'C:\data\TEST.xlsx' , use_iterators=True)
ws = wb.get_sheet_by_name(name='QuoteFile ')
If val's a number, return it. Otherwise, take the difference between the datetime
and 1899-12-31 00:00:00. The way the datetimes work is they're internally a float,
being the number of days since the start of 1900. We get the number of seconds in
the delta (done through subtraction) and divide that by 86400 (the number of seconds
in a day).
def forcefloat(val):
"""If val's a number, return it. Otherwise, take the difference between the
datetime and 1899-12-31 00:00:00. The way the datetimes work is they're
internally a float, being the number of days since the start of 1900.
We get the number of seconds in the delta (done through subtraction)
and divide that by 86400 (the number of seconds in a day)."""
if isinstance(val, (int, float)):
return val
assert isinstance(val, datetime.datetime)
return (val - datetime.datetime(1899,12,31,0,0,0)).total_seconds() / 86400
for row in ws.iter_rows():
print(
row[0].internal_value,
forcefloat(row[3].internal_value),
row[4].internal_value,
row[5].internal_value,
)
print('Done')
不完全是优雅的解决方案,但它确实有效。