Converting Latitude And Longitude Coordinates Between Decimal And Degrees, Minutes, Seconds

I received an email yesterday from a reader who needed help with implementing my blog post, “Calculating The Bearing And Compass Rose Direction Between Two Latitude / Longitude Coordinates In PHP.”

His problem: He has latitude and longitude coordinates in his database tables that are in degrees-minutes-seconds (DMS) format, rather than decimal format. In other words, his coordinates look more like 55° 45′ 06″ N, 37° 37′ 04″ E than 55.751667, 37.617778.

So, my reader needed a way to convert back and forth between the two.

Fortunately, that’s easily done with a couple PHP functions. And since there’s not a lot that comes up in a Google search about how to make those conversions in PHP (lots of standalone converters, some JavaScript code, little PHP), I’ll fill the void here.

I should also note this function can be used for my other PHP latitude / longitude post, “Getting All ZIP Codes In A Given Radius From A Known Point / ZIP Code Via PHP And MySQL.”

Converting From DMS To Decimal

The easier of the two conversions is going from degrees-minutes-seconds to decimal. That’s because just as in an hour of time, each degree has 60 minutes, and each minute has 60 seconds.

So, to convert from DMS to decimal, we simply start with the degrees; then add the minutes value divided by 60, and the seconds value divided by 3600 (60 * 60). If the coordinates are South (latitude) or West (longitude), we need to make the decimal coordinate negative; North and East coordinates are positive.

Thus, a North latitude or East longitude is converted as:

$decimal = $degrees + ($minutes / 60) + ($seconds / 3600);

A South latitude or West longitude is calculated as:

$decimal = ($degrees + ($minutes / 60) + ($seconds / 3600)) * -1;

Here’s a simple function that makes these conversions. It takes, as arguments, the degrees, minutes and seconds of either a latitude or longitude coordinate, as well as its direction (N, S, E or W), and returns a decimal response.

function DMS2Decimal($degrees = 0, $minutes = 0, $seconds = 0, $direction = 'n') {
	//converts DMS coordinates to decimal
	//returns false on bad inputs, decimal on success
	
	//direction must be n, s, e or w, case-insensitive
	$d = strtolower($direction);
	$ok = array('n', 's', 'e', 'w');
	
	//degrees must be integer between 0 and 180
	if(!is_numeric($degrees) || $degrees < 0 || $degrees > 180) {
		$decimal = false;
	}
	//minutes must be integer or float between 0 and 59
	elseif(!is_numeric($minutes) || $minutes < 0 || $minutes > 59) {
		$decimal = false;
	}
	//seconds must be integer or float between 0 and 59
	elseif(!is_numeric($seconds) || $seconds < 0 || $seconds > 59) {
		$decimal = false;
	}
	elseif(!in_array($d, $ok)) {
		$decimal = false;
	}
	else {
		//inputs clean, calculate
		$decimal = $degrees + ($minutes / 60) + ($seconds / 3600);
		
		//reverse for south or west coordinates; north is assumed
		if($d == 's' || $d == 'w') {
			$decimal *= -1;
		}
	}
	
	return $decimal;
}

You can test this function here: http://www.dougv.com/demo/php_lat_lon_conversion/dms2decimal.php

You call this function as you would any built-in PHP function. For example, assuming you have DMS coordinate values stored in the PHP variables $deg, $min, $sec and $dir, you could assign a value to a decimal equivalent variable, $dec, thus:

$dec = DMS2Decimal($deg, $min, $sec, $dir);

Converting Decimal To DMS

Going from decimal coordinates to degrees-minutes-seconds is a bit more complicated.

  • Set the DMS direction to South (negative latitude), West (negative longitude), North (positive latitude) or East (positive longitude);
  • set the decimal to its absolute (i.e., unsigned) value;
  • set degrees to be the floor of the decimal;
  • subtract degrees from decimal, to get its fractional portion;
  • multiply that by 3600, to get the total number of seconds;
  • divide the seconds by 60, to get the total number of minutes;
  • subtract the total number of minutes, times 60, from seconds; then
  • set seconds value to its floor.

To accomplish this task via a PHP function, we will pass to it six arguments: the decimal coordinate; variables for degrees, minutes, seconds and direction; and a Boolean indicating if this is a latitude or longitude coordinate.

Four of our six arguments — degrees, minutes, seconds and direction — will be passed by reference. What that means to a layman is, the values of those arguments will be set by the function, without the need to specifically set them via an evaluation.

In other words, in PHP, you usually set a variable value via a function like this:

$foo = myfunction($bar);

But we’ll do it this way:

myfunction($bar, $foo);

An example of that in practice follows the function code.

function DecimalToDMS($decimal, &$degrees, &$minutes, &$seconds, &$direction, $type = true) {
	//set default values for variables passed by reference
	$degrees = 0;
	$minutes = 0;
	$seconds = 0;
	$direction = 'X';

	//decimal must be integer or float no larger than 180;
	//type must be Boolean
	if(!is_numeric($decimal) || abs($decimal) > 180 || !is_bool($type)) {
		return false;
	}
	
	//inputs OK, proceed
	//type is latitude when true, longitude when false
	
	//set direction; north assumed
	if($type && $decimal < 0) { 
		$direction = 'S';
	}
	elseif(!$type && $decimal < 0) {
		$direction = 'W';
	}
	elseif(!$type) {
		$direction = 'E';
	}
	else {
		$direction = 'N';
	}
	
	//get absolute value of decimal
	$d = abs($decimal);
	
	//get degrees
	$degrees = floor($d);
	
	//get seconds
	$seconds = ($d - $degrees) * 3600;
	
	//get minutes
	$minutes = floor($seconds / 60);
	
	//reset seconds
	$seconds = floor($seconds - ($minutes * 60));	
}

You can see this in action here: http://www.dougv.com/demo/php_lat_lon_conversion/index.php

Let’s suppose you have the variables $deg, $min, $sec, $dir, for degrees, minutes, seconds and direction, respectively. You also have a decimal coordinate stored in $dec.

This is how you would invoke the function above to assign values to your DMS variables:

//if your decimal coordinate is a latitude:
DecimalToDMS($dec, $deg, $min, $sec, $dir, true);

//if your decimal coordinate is a longitude:
DecimalToDMS($dec, $deg, $min, $sec, $dir, false);

You can download the demo code here: Converting Latitude And Longitude Coordinates Between Decimal And Degrees, Minutes, Seconds demo code

I distribute code under the GNU GPL. See Copyright & Attribution for details.

All links in this post on delicious: http://delicious.com/dougvdotcom/converting-latitude-and-longitude-coordinates-between-decimal-and-hours-minutes-seconds

4 thoughts on “Converting Latitude And Longitude Coordinates Between Decimal And Degrees, Minutes, Seconds

  1. Matthew

    I am trying to use this, but not in a form, just as function in my wordpress. I can put the code in the functions.php, but without having a form to submit it with I am just not getting it. I think I want two functions, one for lat and one for lng then I want to say

    Right? This is just really not sinking in, any help is apreciated! Just want this decimals to dms using an on page variable not a form…thanks man!

Leave a Reply