Skip to content

Instantly share code, notes, and snippets.

@tomwhipple
Created September 2, 2012 16:25
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save tomwhipple/3601130 to your computer and use it in GitHub Desktop.
Save tomwhipple/3601130 to your computer and use it in GitHub Desktop.
convert DMS coordinates to decimal in Python
#!/env/python
# coding=utf8
"""
Converting Degrees, Minutes, Seconds formatted coordinate strings to decimal.
Formula:
DEC = (DEG + (MIN * 1/60) + (SEC * 1/60 * 1/60))
Assumes S/W are negative.
"""
import re
def dms2dec(dms_str):
"""Return decimal representation of DMS
>>> dms2dec(utf8(48°53'10.18"N))
48.8866111111F
>>> dms2dec(utf8(2°20'35.09"E))
2.34330555556F
>>> dms2dec(utf8(48°53'10.18"S))
-48.8866111111F
>>> dms2dec(utf8(2°20'35.09"W))
-2.34330555556F
"""
dms_str = re.sub(r'\s', '', dms_str)
if re.match('[swSW]', dms_str):
sign = -1
else:
sign = 1
(degree, minute, second, frac_seconds, junk) = re.split('\D+', dms_str, maxsplit=4)
return sign * (int(degree) + float(minute) / 60 + float(second) / 3600 + float(frac_seconds) / 36000)
@jelson
Copy link

jelson commented Dec 21, 2013

This code has several bugs.

On line 34, re.search should be used instead of re.match -- match only matches the beginning of the string, whereas search finds the pattern anywhere.

On line 41, the formula for conversion does not handle frac_seconds correctly; it assumes exactly one digit of frac_seconds is provided. I fixed it using the following:

frac_seconds_len = len(frac_seconds)

frac_seconds = float(frac_seconds)
for i in xrange(frac_seconds_len):
    frac_seconds = frac_seconds / 10.0

return sign * (int(degree) + float(minute) / 60 + float(second) / 3600 + float(frac_seconds) / 3600)

@Nodd
Copy link

Nodd commented Aug 19, 2014

I used something simpler for frac_seconds:

second += "." + frac_seconds
return sign * (int(degree) + float(minute) / 60 + float(second) / 3600)

@jeteon
Copy link

jeteon commented May 6, 2016

Also assumes a very rigid format in line 39. This also chokes on something like S26d15'10" as the degree variable would then be an empty string. I changed this to:

    numbers = filter(len, re.split('\D+', dms_str, maxsplit=4))       # Use filter function to remove empty strings from result
    degree = numbers[0]
    minute = numbers[1] if len(numbers) >= 2 else '0'
    second = numbers[2] if len(numbers) >= 3 else '0'
    frac_seconds = numbers[3] if len(numbers) >= 4 else '0'

I put up a fork with this fix and the fixes mentioned by others here: https://gist.github.com/jeteon/89c41e4081d87b798d8006b16a52c695.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment