Select to view content in your preferred language

Code in python the equivalent of the VB Format function

7977
26
01-14-2011 03:32 AM
JoseSanchez
Frequent Contributor
Hi all

I am using ArcGIs 9.3 and Model Bulder. I was able to code a calculate field in VB that formats a field as follows Format("08.00.00") and converts it to "08:00:00 AM"

How can I do the same thing in Python (phyton 3 or python)?

Please advise!
Tags (2)
0 Kudos
26 Replies
MustafaELHalwagy
Emerging Contributor
OK, i will say you the story from the start, i want to make a (tip) to make a buffering raster by spatial analyst tool, so to make this, we must be open (Raster Calc) and then type this syntax in the field raster calc: EXPAND ([Streams_rr2m],10,LIST,1.2 ) it was made by vb, so tha spatial analyst command, EXPAND: it mean that fatten up the zones, which is reputed to be the raster equivalent of the vector produce BUFFER. so i  just need only, if this proper syntax in Python field, i do not know this exactly.
thank you
0 Kudos
MustafaELHalwagy
Emerging Contributor
vb function is: EXPAND ([Streams_rr2m],10,LIST,1.2 )
0 Kudos
ChrisSnyder
Honored Contributor
Mustafa needs help with the new map algebra syntax (v10 syntax). I haven't gotten there yet, but... Here's the intro to the help topic though: http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/What_is_Map_Algebra/00p600000002000000...
0 Kudos
MustafaELHalwagy
Emerging Contributor
Thank you very much
0 Kudos
KarlZimmer
Deactivated User
Hello all,

I am having a similar issue of converting a VB code block to a equivalent python code block for use in the Calculate Field tool. I used the following VB code with NewString as the expression in Modelbuilder and it works fine; however, I want to run the Calculate Field as a Python Script so seems like I need to convert it. The objective is to get the three digit date from the time field (i.e 000 to 366) and then assign it the appropriate image date based on where it fits in the select case.  So in this case the field calculated is ImgDate and ImgDate = NewString from expression below

dim NewString as string
Select case (Right("00" + CStr(DatePart("y", [Date_Time])), 3))
case 1 to 16
     NewString = "1"
case 17 to  32
     NewString = "17"
case 33 to 48
     NewString = "33"
case 49 to  64
     NewString = "49"
case 65 to 80
     NewString = "65"
case 81 to  96
     NewString = "81"
case 97 to 112
     NewString = "97"
case 113 to  128
     NewString = "113"
case 129 to 144
     NewString = "129"
case 145 to  160
     NewString = "145"
case 161 to 176
     NewString = "161"
case 177 to  192
     NewString = "177"
case 193 to 208
     NewString = "193"
case 209 to  224
     NewString = "209"
case 225 to 240
     NewString = "225"
case 241 to  256
     NewString = "241"
case 257 to  272
     NewString = "257"
case 273 to 288
     NewString = "273"
case 289 to  304
     NewString = "289"
case 305 to 320
     NewString = "305"
case 321 to  336
     NewString = "321"
case 337 to 352
     NewString = "337"
case 353 to  367
     NewString = "353"
case else
     NewString = "Error"
end select


I think I've got the select case statements figured out, but can't seem to figure out how to get the appropriate three digit date value as a string from a DateTime Field

I tried this in the code block of Modelbuilder but it doesn't work:

NewString =  (rstrip("00" + Str(DatePart("y", !Date_Time!)), 3))

def Calc(NewString):
    if NewString >= 1 or NewString <= 16:
        return 1
    elif NewString >= 17 or NewString <=32:
        return 17
    elif NewString >= 33 or NewString <=48:
        return 33
    else:
       return 0 


I"m also having trouble converting this VB line that takes the image date determined in the code above and adds the year to it and .tif extension to the end (e.g 2006D032.tif) as well.
CStr(DatePart("yyyy", [Date_Time])) + "D" +  Right("00" + CStr([ImgDate]), 3) + ".tif"


Any help would be greatly appreciated. Thanks in advance.

Cheers!
0 Kudos
BradPosthumus
Frequent Contributor
As mentioned above you can use the datetime module to convert your dates to the day of the year.

The codeblock below demonstrates how to do it.

The first line splits the date into a Python list containing the day, month, and year. Note the map function runs the int function on each part to convert them from strings to integers.

The second line creates a date object using the Python list.

The third line converts the date to the day of the year.

import datetime
def Calc(strDate):
    lstDate = map(int, strDate.split("/")) # create list of date integers  D(D), M(M), YYYY
    objDate = datetime.date(lstDate[2], lstDate[1], lstDate[0]) # create date object
    intDay = int(objDate.strftime("%j")) # integer day of the year
    for i in range(1, 366, 16):
        if intDay >= i and intDay < i+16:
            return i
    return 0


(Use Calc(!Date_Time!) as the EXPRESSION.)

