Latitude Longitude Functions

treasure map

Working with distance, latitude and longitude in Excel

This page presents various methods for acquiring latitude and longitude in Excel, as well as driving distance. The code on this page is somewhat old and I am planning at some point to refactor it.

Driving Distance MapQuest UDF

Here is a UDF for getting driving distance from MapQuest, based on cells in your worksheet.

Let's say you have a starting address in cells A1 (street), B1 (city), C1 (state), D1 (zip), and the destination address is E1 (street), F1 (city), G1 (state), H1 (zip). This function pulls the address from the cells in Excel, creates an instance of Internet Explorer, passes the addresses to MapQuest and returns the driving distance to the target cell. If there is an error with MapQuest, it shows a friendly error message.

Update 10/31/08: MapQuest reorged their page and broke the UDF. I've updated the URL string, and also added a call to the Refresh Method. This is required to make the driving distance appear programmatically.

'
' must set references to Microsoft VBScript Regular Expressions, Internet Controls
' & HTML Object Library before running this script
' based on http://www.vbaexpress.com/kb/getarticle.php?kb_id=386
Public Function GetDistance(startAddr As String, startCity As String, _
  startState As String, startZip As String, endAddr As String, _
  endCity As String, endState As String, endZip As String) As String

Dim sURL As String
Dim appIE As InternetExplorer
Dim regex As RegExp, Regmatch As MatchCollection
Dim BodyTxt As String
Dim GetFirstPos As Long

sURL = "http://www.mapquest.com/maps?1c=" & Replace(startCity, " ", "+")
sURL = sURL & "&1s=" & startState & "&1a=" & Replace(startAddr, " ", "+")
sURL = sURL & "&1z=" & startZip & "&2c=" & endCity & "&2s=" & endState
sURL = sURL & "&2a=" & Replace(endAddr, " ", "+") & "&2z=" & endZip

Set appIE = New InternetExplorer
'Set appIE = CreateObject("Internetexplorer.application")

appIE.navigate sURL
appIE.Visible = True

    Do
        DoEvents
    Loop Until appIE.readyState = READYSTATE_COMPLETE

appIE.Refresh

Set regex = New RegExp
With regex
    .Pattern = "Total Estimated Distance"
    .MultiLine = False
End With

BodyTxt = appIE.document.Body.innerText
Set Regmatch = regex.Execute(BodyTxt)

If Regmatch.Count > 0 Then
    GetFirstPos = WorksheetFunction.Find("Total Estimated Distance", BodyTxt, 1)
   
    GetDistance = Mid$(BodyTxt, GetFirstPos, 30)
 
    Else
    GetDistance = "Address Error, fix and try again"
End If

appIE.Quit
Set appIE = Nothing
Set regex = Nothing
Set Regmatch = Nothing

End Function

This function should be used in a worksheet as follows:

=GetDistance(A1,B1,C1,D1,E1,F1,G1,H1)

Now note that it will return an error if you include suite or apartment numbers in the house number. Also if you include hash marks "#" it will fail. Also keep in mind you are opening Internet Explorer in the background and waiting for MapQuest to load, so there will be an approx 6 second delay between you entering the function and it actually returning a result. Also I recommend that after entering the function and getting the result, you either paste in the value or delete it and re-enter it if needed — the function is volatile and you will end up re-running the code inadvertently, which will slow down your computer to a crawl.


Great Circle Distance UDF using Yahoo API and XML

Yahoo provides a nifty geocoding API which we can use to return latitude and longitude information, based on a given street address. Here I will show a simple UDF that uses XML to return this data to two string variables, which can be used in other VBA procedures or directly in the worksheet.

I have previously posted some sample code showing how to get driving distance into Excel, namely

The first thing I did was go to the following website and create a Yahoo API: Yahoo Developer Network and the website that explains how it works is here: Yahoo Geocoding API

To construct the URL, I simply used the sample URL from their site (see below) and replaced the appid with the one I created using the link above. When you create your own appid, it should be placed in the URL below, between "appid=" and "&street". Then we can use function arguments to pass the additional parameters (city, state and zip).

http://local.yahooapis.com/MapsService/V1/geocode?appid=sGmf70bV34H6QgDaDk.tLer1VOJZEf.P7nZPi2V8MMmFDEQ_f30ByzwxgTI-&street=701+First+Ave&city=Sunnyvale&state=CA

