# Getting latitude/longitude in Degree Minute Second (DMS) using QGIS Field Calculator

I have come up with the following expression to convert 5.1234 to 5°7'24.24"

``````toint(\$x) || '° ' || toint(((\$x) - toint (\$x))*60) || '`' || substr((tostring((((\$x) - toint(\$x))*60) - toint(((\$x) - toint(\$x))*60))*60), 1, 5) || '"'
``````

Here’s the problem: for some points such as 5.1234, it works. But for others, it doesn’t. I suspect the problem is the integer conversion which round up the decimal figures instead of truncating it.

Is there any other option?

• I can suggest a workaround. Not optimal, but if you are stuck right now, you can get your work done. Right click and Save As a CSV. Open the CSV in Excel or Google Docs, enter your formula (which should be cleaner and easier). Delete all fields except a unique identifier and converted DMS strings. Save it. Do a table join with existing layer and you are set. Jul 2, 2012 at 10:46
• Be careful with negative inputs. Jul 2, 2012 at 11:37
• Just to add to spatialthought's answer: rounding down to the nearest degree will work in Excel using the FLOOR() function. Jul 3, 2012 at 11:23

Nowadays there is a native function `to_dms()` for this intent included in the expression calculator.

Now, you can simply run `to_dms(5.1234, 'x', 2)`. A capture of the current doc can be seen below

I like the expression you've put together - probably no solution in QGIS 1.8, but in QGIS 1.9-dev there's a `floor()` rounding function which rounds down. For D°M'S'':

``````(CASE WHEN \$x < 0 THEN '-' ELSE '' END) || floor (abs(\$x)) || '° ' || floor(((abs(\$x)) - floor (abs(\$x))) * 60) ||'\'' || substr( (tostring((((abs(\$x)) - floor (abs(\$x))) * 60) - floor(((abs(\$x)) - floor (abs(\$x))) * 60)) * 60),1,5) || '"'
``````

Note the escaped apostrophe (`\'`).

For D°M.MMM':

``````(CASE WHEN \$x < 0 THEN '-' ELSE '' END) || floor (abs(\$x)) || '° ' || ((abs(\$x) - floor(abs(\$x))) * 60) ||'\''
``````

To limit the number of displayed decimal minutes, substitute # in the expression below with the number of digits:

``````(CASE WHEN \$x < 0 THEN '-' ELSE '' END) || floor (abs(\$x)) || '° ' ||  format_number( (abs(\$x) - floor(abs(\$x))) * 60, #) ||'\'
``````
• Just out of curiosity, how would the formula look like for Degrees, Minutes?
– mace
Jan 8, 2015 at 13:32
• Added an example; this works in QGIS 2.6 (and probably anything 2.0 and up) but there may be more elegant formatting functions available now. Jan 9, 2015 at 4:46
• Just one pitfall: Your formula only works for positive values of Easting and Northing. Negative are one too small. And I wonder how 0.5° E and 0.5° W may be distinguished. floor(+/-0.5) will always be 0, not -0. Jan 9, 2015 at 6:18
• Aaargh. The pitfalls of insufficient testing ... and here's me working in the southern (negative) hemisphere, too. Updating shortly. Jan 9, 2015 at 7:17

The modulo operator can be used to do truncation, but the resulting expression would be very ugly. It is prettier to use string substitution, but unfortunately QGIS doesn't expose any strpos or similar functions. Use `regexp_replace(\$x, '\\..*', '')` to get the whole part and `regexp_replace(\$x, '^[0-9]*\\.', '')` to get the decimal part. Use `toreal` instead of `toint` for calculations with the second expression to make sure there will be no rounding.

• Didn't have a strpos function but does now ;) github.com/qgis/Quantum-GIS/commit/… Jul 2, 2012 at 10:04
• tsk tsk tsk, so much whitespace noise. Jul 2, 2012 at 10:22
• Yeah ignore that first bit it was just a bit of clean up unrelated to the new function. Jul 2, 2012 at 10:25
• Ugly it is... will try to work it out. Jul 2, 2012 at 22:39

I made some changes to the code to get the coordinates in DMS, if necessary. Only adjustments to the EPSG information are needed.

Latitude

``````(CASE WHEN \$y < 0 THEN '-' ELSE '' END) || floor (abs(Y( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
)) || '°' || floor(((abs(Y( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
)) - floor (abs(Y( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
))) * 60) ||'\'' || substr( (tostring((((abs(Y( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
)) - floor (abs(Y( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
))) * 60) - floor(((abs(Y( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
)) - floor (abs(Y( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
))) * 60)) * 60),1,5) || '"'
``````

Longitude

``````(CASE WHEN \$x < 0 THEN '-' ELSE '' END) || floor (abs(X( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
)) || '°' || floor(((abs(X( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
)) - floor (abs(X( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
))) * 60) ||'\'' || substr( (tostring((((abs(X( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
)) - floor (abs(X( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
))) * 60) - floor(((abs(X( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
)) - floor (abs(X( transform( \$geometry, 'EPSG:31983', 'EPSG:4326'))
))) * 60)) * 60),1,5) || '"'
``````