24

How do you convert Decimal Degrees to Degrees Minutes Seconds In Python? Is there a Formula already written?

smci
  • 32,567
  • 20
  • 113
  • 146
David
  • 241
  • 1
  • 2
  • 4

15 Answers15

28

This is exactly what divmod was invented for:

def decdeg2dms(dd):
    mult = -1 if dd < 0 else 1
    mnt,sec = divmod(abs(dd)*3600, 60)
    deg,mnt = divmod(mnt, 60)
    return mult*deg, mult*mnt, mult*sec

dd = 45 + 30/60 + 1/3600
print(decdeg2dms(dd))

# negative value returns all negative elements
print(decdeg2dms(-122.442))

Prints:

(45.0, 30.0, 1.0)
(-122.0, -26.0, -31.199999999953434)
PaulMcG
  • 62,419
  • 16
  • 94
  • 130
16

Here is my updated version based upon Paul McGuire's. This one should handle negatives correctly.

def decdeg2dms(dd):
   is_positive = dd >= 0
   dd = abs(dd)
   minutes,seconds = divmod(dd*3600,60)
   degrees,minutes = divmod(minutes,60)
   degrees = degrees if is_positive else -degrees
   return (degrees,minutes,seconds)
Erik L
  • 1,104
  • 15
  • 31
13

If you want to handle negatives properly, the first non-zero measure is set negative. It is counter to common practice to specify all of degrees, minutes and seconds as negative (Wikipedia shows 40° 26.7717, -79° 56.93172 as a valid example of degrees-minutes notation, in which degrees are negative and minutes have no sign), and setting degrees as negative does not have any effect if the degrees portion is 0. Here is a function that adequately handles this, based on Paul McGuire's and baens' functions:

def decdeg2dms(dd):
    negative = dd < 0
    dd = abs(dd)
    minutes,seconds = divmod(dd*3600,60)
    degrees,minutes = divmod(minutes,60)
    if negative:
        if degrees > 0:
            degrees = -degrees
        elif minutes > 0:
            minutes = -minutes
        else:
            seconds = -seconds
    return (degrees,minutes,seconds)
iamed2
  • 170
  • 2
  • 5
8

Just a couple of * 60 multiplications and a couple of int truncations, i.e.:

>>> decdegrees = 31.125
>>> degrees = int(decdegrees)
>>> temp = 60 * (decdegrees - degrees)
>>> minutes = int(temp)
>>> seconds = 60 * (temp - minutes)
>>> print degrees, minutes, seconds
31 7 30.0
>>> 
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
4

This is my Python code:

def DecimaltoDMS(Decimal):
    d = int(Decimal)
    m = int((Decimal - d) * 60)
    s = (Decimal - d - m/60) * 3600.00
    z= round(s, 2)
    if d >= 0:
        print ("N ", abs(d), "º ", abs(m), "' ", abs(z), '" ')
    else:
        print ("S ", abs(d), "º ", abs(m), "' ", abs(z), '" ')
Derek_P
  • 658
  • 8
  • 29
4

Improving @chqrlie answer:

    def deg_to_dms(deg, type='lat'):
        decimals, number = math.modf(deg)
        d = int(number)
        m = int(decimals * 60)
        s = (deg - d - m / 60) * 3600.00
        compass = {
            'lat': ('N','S'),
            'lon': ('E','W')
        }
        compass_str = compass[type][0 if d >= 0 else 1]
        return '{}º{}\'{:.2f}"{}'.format(abs(d), abs(m), abs(s), compass_str)
3

The sign has better be returned separately, so that it can be used to choose from ('N', 'S') or ('E', 'W'), for example.

import math

def dd_to_dms(degs):
    neg = degs < 0
    degs = (-1) ** neg * degs
    degs, d_int = math.modf(degs)
    mins, m_int = math.modf(60 * degs)
    secs        =           60 * mins
    return neg, d_int, m_int, secs
musiphil
  • 3,837
  • 2
  • 20
  • 26
3

Here's my slightly different approach that works the same as on my HP Prime for positive and negative decimal degrees...

def dms(deg):
    f,d = math.modf(deg)
    s,m = math.modf(abs(f) * 60)
    return (d,m,s * 60)
0

Use fmod and rounding to get the degrees and fraction separated. Multiply the fraction by 60 and repeat to get minutes and a remainder. Then multiply that last part by 60 again to get the number of seconds.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
0

Now we can use LatLon library...

https://pypi.org/project/LatLon/