Then it is simply a matter of using the stock code from Website Parsing/Retrieval using XML and using text functions like Instr, Left$, Mid$ and Len to extract the latitude and longitude from the returned XML response.

Remember to set a reference to Microsoft XML, v6.0 (c:\WINDOWS\system32\msxml6.dll on my system) in the VB Editor. See the Binding page for help setting up references to object libraries.

Function GCDist(strStartAddr As String, strStartCity As String, _
strStartState As String, strEndAddr As String, strEndCity As String, _
strEndState As String) As Double
'
' Jimmy Pena 4-2-2008
' http://www.codeforexcelandoutlook.com
'
' uses formula from http://www.cpearson.com/excel/latlong.htm with slight mod

Dim MyStartLat As String
Dim MyStartLong As String
Dim MyEndLat As String
Dim MyEndLong As String

MyStartLat = GetLatitude(strStartAddr, strStartCity, strStartState)
MyStartLat = CDec(MyStartLat)
MyStartLong = GetLongitude(strStartAddr, strStartCity, strStartState)
MyStartLong = CDec(MyStartLong)

MyEndLat = GetLatitude(strEndAddr, strEndCity, strEndState)
MyEndLat = CDec(MyEndLat)
MyEndLong = GetLongitude(strEndAddr, strEndCity, strEndState)
MyEndLong = CDec(MyEndLong)

With WorksheetFunction
    GCDist = Format(3958.756 * .Acos(Cos(.Radians(90 - (MyStartLat))) * _
Cos(.Radians(90 - (MyEndLat))) + Sin(.Radians(90 - (MyStartLat))) * _
Sin(.Radians(90 - (MyEndLat))) * _
Cos(.Radians((MyStartLong - MyEndLong)))), "####.##")
End With

End Function
Private Function GetLatitude(strStreet As String, strCity As String, _
strState As String) As String

Dim sURL As String
Dim FirstPos As Long
Dim LastPos As Long

Dim xmlSite As XMLHTTP60
Set xmlSite = New XMLHTTP60

sURL = "http://local.yahooapis.com/MapsService/V1/geocode?" & _
"appid=sGmf70bV34H6QgDaDk.tLer1VOJZEf.P7nZPi2V8MMmFDEQ_f30ByzwxgTI-" & _
"&street=" & Replace(strStreet, " ", "+") & "&city=" & strCity & _
"&state=" & strState

xmlSite.Open "GET", sURL, False
xmlSite.Send

Do Until xmlSite.readyState = 4
Loop

FirstPos = InStr(xmlSite.responseText, "Latitude") + 9
LastPos = InStr(FirstPos + 1, xmlSite.responseText, "/Latitude") - 1

GetLatitude = Mid$(xmlSite.responseText, FirstPos, LastPos - FirstPos)

Set xmlSite = Nothing

End Function
Private Function GetLongitude(strStreet As String, strCity As String, _
strState As String) As String

Dim sURL As String
Dim FirstPos As Long
Dim LastPos As Long

Dim xmlSite As XMLHTTP60
Set xmlSite = New XMLHTTP60

sURL = "http://local.yahooapis.com/MapsService/V1/geocode?" & _
"appid=sGmf70bV34H6QgDaDk.tLer1VOJZEf.P7nZPi2V8MMmFDEQ_f30ByzwxgTI-" & _
"&street=" & Replace(strStreet, " ", "+") & "&city=" & strCity & _
"&state=" & strState

xmlSite.Open "GET", sURL, False
xmlSite.Send

Do Until xmlSite.readyState = 4
Loop

FirstPos = InStr(xmlSite.responseText, "Longitude") + 10
LastPos = InStr(FirstPos + 1, xmlSite.responseText, "/Longitude") - 1

GetLongitude = Mid$(xmlSite.responseText, FirstPos, LastPos - FirstPos)

Set xmlSite = Nothing

End Function

To use, you should have a starting address, city and state in separate cells (ex: A1:A3), and destination address, city and state in separate cells (ex: B1:B3) type =GCDist(A1,A2,A3,B1,B2,B3) in a cell and press Enter. You could also type the arguments directly into the parenthesis, for example:

