Home

Current PostGIS Blog Articles

Search

Browse

Email me

## COGO: Converting Decimal Degrees to Degrees Minutes and Seconds - and back again (PostGIS)

Thursday March 01 2012 at 00:54

KeywordsDD2MS DMS2DD Decimal Degrees Degrees Minutes Seconds
Summary

This article shows how to implement conversion functions for decimal degrees to degrees minutes and seconds and the reverse: plpgsql functions are presented called Dms2Dd Dd2Dms.

It is useful to have functions for converting from individual degrees, minutes and seconds to a single decimal degree value and back again.

Here are some useful plPgSql functions.

DMS2DD

Firstly, a function to convert individual degrees, minutes and seconds values to a single decimal degree value.

1. CREATE FUNCTION DMS2DD( p_dDeg IN FLOAT,
2.                         p_dMin IN FLOAT,
3.                         p_dSec IN FLOAT)
4. RETURNS FLOAT
5. AS
6. \$BODY\$
7. DECLARE
8.    v_dDD FLOAT;
9. BEGIN
10.    v_dDD := ABS(p_dDeg) + p_dMin / 60::FLOAT + p_dSec / 3600::FLOAT;
11.    RETURN SIGN(p_dDeg) * v_dDD;
12. END;
13. \$BODY\$
14.   LANGUAGE 'plpgsql' IMMUTABLE STRICT
15.   COST 100;

Now for some examples….

1. SELECT DMS2DD(-44,10,50);

Result:

dms2dd
-44.1805555555556
1. SELECT DMS2DD(-44,00,00);

Result:

dms2dd
-44

There is also a function, DMS2DD that takes a string input (cf Google Earth/Maps) and returns its decimal equivalent.

DD2DMS

Secondly, a function to convert a single decimal degree value to individual degrees, minutes and seconds values as a string.

1. CREATE OR REPLACE FUNCTION DD2DMS( p_dDecDeg       IN FLOAT,
2.                                    p_sDegreeSymbol IN VARCHAR(1),
3.                                    p_sMinuteSymbol IN VARCHAR(1),
4.                                    p_sSecondSymbol IN VARCHAR(1) )
5. RETURNS VARCHAR(50)
6. AS
7. \$BODY\$
8. DECLARE
9.    v_iDeg INT;
10.    v_iMin INT;
11.    v_dSec FLOAT;
12. BEGIN
13.    v_iDeg := Trunc(p_dDecDeg)::INT;
14.    v_iMin := Trunc(   (Abs(p_dDecDeg) - Abs(v_iDeg)) * 60)::INT;
15.    v_dSec := Round(((((Abs(p_dDecDeg) - Abs(v_iDeg)) * 60) - v_iMin) * 60)::NUMERIC, 3)::FLOAT;
16.    RETURN TRIM(to_char(v_iDeg,'9999')) || p_sDegreeSymbol::text || TRIM(to_char(v_iMin,'99')) || p_sMinuteSymbol::text ||
17.           CASE WHEN v_dSec = 0::FLOAT THEN '0' ELSE REPLACE(TRIM(to_char(v_dSec,'99.999')),'.000','') END || p_sSecondSymbol::text;
18. END;
19. \$BODY\$
20.   LANGUAGE 'plpgsql' IMMUTABLE STRICT
21.   COST 100;

Some examples.

1. SELECT DD2DMS(-44,'d','m','s');

Result:

dd2dms
-44d0m0s
1. SELECT DD2DMS(-44.5,'d','m','s');

Result:

dd2dms
-44d30m0s
1. SELECT DD2DMS(-44.577,'d','m','s');

Result:

dd2dms
-44d34m37.200s
1. SELECT DD2DMS(gis.DMS2DD(-44,10,50),'d','s','"');

Result:

dd2dms
-44d10s50”

DD2DMST

But what if I only want the individual degrees, minutes and seconds values from a decimal degree value?

This can be done in a number of ways eg writing three functions to extract each individual value. But the way I will do it is via a TYPE and a single function.

1. CREATE TYPE DMS AS (
2.    degree INT,
3.    MINUTE INT,
4.    SECOND FLOAT
5. );
6. -- Function
7. --
8. CREATE OR REPLACE FUNCTION DD2DMST( p_dDecDeg IN FLOAT )
9. RETURNS DMS
10. AS
11. \$BODY\$
12. DECLARE
13.    v_dms  DMS;
14. BEGIN
15.    v_dms.degree := Trunc(p_dDecDeg)::INT;
16.    v_dms.MINUTE := Trunc(   (Abs(p_dDecDeg) - Abs(v_dms.degree)) * 60)::INT;
17.    v_dms.SECOND := Round(((((Abs(p_dDecDeg) - Abs(v_dms.degree)) * 60) - v_dms.MINUTE) * 60)::NUMERIC, 3)::FLOAT;
18.    RETURN v_dms;
19. END;
20. \$BODY\$
21.   LANGUAGE 'plpgsql' IMMUTABLE STRICT
22.   COST 100;

Some examples.

1. SELECT DD2DMST(-44);

Result:

dd2dmst
(-44,0,0)
1. SELECT (DD2DMST(-44.5)).*;

Result:

degree minute second
-44 30 0
1. SELECT degree,MINUTE,SECOND FROM (SELECT (DD2DMST(-44.577)).* ) AS a;

Result:

degree minute second
-44 34 37.2
1. SELECT DD2DMST(DMS2DD(-44,10,50));

Result:

dd2dmst
(-44,10,50)

I hope these are useful to someone.

### Comment

 Name Remember E-mail Message Textile Help