Creating a string such as "2006D032.tif" is simply a matter of concatenating the parts of the date object using stftime formatting (dig around here http://docs.python.org/library/datetime.html for more info regarding format codes).


strTif = objDate.strftime("%Y") + "D" + objDate.strftime("%j") + ".tif" 

0 Kudos
KarlZimmer
Deactivated User
Hi Brad,

Thanks for the reply.  I believe what you have suggested is exactly what I need and is much more efficient then my current vb code! However, I am still struggling with the syntax and getting the Calculate Field tool to work properly. I keep getting the following error.

ERROR 000539: Error running expression: Calc("1/29/2007") <type 'exceptions.NameError'>: global name 'objDate' is not defined
Failed to execute (Calculate Field (3))

I've attached screen shots of the parameters I entered in the Calculate Field tool.  I looked through the link you sent, but still can't seem to figure out the error. My field in the attribute table is Named Date_Time and is Type Date. The date is formated  M/DD/YYYY (1/29/2007).

Any futher help would be greatly appreciated!

Cheers,
Karl
0 Kudos
BradPosthumus
Frequent Contributor
For the second script, you need to (1) create the date object, (2) pass the ImgDate attribute as a parameter to the Calc function, and (3) return the result of the function.

See if this works, using Calc(!Date_Time!, !ImgDate!) as the expression:

import datetime
def Calc(strDate, strImageDate):
    lstDate = map(int, strDate.split("/")) # create list of date integers  D(D), M(M), YYYY
    objDate = datetime.date(lstDate[2], lstDate[1], lstDate[0]) # create date object
    strTif = r"J:\GEOG683\HED_NDVI_GEO" + r"\Montana_Canada_NDVI_A" + objDate.strftime("%Y") + "D" + strImageDate + ".tif"
    return strTif


Alternatively, you can shorten this quite a bit. Since you just need the year in this script you could directly split it out from Date_Time attribute:

import datetime
def Calc(strDate, strImageDate):
    return r"J:\GEOG683\HED_NDVI_GEO" + r"\Montana_Canada_NDVI_A" + strDate.split("/")[2] + "D" + strImageDate + ".tif"
0 Kudos
KarlZimmer
Deactivated User
Hi Brad,

Thank you so much for your patience and assistance. However, I am still getting an error when I run the Calculate Field. However, now my error is:

ERROR 000539: Error running expression: Calc("6/16/2006") <type 'exceptions.ValueError'>: month must be in 1..12
Failed to execute (Calculate Field (3)).

I think this must mean my Date_Time field isn't in the correct format. Reading the ArcGIS help online it mentions that shapefiles and coverages store Dates differently as it only stores dates and not time. In anycase my dataset is a shapefile and I'm working in 9.3.1 if that makes a difference.

I apologize for not figuring this out myself, but I've having some trouble understanding the details of the code as I'm new to Python.

Thanks again for you help!
0 Kudos
BradPosthumus
Frequent Contributor
Hi Brad,

Thank you so much for your patience and assistance. However, I am still getting an error when I run the Calculate Field. However, now my error is:

ERROR 000539: Error running expression: Calc("6/16/2006") <type 'exceptions.ValueError'>: month must be in 1..12
Failed to execute (Calculate Field (3)).

I think this must mean my Date_Time field isn't in the correct format. Reading the ArcGIS help online it mentions that shapefiles and coverages store Dates differently as it only stores dates and not time. In anycase my dataset is a shapefile and I'm working in 9.3.1 if that makes a difference.

I apologize for not figuring this out myself, but I've having some trouble understanding the details of the code as I'm new to Python.

Thanks again for you help!


Let's start with this line:

lstDate = map(int, strDate.split("/")) # create list of date integers  D(D), M(M), YYYY


(note that comments are preceded by #, so anything following # is ignored)

This is actually two commands joined as one: the "map" function and the "split" string method.

Say you have a date of "6/16/2006". The string method

strDate.split("/") 


creates a Python list by splitting the string at the forward slash, with a result of ["6", "16", "2006"]. So now Python interprets the line as:

lstDate = map(int, ["6", "16", "2006"]) 


The map function simply says "take each element in the list (second parameter) and pass it into the function defined in the first parameter". In this case, each element is passed into the int() function, converting the strings in the list to integers. So now Python interprets the line as:

lstDate = [6, 16, 2006]


To access each element in the list you append an index number in square brackets to the list variable name. The index numbering starts with 0, so you can extract each value like this:
lstDate[0] = 6        # month
lstDate[1] = 16      # date
lstDate[2] = 2006   # year


Now jump into this line:

objDate = datetime.date(lstDate[2], lstDate[1], lstDate[0]) # create date object


The date object is created by passing three parameters, as integers, to the datetime.date method in the following order:

datetime.date(<year>, <month>, <date>)

The date format in my data was DD/MM/YYYY, so lstDate[0] was day, lstDate[1], was month, and lstDate[2] was year. Therefore, the parameters are:

datetime.date(lstDate[2], lstDate[1], lstDate[0])


Your data (and I didn't notice before my last post) is MM/DD/YYYY. Therefore, you simply need to change the order of the parameters to fix the error.

objDate = datetime.date(lstDate[2], lstDate[0], lstDate[1]) # create date object
0 Kudos