=GCDist("123 Main St","Queens","NY","100 Main Blvd","Ames","IA")

The first thing you may notice is just how much faster this is than the GetDistance() function above. Keep in mind, though, that even though it is much faster, less volatile and less prone to error, this function returns great circle ("as the crow flies") distances, where the GetDistance() function returns actual door to door distance (much more useful in my opinion).

The first thing the function does is pass the arguments to the "real" functions, a series of functions declared Private so they are only accessible from the GCDist() function. i.e. they can't be found in the GUI. These functions, GetLatitude() and GetLongitude(), use the XMLHTTP60 object to open a request to the Yahoo website, pass the URL and grab the return text, then parse it for the latitute and longitude (respectively).

These values are returned to the GCDist function, converted to decimal values (CDec), then passed to the formula (courtesy of Chip Pearson's website) which calculates the great circle distance.

I use the Replace() function because if you notice in the sample URL there are plus signs where there are usually spaces in the street address. Since we can't have spaces in the URL, we replace them with plus signs wherever found.

xml logo

Get Latitude and Longitude using XML

We can also use web services to look up latitude and longitude. WebserviceX.net offers a few free web APIs for consuming weather information. Fortunately, this service also returns the latitude and longitude for a given zip code. Paste the following into a standard module and run the TestGetLatLong function.

The GetLatitudebyZip and GetLongitudeByZip functions create temporary XML files and do a rudimentary parsing for the latitude and longitude found therein. The temp file is removed after processing. You could easily combine these two functions to return both the latitude and longitude. For example, as an array.

Const XML_FILE_EXTENSION As String = ".xml"

Sub TestGetLatLong()

  Debug.Print GetLatitudeByZip("11103")
  Debug.Print GetLongitudeByZip("11103")

End Sub

Function GetLatitudeByZip(ZipCode As String) As Double
' http://www.webservicex.net/WCF/ServiceDetails.aspx?SID=44
' requires %windir%\system32\msxml2.dll

Dim xml As Object
Dim result As String
Dim nextFileNum As Long
Dim tempFile As String
Dim doc As Object
Dim objRoot As Object
Dim objChild As Object

  ' create XML document with weather info (which also
 ' contains lat/long)
 Set xml = CreateObject("MSXML2.XMLHTTP")

  xml.Open "GET", _
"http://www.webservicex.net/WeatherForecast.asmx/GetWeatherByZipCode?ZipCode=" & ZipCode, False
  xml.Send

  result = xml.responsetext

  ' write to temp xml file
 nextFileNum = FreeFile

  tempFile = Environ("temp") & Application.PathSeparator & ZipCode & XML_FILE_EXTENSION

  Open tempFile For Output As #nextFileNum
  Print #nextFileNum, result
  Close #nextFileNum

  ' create new XML doc
 Set doc = CreateObject("MSXML2.DOMDocument")
  doc.validateOnParse = False

  doc.Load tempFile

  Set objRoot = doc.documentElement
 
  ' loop through top-level children
 For Each objChild In objRoot.childNodes

    If objChild.nodeName = "Latitude" Then
      GetLatitudeByZip = objChild.Text
      Kill tempFile
      Exit Function
    End If
  Next objChild

End Function

Function GetLongitudeByZip(ZipCode As String) As Double
' http://www.webservicex.net/WCF/ServiceDetails.aspx?SID=44
' requires %windir%\system32\msxml2.dll

Dim xml As Object
Dim result As String
Dim nextFileNum As Long
Dim tempFile As String
Dim doc As Object
Dim objRoot As Object
Dim objChild As Object

  ' create XML document with weather info (which also
 ' contains lat/long)
 Set xml = CreateObject("MSXML2.XMLHTTP")

  xml.Open "GET", _
"http://www.webservicex.net/WeatherForecast.asmx/GetWeatherByZipCode?ZipCode=" & ZipCode, False
  xml.Send

  result = xml.responsetext

  ' write to temp xml file
 nextFileNum = FreeFile

  tempFile = Environ("temp") & Application.PathSeparator & ZipCode & XML_FILE_EXTENSION

  Open tempFile For Output As #nextFileNum
  Print #nextFileNum, result
  Close #nextFileNum

  ' create new XML doc
 Set doc = CreateObject("MSXML2.DOMDocument")
  doc.validateOnParse = False

  doc.Load tempFile

  Set objRoot = doc.documentElement

  ' loop through top-level children
 For Each objChild In objRoot.childNodes

    If objChild.nodeName = "Longitude" Then
      GetLongitudeByZip = objChild.Text
      Kill tempFile
      Exit Function
    End If
  Next objChild

End Function

geonames logo

Latitude and Longitude from Geonames

Geonames is a web service that returns geographical information from its database. It also returns latitude and longitude for select functions.

The following function may be used (within the United States) to return the latitude and longitude for a given zip code. It's approximate, but good enough for many purposes.

Don't forget to paste the helper functions into a standard module in the same project.

Function GetLatLong(postCode As String, Optional countryCode As String = "USA", _
                    Optional radius As Long = 10, _
                    Optional maxRows As Long = 1) As String()

Dim xml As Object ' MSXML2.XMLHTTP
Dim result As String
Dim tempFile As String
Dim tempString() As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim geoNames As Object ' MSXML2.IXMLDOMNode
Dim code As Object ' MSXML2.IXMLDOMNode
Dim i As Long

  tempFile = Environ("temp") & "\" & postCode & "latlong.xml"

  If Len(Dir(tempFile)) = 0 Then

    Set xml = CreateObject("MSXML2.XMLHTTP")

    xml.Open "GET", "http://ws.geonames.org/findNearbyPostalCodes?postalcode=" & _
                    postCode & "&country=" & countryCode & "&radius=" & radius & _
                    "&maxRows=" & maxRows & "&type=xml", False
    xml.send

    result = ConvertAccent(xml.responseText)

    ' create XML file from result
   Call CreateXMLFile(tempFile, result)

  End If

  ' create XML doc
 Set xmlDoc = CreateObject("MSXML2.DOMDocument")

  With xmlDoc
    .async = False
    .validateOnParse = False
    .Load tempFile
  End With

  ' check that the XML doc loaded
 If LoadError(xmlDoc) Then
    Exit Function
  End If

  ' get first level nodes
 Set geoNames = xmlDoc.childNodes(1)

  ' resize array
 ReDim tempString(1 To 2)

  ' the first and only node
 Set code = geoNames.childNodes(0)

  tempString(1) = code.childNodes(3).nodeTypedValue
  tempString(2) = code.childNodes(4).nodeTypedValue

  GetLatLong = tempString

End Function

The function returns latitude and longitude as a String array; the first element is latitude, the second is longitude.

Sub TestGetLatLongFromGeonames()

Dim results() As String
Dim latitude As String
Dim longitude As String

  results = GetLatLong("11103")

  latitude = results(1)
  longitude = results(2)

End Sub

Helper Functions

These functions are used by the Geonames function; make sure you paste them into a standard module in the same project.

Function GetChildNodes(node As Object) As Object
' returns child nodes for a given MSXML2.IXMLDOMNode
 Set GetChildNodes = node.childNodes
End Function

Function CreateXMLFile(fileName As String, contents As String) As String
' creates XML file from string contents

Dim tempFile As String
Dim nextFileNum As Long

  nextFileNum = FreeFile

  tempFile = fileName

  Open tempFile For Output As #nextFileNum
  Print #nextFileNum, FixAngleBrackets(contents)
  Close #nextFileNum

  CreateXMLFile = tempFile
End Function

Function GetRootNode(xmlDoc As Object) As Object
' returns root node
 Set GetRootNode = xmlDoc.documentElement
End Function

Function GetNode(parentNode As Object, nodeNumber As Long) As Object
  On Error Resume Next
  ' if parentNode is a MSXML2.IXMLDOMNodeList
 Set GetNode = parentNode.item(nodeNumber - 1)

  ' if parentNode is a MSXML2.IXMLDOMNode
 If GetNode Is Nothing Then
    Set GetNode = parentNode.childNodes(nodeNumber - 1)
  End If
End Function

Function LoadError(xmlDoc As Object) As Boolean
' checks if a xml file load error occurred
 LoadError = (xmlDoc.parseError.errorCode <> 0)
End Function

Function ClearCache(Optional fileExtension As String = "xml")
' deletes stored xml files from temp folder
Dim filesToDelete As String
  filesToDelete = environ("temp") & "\*." & fileExtension

  Kill filesToDelete
End Function

Function FixAngleBrackets(textString As String) As String
  FixAngleBrackets = Replace(Replace(textString, "&lt;", "<"), "&gt;", ">")
End Function

Function ConvertAccent(ByVal inputString As String) As String
' http://www.vbforums.com/archive/index.php/t-483965.html

Const AccChars As String = "ŠŽšžŸÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðñòóôõöùúûüýÿ"
Const RegChars As String = "SZszYAAAAAACEEEEIIIIDNOOOOOUUUUYaaaaaaceeeeiiiidnooooouuuuyy"

Dim i As Long, j As Long
Dim tempString As String
Dim currentCharacter As String
Dim found As Boolean
Dim foundPosition As Long

  tempString = inputString

  ' loop through the shorter string
 Select Case True
    Case Len(AccChars) <= Len(inputString)
      ' accent character list is shorter (or same)
     ' loop through accent character string
     For i = 1 To Len(AccChars)

        ' get next accent character
       currentCharacter = Mid$(AccChars, i, 1)

        ' replace with corresponding character in "regular" array
       If InStr(tempString, currentCharacter) > 0 Then
          tempString = Replace(tempString, currentCharacter, Mid$(RegChars, i, 1))
        End If

      Next i
    Case Len(AccChars) > Len(inputString)
      ' input string is shorter
     ' loop through input string
     For i = 1 To Len(inputString)

        ' grab current character from input string and determine if it is a special char
       currentCharacter = Mid$(inputString, i, 1)
        found = (InStr(AccChars, currentCharacter) > 0)

        If found Then

          ' find position of special character in special array
         foundPosition = InStr(AccChars, currentCharacter)

          ' replace with corresponding character in "regular" array
         tempString = Replace(tempString, currentCharacter, Mid$(RegChars, foundPosition, 1))

        End If
      Next i
  End Select

  ConvertAccent = tempString
End Function

For more Geonames API functions, visit my blog.


business.gov logo

Latitude and longitude using Business.Gov API

We can also return latitude and longitude using the Business.Gov API. It returns latitude and longitude for a city/state combination (U.S. only). While this isn't as accurate as lat/lon for a street address, it may be good enough for your needs.

To use this function you'll need the URLEncode function, as well as the helper functions used elsewhere.

Function GetLatLong(stateAbbr As stateAbbr, city As String) As String()
' uses business.gov API to get latitude and
' longitude for a city/state combo

Dim xml As Object ' MSXML2.XMLHTTP
Dim tempFile As String
Dim tempString() As String
Dim result As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim sites As Object ' MSXML2.IXMLDOMNodeList
Dim site As Object ' MSXML2.IXMLDOMNode
Dim i As Long, j As Long
Dim state As String

  state = GetStateAbbr(stateAbbr)

  Const TEMP_FILENAME As String = "LatLong"
  Const XML_FILE_EXTENSION As String = ".xml"

  ' if XML file exists, don't requery website
 tempFile = environ("temp") & "\" & TEMP_FILENAME & state & city & XML_FILE_EXTENSION

  If Len(Dir(tempFile)) = 0 Then

    Set xml = CreateObject("MSXML2.XMLHTTP")

    With xml
      .Open "GET", _
    "http://api.business.gov/geodata/all_links_for_city_of/" & _
    URLEncode(city) & "/" & state & ".xml", False
      .send
    End With

    result = ConvertAccent(xml.responseText)

    ' save result as temp XML document
   tempFile = CreateXMLFile(tempFile, result)

  End If

  ' load XML file into new XML document
 Set xmlDoc = CreateObject("MSXML2.DOMDocument")

  With xmlDoc
    .async = False
    .validateOnParse = False
    .Load tempFile
  End With

  ' check that the XML doc loaded
 If LoadError(xmlDoc) Then
    Exit Function
  End If

  ' get root node
 Set xmlDocRoot = GetRootNode(xmlDoc)

  ' get first level child nodes
 Set sites = GetChildNodes(xmlDocRoot)

  ' resize array
 ReDim tempString(1 To 2)

  Set site = sites.item(0)

  tempString(1) = site.childNodes.item(10).nodeTypedValue
  tempString(2) = site.childNodes.item(11).nodeTypedValue

  GetLatLong = tempString

End Function

You'll also need the following Enum section, and a function to translate the constant into a String. Paste it at the top of a standard module in the same project. The GetStateAbbr function translates the constant into a string needed for the GetLatLong function.

Public Enum stateAbbr
  ALABAMA
  ALASKA
  AMERICAN_SAMOA
  ARIZONA
  ARKANSAS
  CALIFORNIA
  COLORADO
  CONNECTICUT
  DELAWARE
  DISTRICTOFCOLUMBIA
  MICRONESIA
  FLORIDA
  GEORGIA
  GUAM
  HAWAII
  IDAHO
  ILLINOIS
  INDIANA
  IOWA
  KANSAS
  KENTUCKY
  LOUISIANA
  MAINE
  MARSHALL_ISLANDS
  MARYLAND
  MASSACHUSETTS
  MICHIGAN
  MINNESOTA
  MISSISSIPPI
  MISSOURI
  MONTANA
  NEBRASKA
  NEVADA
  NEW_HAMPSHIRE
  NEW_JERSEY
  NEW_MEXICO
  NEW_YORK
  NORTH_CAROLINA
  NORTH_DAKOTA
  NORTHERN_MARIANA_ISLANDS
  OHIO
  OKLAHOMA
  OREGON
  PALAU
  PENNSYLVANIA
  PUERTO_RICO
  RHODE_ISLAND
  SOUTH_CAROLINA
  SOUTH_DAKOTA
  TENNESSEE
  TEXAS
  UTAH
  VERMONT
  VIRGIN_ISLANDS
  VIRGINIA
  WASHINGTON
  WEST_VIRGINIA
  WISCONSIN
  WYOMING
End Enum

Function GetStateAbbr(stateAbbr As stateAbbr) As String
  Select Case stateAbbr
    Case 0: GetStateAbbr = "AL"
    Case 1: GetStateAbbr = "AK"
    Case 2: GetStateAbbr = "AS"
    Case 3: GetStateAbbr = "AZ"
    Case 4: GetStateAbbr = "AR"
    Case 5: GetStateAbbr = "CA"
    Case 6: GetStateAbbr = "CO"
    Case 7: GetStateAbbr = "CT"
    Case 8: GetStateAbbr = "DE"
    Case 9: GetStateAbbr = "DC"
    Case 10: GetStateAbbr = "FM"
    Case 11: GetStateAbbr = "FL"
    Case 12: GetStateAbbr = "GA"
    Case 13: GetStateAbbr = "GU"
    Case 14: GetStateAbbr = "HI"
    Case 15: GetStateAbbr = "ID"
    Case 16: GetStateAbbr = "IL"
    Case 17: GetStateAbbr = "IN"
    Case 18: GetStateAbbr = "IA"
    Case 19: GetStateAbbr = "KS"
    Case 20: GetStateAbbr = "KY"
    Case 21: GetStateAbbr = "LA"
    Case 22: GetStateAbbr = "ME"
    Case 23: GetStateAbbr = "MH"
    Case 24: GetStateAbbr = "MD"
    Case 25: GetStateAbbr = "MA"
    Case 26: GetStateAbbr = "MI"
    Case 27: GetStateAbbr = "MN"
    Case 28: GetStateAbbr = "MS"
    Case 29: GetStateAbbr = "MO"
    Case 30: GetStateAbbr = "MT"
    Case 31: GetStateAbbr = "NE"
    Case 32: GetStateAbbr = "NV"
    Case 33: GetStateAbbr = "NH"
    Case 34: GetStateAbbr = "NJ"
    Case 35: GetStateAbbr = "NM"
    Case 36: GetStateAbbr = "NY"
    Case 37: GetStateAbbr = "NC"
    Case 38: GetStateAbbr = "ND"
    Case 39: GetStateAbbr = "MP"
    Case 40: GetStateAbbr = "OH"
    Case 41: GetStateAbbr = "OK"
    Case 42: GetStateAbbr = "OR"
    Case 43: GetStateAbbr = "PW"
    Case 44: GetStateAbbr = "PA"
    Case 45: GetStateAbbr = "PR"
    Case 46: GetStateAbbr = "RI"
    Case 47: GetStateAbbr = "SC"
    Case 48: GetStateAbbr = "SD"
    Case 49: GetStateAbbr = "TN"
    Case 50: GetStateAbbr = "TX"
    Case 51: GetStateAbbr = "UT"
    Case 52: GetStateAbbr = "VT"
    Case 53: GetStateAbbr = "VI"
    Case 54: GetStateAbbr = "VA"
    Case 55: GetStateAbbr = "WA"
    Case 56: GetStateAbbr = "WV"
    Case 57: GetStateAbbr = "WI"
    Case 58: GetStateAbbr = "WY"
  End Select

End Function

Sample usage

Sub TestGetLatLong()

Dim results() As String
Dim latitude As String
Dim longitude As String

results = GetLatLong(NEW_YORK, "Albany")
latitude = results(1)
longitude = results(2)

End Sub

abbreviations.com logo

Abbreviations.com Zip Codes API returns Latitude and Longitude

Here's yet another way to get latitude and longitude. Will it ever stop?

To use the Zip Codes API from Abbreviations.com, visit their API page. You'll need an API key to use the following function. I have an API key (they call it a "token ID"), but in the sample code below it has been removed.

This function takes a zip code and returns the latitude and longitude as an array. It's not as accurate as a street address, but might be close enough for most purposes. It is late bound but uses MSXML2.DLL which should be located in your %windir%\system32 folder.

Note: The second and third values of the returned String array contain the latitude and longitude for the given zip code.

Public Const zip_base_URL As String = "http://www.uszip.com/services/v1/zip.aspx"

Function GetLatLong(tokenID As String, zipCode As String, _
                            Optional forceRequery As Boolean = False) As String()

Dim xml As Object ' MSXML2.XMLHTTP
Dim result As String
Dim tempFolder As String
Dim tempFile As String
Dim tempString() As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim results As Object ' MSXML2.IXMLDOMNodeList
Dim resultNode As Object ' MSXML2.IXMLDOMNode

Const XML_FILE_EXTENSION As String = ".xml"

  tempFolder = environ("temp") & "\"
  tempFile = tempFolder & zipCode & XML_FILE_EXTENSION

  ' requery if cache file is missing or forceRequery set to True
 If Len(Dir(tempFile)) = 0 Or forceRequery Then

    Set xml = CreateObject("MSXML2.XMLHTTP")

    With xml
      .Open "GET", zip_base_URL & "?tokenid=" & tokenID & "&zip=" & zipCode, False
      .send
    End With

    result = xml.responseText

    CreateXMLFile tempFile, ConvertAccent(result)

  End If

  ' load XML file into new XML document
 Set xmlDoc = CreateObject("MSXML2.DOMDocument")

  With xmlDoc
    .async = False
    .validateOnParse = False
    .Load tempFile
  End With

  ' check that the XML doc loaded
 If LoadError(xmlDoc) Then
    Exit Function
  End If

  ' get root node
 Set xmlDocRoot = GetRootNode(xmlDoc)
  Set resultNode = GetNode(xmlDocRoot, 1)

  ' resize array
 ReDim tempString(1 To 1, 1 To resultNode.childNodes.Length)

  tempString(1, 1) = GetNode(resultNode, 1).nodeTypedValue
  ' latitude
 tempString(1, 2) = GetNode(resultNode, 2).nodeTypedValue
  ' longitude
 tempString(1, 3) = GetNode(resultNode, 3).nodeTypedValue

  GetLatLong = tempString

End Function

Sample Usage

This sample procedure will return the latitude and longitude for Astoria, NY (zip code 11103).

Sub tst()

Dim tokenID As String
Dim results() As String
Dim result As String
Dim i As Long, j As Long

  tokenID = "get your token ID from Abbreviations.com"
  results = GetLocationFromZip(tokenID, "11103")

  For i = LBound(results) To UBound(results)
    For j = LBound(results, 2) To UBound(results, 2)
      Debug.Print results(i, j)
    Next j
  Next i

End Sub

Don't forget to copy the helper functions found elsewhere in this article.

See more Abbreviations.com API code samples.

Site last updated August 24, 2010 @ 5:56 pm