使用Python通过win32com写入日期值时遇到问题
大约一年前,我写了一个Python脚本,这个脚本一直运行得不错。它从一个Oracle数据库中提取一些值,然后通过ArcGIS的arcpy模块使用搜索游标,把这些值写入Excel电子表格,接着用win32com来完成写入。
最近,我遇到了一个错误,我觉得我大概找到了问题所在。错误信息如下:
sheet.Cells(excelrow,excelcol).Value = rowItem
File "E:\sw_nt\Python27\ArcGIS10.1\lib\site-packages\win32com\client\__init__.py", line 474, in __setattr__
self._oleobj_.Invoke(*(args + (value,) + defArgs))
com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146827284), None)
这个错误发生在我从Oracle数据库提取一个特定值时,当它尝试写入Excel时出问题了,具体是在这一行:
sheet.Cells(excelrow,excelcol).Value = rowItem
我打印了rowItem的值和类型,结果是:
- 值 = 12/05/1193
- 类型 = datetime.datetime
到目前为止,脚本已经成功写入了大约一百行日期值,所以这个问题似乎只出现在这个特定的值上。我觉得Excel可能不喜欢这个日期中的年份1193。Excel在处理datetime.datetime值时,对年份有没有限制呢?我想不出其他原因,但这似乎是唯一的可能。
我知道这个值是错误的,因为我们这个数据库的记录不应该超过大约1890年。要改变这个值会花费更多的时间和精力,这不值得(我在政府工作,不拥有这个数据库,因此没有权限去更改它)。而且,我担心会遇到更多这样的错误,所以我宁愿处理这些错误,而不是去改动它们。
这是我快速写的一个更完整的脚本,用来测试这个问题:
import arcpy, win32com.client
# Set a variable to an empty excel instance
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = True
# Initialize a workbook within excel
book = excel.Workbooks.Add()
# Set first sheet in book and rename it for the report
sheet = book.Worksheets(1)
sheet.Columns(1).ColumnWidth = 30
x = r"path_to_Database"
excelrow = 1
for row in arcpy.SearchCursor(x):
sheet.Cells(excelrow,1).Value = row.WORK_START_DATE
excelrow +=1
我尝试把它转换成字符串:
str(rowItem)
但这又引发了一堆新的问题(其他值的Unicode错误等等),所以我想先解决这个特定的情况。有没有人能看出是什么导致了这个错误呢?
谢谢!
1 个回答
问题的关键,正如你所猜测的,是年份。我用以下代码确认了这一点:
>>> d = datetime.datetime(1193, 12, 5)
>>> sheet.Cells(1,1).Value = d
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\win32com\client\__init__.py", line 474, in __setattr__
self._oleobj_.Invoke(*(args + (value,) + defArgs))
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146827284), None)
>>> d = datetime.datetime(1993, 12, 5)
>>> sheet.Cells(1,1).Value = d
>>>
之所以会这样,可能是因为Excel的日期表示法最早只能到1/0/1900
。它其实是用数字来表示日期的,所以1990年之前的日期就得用负数来表示。Excel处理不了这种情况,因此会给你一个错误提示。
如果你无法更改数据源中的日期,那么接下来就要考虑你想怎么处理这个问题。有几种可能的解决方案,我建议使用try...except
。
try:
sheet.Cells(excelrow, 1).Value = row.WORK_START_DATE
except:
datetime.datetime(row.WORK_START_DATE.year + 800, row.WORK_START_DATE.month, row.WORK_START_DATE.day)
不幸的是,你不能直接捕捉这个错误,所以需要用一个简单的except
,但这样会让任何写入失败的日期多出800年。