>> palmyra = LatLon(Latitude(5.8833), Longitude(-162.0833)) # Location of Palmyra Atoll in decimal degrees
>> palmyra = LatLon(5.8833, -162.0833) # Same thing but simpler! 
>> palmyra = LatLon(Latitude(degree = 5, minute = 52, second = 59.88),
                     Longitude(degree = -162, minute = -4.998) # or more complicated!
>> print palmyra.to_string('d% %m% %S% %H') # Print coordinates to degree minute second
('5 52 59.88 N', '162 4 59.88 W')`
  • The version you linked is only tested to Python 2.7. There is a newer version, but even that one is only tested to Python 3.6 https://pypi.org/project/latlon3 – user3185563 Dec 19 '20 at 10:24
  • 1
    Hi, what I am using now is LatLon23 in my Python 3.7.4 https://pypi.org/project/LatLon23/#description – Sungsoo Lim Dec 20 '20 at 16:46
  • That's great. It seems to be working with 3.9 as well. It's more straightforward than Geographiclib, which is what I ended up with. – user3185563 Dec 21 '20 at 11:34
  • Just a note for users following the documentation that says that you import the module using the syntax `import latlon` You need to use the following `from latlon import LatLon` to make these examples work. Note the case –  Jul 19 '22 at 02:41
0

You can use the function clean_lat_long() from the library DataPrep if your data is in a DataFrame. Install DataPrep with pip install dataprep.

from dataprep.clean import clean_lat_long
df = pd.DataFrame({"coord": [(45.5003, -122.4420), (5.8833, -162.0833)]})

df2 = clean_lat_long(df, "coord", output_format="dms")
# print(df2)
                 coord                        coord_clean
0  (45.5003, -122.442)  45° 30′ 1.08″ N, 122° 26′ 31.2″ W
1  (5.8833, -162.0833)  5° 52′ 59.88″ N, 162° 4′ 59.88″ W

Or if latitude and longitude are in separate columns:

df = pd.DataFrame({"latitude": [45.5003, 5.8833], "longitude": [-122.4420, -162.0833]})

df2 = clean_lat_long(df, lat_col="latitude", long_col="longitude", output_format="dms")
# print(df2)
   latitude  longitude                 latitude_longitude
0   45.5003  -122.4420  45° 30′ 1.08″ N, 122° 26′ 31.2″ W
1    5.8833  -162.0833  5° 52′ 59.88″ N, 162° 4′ 59.88″ W
victoria55
  • 225
  • 2
  • 6
0
# Program to convert degree to Degree, Minutes and Seconds
# Using try and except for int data validations
try:

    # Requesting input degree from user
    print ("degree to Degree Minutes seconds converter ". upper ())
    degree = float(input ("\nEnter Degree: "))
    
    # Casting input from float to int 
    degree_d = int(degree)
    
    # Working on minutes
    minute =60 * (degree - degree_d)
    minutes = int(minute)
    
    # Working on seconds
    second = 60 * (minute - minutes)
    # Rounding seconds to whole number 
    seconds= round(second)
    
    # print 
    print (f"\nThe Answer In Degree-Minutes-Seconds are: \n{degree_d}°{minutes}'{seconds}\"  ✓\n ") 


#Except

except ValueError:
    print ("Wrong Input ")
The Thonnu
  • 3,578
  • 2
  • 8
  • 30
Codex
  • 1
0

My approach:

import sys
import math

dd = float(sys.argv[1])
f,d = math.modf(dd)
f,m = math.modf(60*f)
s = round(60*f, 6)

print(int(d), int(m), s)
Maksym
  • 11
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 19 '23 at 21:57
  • Testing with math.degrees(1.777036) and rounding set to 1 decimal place on seconds you get (101 48 60.0) -- any simplistic conversion that rounds will have this kind of issue. – DarkStar Jun 26 '23 at 19:42
0

This is a numpy version of PaulMcG's answer with the addition that it will round to tenths of a second (you can change second argument to round function) and it returns the sign (-1 or 1) as a separate value (this made it easier for me to handle as latitude/longitude values). Main difference here is that you can pass in an array of decimal_degrees or a single double value (note if you pass a list you get a list-of-lists back). Before using please make sure you are happy with the rounding behavior or you can remove it.

def to_dms(decimal_degrees):
    # convert degrees into dms and a sign indicator
    degrees = np.array(decimal_degrees)
    sign = np.where(degrees < 0, -1, 1)
    r, s = np.divmod(np.round(np.abs(degrees) * 3600, 1), 60)
    d, m = np.divmod(r, 60)
    # np.transpose([d, m, s]*sign)  # if you wanted signed results
    return np.transpose([d, m, s, sign])

# print("array test:", to_dms([101.816652, -101.816653]))
# array test: [[101. 48. 59.9000000000232831 1.] [101. 49. 0. -1.]]
DarkStar
  • 555
  • 4
  • 5
-1
def dms_to_deg(dms):
    import math
    import numpy as np
    a=math.fabs(dms)
    d=a//10000
    m=(a-d*10000)//100
    s=(a-d*10000-m*100)
    deg=(d+m/60+s/3600)*np.sign(dms)
    return deg

#---Usage
r1=dms_to_deg(243055.25)
r2=dms_to_deg(-243055.25)
print(r1,r2)
DaveL17
  • 1,673
  • 7
  • 24
  • 38
  • A Python function to Convert degree minutes seconds to degree decimal for both positive and negative numbers. Check Example in Usage. – S.M.Saifullah Jul 19 '23 at 04:13
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 23 '23 at 14:46