I am attempting to identify utility poles that require inspection. Currently, the feature has a field containing the pole's birthmark in a string format and an installation date field (with the majority being null values at the moment). The birthmark field is formatted as 40-5-18 where 40 is the height, 5 is the class, and 18 is the year. I need a Python solution to capture the last two digits of the birth mark string and either update the installation date field to some arbitrary date in the corresponding year or select values (< or > a particular year) using a mathematical operator. The ultimate goal is to be able to query poles due for inspection based on the date of the birthmark or installation.


| improve this question | | | | |
  • 2
    Welcome to GIS StackExchange! As a new user please take a moment to take the tour to learn about our focused Q&A format. Please note that this question is likely to be closed if you don't include a code snippet of what you've tried already, since you are asking for python-based solution. Please edit your question to include that code. If you haven't tried code yet, have you tried to do this within something like the Field Calculator in ArcGIS? (And what version of ArcMap / ArcGIS Pro are you using?) – smiller Nov 16 '18 at 16:58
  • I am not familiar enough with the syntax to attempt this without direction. I am using ArcGIS Pro 2.2. – Matt C Nov 16 '18 at 17:04
  • 1
    One thing to do whenever you are trying to determine the arcpy syntax is first to identify the tools you would use interactively. One advantage to using ArcGIS Pro is that once you run the tool, you can right click on the output and copy the code. Interactively, I would start with creating a field to store the last two digits (installation year). The reason I'd do this rather than update the installation date field is simply for error checking. Then I'd use Field Calculator (syntax of !birthmark![-2:] should get the last two characters in the birthmark field, assuming it is string.) – smiller Nov 16 '18 at 17:08
  • Once you have worked out the details of how to approach it using interactive tools, you can convert this to arcpy. (Right click the results from Field Calculator and copy the code, or look at the code snippets in the documentation: pro.arcgis.com/en/pro-app/tool-reference/data-management/…) – smiller Nov 16 '18 at 17:11
  • How would I convert it from string to integer so that the boolean operators will work when performing a selection query? – Matt C Nov 16 '18 at 17:15

As this solution only needs to be performed once and not repeated over a number of shapefiles, a Field Calculator based solution in ArcGIS Pro should work.

Because we want to add the leading 19 or 20 (to produce years such as 1999 or 2004), we need a slightly more complicated Field Calculator expression. You can create a function within a code block, and then pass the column to that function within the Field Calculator. Note the variable names within the codeblock won't have the surrounding exclamation marks that you will see in the field names for the field calculator.

I assumed that the earliest date is about 100 years ago 1919, so this will have to be modified to figure out the correct year if that's not the case.

Note that numbers with leading zeroes are considered octal in Python and you get unexpected results from converting using 'int'. I've included a workaround.


def extractyear(hgtclassyr):
    yrroot = hgtclassyr.split('-')[-1]  # split on dashes and take the last one
    yrroot = yrroot.rjust(2,'0') # adds 0 padding to two characters
    if yrroot.startswith('0'): 
        year = int('20' + yrroot) # converts to integer e.g. 2004, 2009
    elif int(yrroot) > 18:
        year = int('19' + yrroot) # converts to integer e.g. 1956
        year = int('20' + yrroot) # e.g. 2018
    return year

In the Field Calculator window, enter the codeblock as above and for the expression, enter


For your additional question, if you wanted to return a date instead of an integer-valued year:

import datetime
def extractyear(hgtclassyr):
    yrroot = hgtclassyr.split('-')[-1]  # split on dashes and take the last one
    yrroot = yrroot.rjust(2,'0') # adds 0 padding to two characters
    if yrroot.startswith('0'): 
        year = '20' + yrroot # e.g. 2004, 2009
    elif int(yrroot) > 18:
        year = '19' + yrroot # e.g. 1956
        year = '20' + yrroot # e.g. 2018
    dt_obj = datetime.datetime.strptime(year, '%Y')  #defaults to January 1st of the year.
    return dt_obj  
| improve this answer | | | | |
  • I ran into the issue with octal number interpretation in Python2, but can't replicate today. (This workaround may not be necessary.) – smiller Nov 16 '18 at 18:19
  • ERROR 000539: Traceback (most recent call last): File "<expression>", line 1, in <module> File "<string>", line 8, in extractyear ValueError: invalid literal for int() with base 10: '20-4' – Matt C Nov 16 '18 at 19:19
  • So in this case the entry was something like 40-5-4 instead of 40-5-04. Let's use split instead (by '-') to avoid these cases, and add in length checking. – smiller Nov 16 '18 at 19:23
  • used zero padding instead of length checking. Code in edited answer above. – smiller Nov 16 '18 at 19:30
  • Same error. Is there a way for the code to skip the features that aren't in like formatting and finish running? – Matt C Nov 16 '18 at 19:36

You can use the datetime module and update the date field with values from the text field:

import arcpy
from datetime import datetime

fc = 'Formulas' #Change
stringfield = 'birthmark' #Change
datefield = 'instdate' #Change

with arcpy.da.UpdateCursor(fc,[stringfield,datefield]) as cursor:
    for row in cursor:

enter image description here

| improve this answer | | | | |

Another possibility, if your years are all between 1950 and 2049, you can use this one-line shortcut directly in the field calculator in python mode:

2000 + int(!BirthMark![-2:]) - (int(!BirthMark![-2:])/50) * 100

However, this would not work for years before 1950.

| improve this answer | | | | |
  • This produced some issues. As an example, an 04 pole returned as 1996. – Matt C Nov 16 '18 at 19:26
  • Oh, I forgot to mention, the destination field needs to be of type integer – FSimardGIS Nov 16 '18 at 20:15
  • After checking other comments I realized that the issue might be the fact that you have some values with missing trailing zero, like this : 40-5-4, so that's why. The last 2 characters must have been '-4', leading to a negative number. In this case, I think you'd better use smiller's solution. – FSimardGIS Nov 16 '18 at 20:20

Not the answer you're looking for? Browse other questions tagged or ask your own question.