<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Perseverance Trumps Talent &#187; zip code</title>
	<atom:link href="http://aaroncollegeman.com/tag/zip-code/feed/" rel="self" type="application/rss+xml" />
	<link>http://aaroncollegeman.com</link>
	<description></description>
	<lastBuildDate>Thu, 11 Feb 2010 22:26:31 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Calculate the distance between two U.S. zip codes</title>
		<link>http://aaroncollegeman.com/2009/02/calculate-the-distance-between-two-us-zip-codes/</link>
		<comments>http://aaroncollegeman.com/2009/02/calculate-the-distance-between-two-us-zip-codes/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 03:45:24 +0000</pubDate>
		<dc:creator>Aaron</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[Science]]></category>
		<category><![CDATA[calculator]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[postal code]]></category>
		<category><![CDATA[zip code]]></category>
		<category><![CDATA[zipcode]]></category>

		<guid isPermaLink="false">http://aaroncollegeman.com/?p=220</guid>
		<description><![CDATA[Every once in a while a Web developer gets the opportunity to use those math skills he honed in college.  (I suppose this is only theoretical, since I didn&#8217;t go to college.)
We&#8217;re working on a project that calls for restricting search results to those occurring within a fixed distance from a user-supplied zip code.  The [...]]]></description>
			<content:encoded><![CDATA[<p>Every once in a while a Web developer gets the opportunity to use those math skills he honed in college.  (I suppose this is only theoretical, since I didn&#8217;t go to college.)</p>
<p>We&#8217;re working on a project that calls for restricting search results to those occurring within a fixed distance from a user-supplied zip code.  The premise is simple enough: discover the geographical location of two zip codes and calculate the distance between them.  Of course, there are a few prerequisites:</p>
<ul>
<li>a database of geocoded zip codes</li>
<li>a formula for calculating the distance between them</li>
</ul>
<p>I thought the first resource would be difficult to find, especially considering my budget for this project is exactly $0.  But lo and behold, much to my surprise and delight, the folks over at <a href="http://populardata.com">PopularData.com</a> provide <a href="http://www.populardata.com/downloads.html">such a resource</a>, <em>and</em> it&#8217;s free!  (As well it should be, since it&#8217;s probably based on the U.S. Census data collected in 2000 or earlier.)  They claim that the database is mostly complete, except for a few dropouts (most of which, they say, are military stations, and not too useful to our application.)</p>
<p>I had built an application similar to this one in the past, so I knew somewhere someone had written down the formula for calculating the distance.  Remember that it&#8217;s not just a simple point to point calculation.  No, that would be too easy.  You see, the Earth is round.  (No, really.)  And the curvature of the Earth <em>increases</em> the distance between two points.  Oh, if only Columbus had been wrong: think of how much gas we&#8217;d save!</p>
<p>In fact, the formula for calculating this distance is known as the <em>Haversine formula</em>. You can <a href="http://www.movable-type.co.uk/scripts/latlong.html">read more</a> <a href="http://en.wikipedia.org/wiki/Haversine_formula">about it</a>, if you wanna; but it basically goes like this (in JavaScript):</p>
<div class="geshi"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> R <span style="color: #339933;">=</span> <span style="color: #CC0000;">6371</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// circumference of the Earth, in kilometers</span>
<span style="color: #003366; font-weight: bold;">var</span> dLat <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>lat2<span style="color: #339933;">-</span>lat1<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toRad</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> dLon <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>lon2<span style="color: #339933;">-</span>lon1<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toRad</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> a <span style="color: #339933;">=</span> Math.<span style="color: #660066;">sin</span><span style="color: #009900;">&#40;</span>dLat<span style="color: #339933;">/</span>2<span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> Math.<span style="color: #660066;">sin</span><span style="color: #009900;">&#40;</span>dLat<span style="color: #339933;">/</span>2<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span>
Math.<span style="color: #660066;">cos</span><span style="color: #009900;">&#40;</span>lat1.<span style="color: #660066;">toRad</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> Math.<span style="color: #660066;">cos</span><span style="color: #009900;">&#40;</span>lat2.<span style="color: #660066;">toRad</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span>
Math.<span style="color: #660066;">sin</span><span style="color: #009900;">&#40;</span>dLon<span style="color: #339933;">/</span>2<span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> Math.<span style="color: #660066;">sin</span><span style="color: #009900;">&#40;</span>dLon<span style="color: #339933;">/</span>2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> c <span style="color: #339933;">=</span> 2 <span style="color: #339933;">*</span> Math.<span style="color: #660066;">atan2</span><span style="color: #009900;">&#40;</span>Math.<span style="color: #660066;">sqrt</span><span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> Math.<span style="color: #660066;">sqrt</span><span style="color: #009900;">&#40;</span>1<span style="color: #339933;">-</span>a<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> d <span style="color: #339933;">=</span> R <span style="color: #339933;">*</span> c<span style="color: #339933;">;</span></pre><textarea onfocus="jQuery(this).select();" onblur="jQuery(this).hide().prev().show();" style="display:none;">var R = 6371; // circumference of the Earth, in kilometers
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;</textarea><a class="clipboard" href="javascript:;" onclick="jQuery(window).scrollTo(jQuery(this).prev().show().focus().prev().hide().parent(), 500);">copy code</a></div>
<p>For our application, we basically want a view of our zip code data that represents the set of zip codes within <em>X</em> miles (or kilometers) of a given zip code origin.  We&#8217;ll use that view to filter our other records before returning those to the end-user.  To achieve this, I&#8217;ve written three MySQL procedures:</p>
<ul>
<li>function <em>km</em>, which performs the calculation between two sets of latitude and longitude coordinates</li>
<li>function <em>miles</em>, which relies on <em>km</em> to do the calculation, and then converts the result to miles</li>
<li>procedure <em>inside</em>, which accepts two parameters: a zip code origin, and a maximum distance with units (<em>km</em> for kilometers, and <em>mi</em> for miles)</li>
</ul>
<p>So, to query those zip codes within a ten mile radius of my home, the SQL looks something like this:</p>
<div class="geshi"><pre class="sql" style="font-family:monospace;">CALL inside<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'22601'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'10mi'</span><span style="color: #66cc66;">&#41;</span>;</pre><textarea onfocus="jQuery(this).select();" onblur="jQuery(this).hide().prev().show();" style="display:none;">CALL inside('22601', '10mi');</textarea><a class="clipboard" href="javascript:;" onclick="jQuery(window).scrollTo(jQuery(this).prev().show().focus().prev().hide().parent(), 500);">copy code</a></div>
<p>And the results are a bit like this:</p>
<div class="geshi"><pre class="php" style="font-family:monospace;"><span style="color: #0000ff;">&quot;22601&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">39.1697</span><span style="color: #339933;">,-</span><span style="color:#800080;">78.1686</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;WINCHESTER&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;VA&quot;</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">0</span>
<span style="color: #0000ff;">&quot;22604&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">39.1676</span><span style="color: #339933;">,-</span><span style="color:#800080;">78.1686</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;WINCHESTER&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;VA&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">0.142347455024719</span>
<span style="color: #0000ff;">&quot;22655&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">39.1634</span><span style="color: #339933;">,-</span><span style="color:#800080;">78.2462</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;STEPHENS CITY&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;VA&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">4.17041921615601</span>
<span style="color: #0000ff;">&quot;22656&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">39.2137</span><span style="color: #339933;">,-</span><span style="color:#800080;">78.0901</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;STEPHENSON&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;VA&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">5.17398071289062</span>
<span style="color: #0000ff;">&quot;22602&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">39.1501</span><span style="color: #339933;">,-</span><span style="color:#800080;">78.269</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;WINCHESTER&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;VA&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">5.53605270385742</span>
<span style="color: #0000ff;">&quot;22603&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">39.264</span><span style="color: #339933;">,-</span><span style="color:#800080;">78.1989</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;WINCHESTER&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;VA&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">6.70094060897827</span>
<span style="color: #0000ff;">&quot;22638&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">39.2369</span><span style="color: #339933;">,-</span><span style="color:#800080;">78.2885</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;WINCHESTER&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;VA&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">7.90875339508057</span>
<span style="color: #0000ff;">&quot;22624&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">39.2719</span><span style="color: #339933;">,-</span><span style="color:#800080;">78.0998</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;CLEAR BROOK&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;VA&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">7.94622468948364</span>
<span style="color: #0000ff;">&quot;22622&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">39.2543</span><span style="color: #339933;">,-</span><span style="color:#800080;">78.0664</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;BRUCETOWN&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;VA&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">7.98962259292603</span>
<span style="color: #0000ff;">&quot;22611&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">39.1357</span><span style="color: #339933;">,-</span><span style="color:#800080;">77.9919</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;BERRYVILLE&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;VA&quot;</span><span style="color: #339933;">,</span><span style="color:#800080;">9.72859001159668</span></pre><textarea onfocus="jQuery(this).select();" onblur="jQuery(this).hide().prev().show();" style="display:none;">"22601",39.1697,-78.1686,"WINCHESTER","VA",0
"22604",39.1676,-78.1686,"WINCHESTER","VA",0.142347455024719
"22655",39.1634,-78.2462,"STEPHENS CITY","VA",4.17041921615601
"22656",39.2137,-78.0901,"STEPHENSON","VA",5.17398071289062
"22602",39.1501,-78.269,"WINCHESTER","VA",5.53605270385742
"22603",39.264,-78.1989,"WINCHESTER","VA",6.70094060897827
"22638",39.2369,-78.2885,"WINCHESTER","VA",7.90875339508057
"22624",39.2719,-78.0998,"CLEAR BROOK","VA",7.94622468948364
"22622",39.2543,-78.0664,"BRUCETOWN","VA",7.98962259292603
"22611",39.1357,-77.9919,"BERRYVILLE","VA",9.72859001159668</textarea><a class="clipboard" href="javascript:;" onclick="jQuery(window).scrollTo(jQuery(this).prev().show().focus().prev().hide().parent(), 500);">copy code</a></div>
<p>To increase the usefulness of the result set, we sort the results of the stored procedure by their distance from the origin: least to greatest.</p>
<p>I hope this turns out to be as useful for you as it is for us.  If you&#8217;d like to get a head start, feel free to download our source files:</p>
<ul>
<li>the <a href="http://scottlib.googlecode.com/files/zip_codes.zip">data archive</a> from PopularData.com</li>
<li>the <a href="http://scottlib.googlecode.com/files/zips.sql">MySQL schema</a>, including a table for storing the zip codes, and the functions and stored procedure</li>
<li>and a <a href="http://scottlib.googlecode.com/files/mountzips.php">PHP script for mounting the data</a> into MySQL</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://aaroncollegeman.com/2009/02/calculate-the-distance-between-two-us-zip-codes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
