I'm using ArcGIS 10.3.1 for Desktop to test before writing an answer to Entering date with arcpy.GetParameterAsText()? I have written the test code below that I am running against a test feature class (testFC
) with four line features to try and update its dateField
with a constant date value of "01.07.2015".
import arcpy
dmyString = "01.07.2015"
fc = r"C:\temp\test.gdb\testFC"
item = "dateField"
dmyDate = datetime.datetime.strptime(dmyString,'%d.%m.%Y')
print dmyDate
arcpy.CalculateField_management(fc,item,dmyDate,"PYTHON")
with arcpy.da.SearchCursor(fc,[item]) as cursor:
for row in cursor:
print row[0]
I think the above should work, and from the output below you can see that the date object (dmyDate
) seems to be created fine, but the values written to each of the four features are not what I would expect.
>>> ================================ RESTART ================================
>>>
2015-07-01 00:00:00
1899-12-30 00:00:00
1899-12-30 00:00:00
1899-12-30 00:00:00
1899-12-30 00:00:00
>>>
Can someone explain why 1899-12-30 00:00:00
is being written instead of 2015-07-01 00:00:00
?
The attribute table displays as below:
If I replace the CalculateField line above with either:
arcpy.CalculateField_management(fc,item,"date '2015-07-01 00:00:00'","PYTHON")
or
arcpy.CalculateField_management(fc,item,"date '2015/07/01 00:00:00'","PYTHON")
as per @Vince's comments I receive an error:
Traceback (most recent call last):
File "C:\temp\test.py", line 11, in
arcpy.CalculateField_management(fc,item,"date '2015-07-01 00:00:00'","PYTHON")
File "C:\Program Files (x86)\ArcGIS\Desktop10.3\ArcPy\arcpy\management.py", line 3457, in CalculateField
raise e
ExecuteError: ERROR 000539: SyntaxError: invalid syntax (, line 1)
Failed to execute (CalculateField).
Answer
The code below demonstrates how to get this to work using code very similar to that in the question, but I recommend also reviewing the detailed explanation that follows in order to understand why it works:
import arcpy
dmyString = "01.07.2015"
d,m,Y = dmyString.split(".")
dmyDate = datetime.datetime(int(Y),int(m),int(d))
epoch = datetime.datetime(1899, 12, 30)
days = (dmyDate - epoch).days
fc = r"C:\temp\test.gdb\testFC"
item = "dateField"
print dmyDate
arcpy.CalculateField_management(fc,item,days,"PYTHON")
print "\nOutput:"
with arcpy.da.SearchCursor(fc,[item]) as cursor:
for row in cursor:
print row[0]
produces:
>>> ================================ RESTART ================================
>>>
2015-07-01 00:00:00
Output:
2015-07-01 00:00:00
2015-07-01 00:00:00
2015-07-01 00:00:00
2015-07-01 00:00:00
>>>
Don't be disturbed that you see 1/07/2015 (instead of 7/01/2015) above - PolyGeo's Windows settings are for Australia where they tend to use dd/mm/YYYY.
Why it works:
Alright, so CalculateField is expecting a the number of days since the epoch (1899-12-30 as @Vince pointed out) whereas UpdateCursor accepts either a datetime.datetime() object or delta days.
import arcpy, time
arcpy.env.workspace = r"C:\Users\Paul\Desktop\testing.gdb"
def compare(calc, cursor):
#Create new fields
arcpy.DeleteField_management("dater", ["date1", "date2"])
arcpy.AddField_management("dater", "date1", "DATE")
arcpy.AddField_management("dater", "date2", "DATE")
#Let's try CalcField
arcpy.CalculateField_management("dater", "date1", calc, "PYTHON")
#And now Ucursor
with arcpy.da.UpdateCursor("dater", ["date2"]) as rows:
for row in rows:
rows.updateRow([cursor])
#Let's take a look.....
with arcpy.da.SearchCursor("dater", ["date1", "date2"]) as rows:
for row in rows:
print("Calc:\t{}\tUcursor:\t{}".format(*row))
date1 = datetime.datetime(2015, 7, 10)
#Days since the epoch
epoch = datetime.datetime(1899, 12, 30)
days = (date1 - epoch).days
print("Datetime to both:\n")
compare(date1, date1)
print("\nDelta days to calc, datetime to Ucursor:\n")
compare(days, date1)
print("\nDelta days to both::\n")
compare(days, days)
The Result:
Datetime to both:
Calc: 1899-12-30 00:00:00 Ucursor: 2015-07-10 00:00:00
Calc: 1899-12-30 00:00:00 Ucursor: 2015-07-10 00:00:00
Calc: 1899-12-30 00:00:00 Ucursor: 2015-07-10 00:00:00
Delta days to calc, datetime to Ucursor:
Calc: 2015-07-10 00:00:00 Ucursor: 2015-07-10 00:00:00
Calc: 2015-07-10 00:00:00 Ucursor: 2015-07-10 00:00:00
Calc: 2015-07-10 00:00:00 Ucursor: 2015-07-10 00:00:00
Delta days to both::
Calc: 2015-07-10 00:00:00 Ucursor: 2015-07-10 00:00:00
Calc: 2015-07-10 00:00:00 Ucursor: 2015-07-10 00:00:00
Calc: 2015-07-10 00:00:00 Ucursor: 2015-07-10 00:00:00
Very interesting stuff! Clearly, cursors are the preferred choice when dealing with dates. That or the VBScript
parser for FieldCalc.
No comments:
Post a Comment