I need to write the output of a search cursor to a csv file. I stole an idea from this Stackexchange post that uses list comprehension and it works great. The problem is one of my fields is a date field, and it's goofing up the works.
import arcpy
fc = r'\Path\to\my\featureclass'
fields = ['UNIQUE_ID','asset_id','Condition','Year_Installed','Carto_ID',
'Pave_Area','Pave_Width','Length','AM_Asset_ID','Lanes','OCI_Date']
lines = [row for row in arcpy.da.SearchCursor(fc,fields)]
Here is what one of the tuples in the lines list looks like:
('10100922','PWOPS_pave00024318',84,1989,7366264,8800.60992698,35.0,
251.44599791,None,None, datetime.datetime(2019, 2, 1, 0, 0))
Notice how the field OCI_date comes from the search cursor. I get what it's doing with the datetime.datetime() method, but how can I avoid that? I guess I could just append every row to the list as individual tuple elements and for the date, format in a fashion that works, but maybe there is a better way?
Solved! Go to Solution.
import arcpy
from datetime import datetime
fc = r'\Path\to\my\featureclass'
fields = ['UNIQUE_ID','asset_id','Condition','Year_Installed','Carto_ID',
'Pave_Area','Pave_Width','Length','AM_Asset_ID','Lanes','OCI_Date']
lines = [dtFormat(row) for row in arcpy.da.SearchCursor(fc,fields)]
def dtFormat(row):
try:
OCI_Date_index = row[row.index('OCI_Date')]
row[OCI_Date_index] = row[OCI_Date_index].strftime('%m/%d/%Y')
return row
except AttributeError:
return row
Try using datetime strftime to format the date as a string in whatever style you want. You should probably do this in a traditional for loop rather than list comprehension.
That's what I meant by I guess I could just append every row to the list as individual tuple elements. I was hoping to keep in the list comprehension format, but I suspect opening an empty list and appending a formatted tuple to it is the only option...
You could keep the list comprehension to create lines and then go back over lines with a for loop to format the datetime objects. Or write a helper function to check the value for a date and return the formatted date string during the list comprehension.
import arcpy
from datetime import datetime
fc = r'\Path\to\my\featureclass'
fields = ['UNIQUE_ID','asset_id','Condition','Year_Installed','Carto_ID',
'Pave_Area','Pave_Width','Length','AM_Asset_ID','Lanes','OCI_Date']
lines = [dtFormat(row) for row in arcpy.da.SearchCursor(fc,fields)]
def dtFormat(row):
try:
OCI_Date_index = row[row.index('OCI_Date')]
row[OCI_Date_index] = row[OCI_Date_index].strftime('%m/%d/%Y')
return row
except AttributeError:
return row
Sweet. Thanks!
Completely untested, but I think you get the idea. 🙂
A wild guess, if you would consider tab delimited:
lines = ["\t".join(str(i) for i in row) for row in arcpy.da.SearchCursor("MyFeature",["*"])]
You could join with a comma instead of the tab. Just a quick test in desktop, so it is 2.7 python.
You could go with a nested list comprehension:
lines = [
[col.strftime('%m/%d/%Y') if isinstance(col, datetime.datetime) else col for col in row]
for row
in arcpy.da.SearchCursor(fc, fields)
]
Another way:
fc = r'path/to/featureclass'
dateformat = '%Y-%m-%d'
datefields = [d.name for d in arcpy.ListFields(fc, field_type='Date')]
recs = []
with arcpy.da.SearchCursor(fc, ['OID@', 'TheDate']) as rows:
for row in rows:
recs += [r if f not in datefields else r.strftime(dateformat) for r, f in zip(row, rows.fields)]
print(recs)
Or as a iterator:
def datecursor(fc, dateformat, *args, **kwargs):
datefields = [d.name for d in arcpy.ListFields(fc, field_type='Date')]
with arcpy.da.SearchCursor(fc, *args, **kwargs) as rows:
for row in rows:
yield [r if f not in datefields else r.strftime(dateformat) for r, f in zip(row, rows.fields)]
fc = r'path/to/featureclass'
dateformat = '%Y-%m-%d'
recs = [row for row in datecursor(fc, dateformat, ['OID@', 'TheDate'])]