21

In one part of my code I convert from decimal coordinates to degrees/minutes/seconds and I use this:

double coord = 59.345235;
int sec = (int)Math.Round(coord * 3600);
int deg = sec / 3600;
sec = Math.Abs(sec % 3600);
int min = sec / 60;
sec %= 60;

How would I convert back from degrees/minutes/seconds to decimal coordinates?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Justin
  • 17,670
  • 38
  • 132
  • 201
  • Quick question, isn't assigning `sec / 3600` to `deg` the same as assigning `coord` to it? – Jeff LaFay Jul 14 '10 at 19:36
  • 2
    Thanks! Mostly everyone has been nice on here, but the MVP's became that for a reason, they're on forums all day when they should be working and take their titles way too seriously... – Justin Jul 14 '10 at 19:41
  • You're right about sec / 3600 being the same as coord, I actually got that formula off of this site and didn't look it over carefully enough. Now I'm trying to reverse it but am not thinking clearly enough to be able to do it. – Justin Jul 14 '10 at 19:44
  • @Justin: Perhaps John was a little rough in his treatment, but he is correct. The FAQ for the site does request that you leave out things like "Hi" and "Thanks" (basically anything that isn't related to the question). It isn't a matter of being rude, it's just that the site is designed to be searched, and most people aren't interested in reading those things. That being said, it's not like it's a big deal. I would also, however, request that you leave things like "C#" in the tags, not the title. And perhaps lay off the rhetoric about MVP's? Some of us have passion, not just a ton of free time. – Adam Robinson Jul 14 '10 at 19:54
  • 1
    @Justin: One of the reasons StackOverflow is so good is because the community works to keep the BS you see in all other programming forms out of here. So, please, don't put tags in your titles, use salutations and taglines, or be rude to others. If you have any question as to why we do things like we do here, go over to [meta]. –  Sep 27 '11 at 13:14
  • 1
    @Will - and one of the reasons that stack overflow kind of sucks sometimes is because of too much mall cop enforcement of silly rules like "don't use salutations". We're all people here, not robots (except for the bots of course). I think letting people express a modicum of courtesy and gratitude is well worth the extra second it takes to get to the question. I don't want to sit through people's life stories, but a simple "hello" is just fine, even welcome. Stack overflow is a great resource and I want to keep it that way, so let's not let the pendulum swing to far either way. – d512 Aug 28 '14 at 16:45

7 Answers7

41

Try this:

public double ConvertDegreeAngleToDouble( double degrees, double minutes, double seconds )
{
    //Decimal degrees = 
    //   whole number of degrees, 
    //   plus minutes divided by 60, 
    //   plus seconds divided by 3600

    return degrees + (minutes/60) + (seconds/3600);
}
Byron Sommardahl
  • 12,743
  • 15
  • 74
  • 131
  • 11
    This doesnt take into account hemisphere. – Duncan_m Dec 03 '11 at 23:37
  • 2
    One thing that confused me when using google maps was when I was trying to convert MinDec to WGS84 Datum decimal. It is quite obvious now, that it is in degrees and minutes only. My formular ends up being similar of: return degrees + (minutes/60) + (seconds/6000); – Dessus Jan 04 '14 at 23:59
12

Just to save others time, I wanted to add on to Byron's answer. If you have the point in string form (e.g. "17.21.18S"), you can use this method:

public double ConvertDegreeAngleToDouble(string point)
{
    //Example: 17.21.18S

    var multiplier = (point.Contains("S") || point.Contains("W")) ? -1 : 1; //handle south and west

    point = Regex.Replace(point, "[^0-9.]", ""); //remove the characters

    var pointArray = point.Split('.'); //split the string.

    //Decimal degrees = 
    //   whole number of degrees, 
    //   plus minutes divided by 60, 
    //   plus seconds divided by 3600

    var degrees = Double.Parse(pointArray[0]);
    var minutes = Double.Parse(pointArray[1]) / 60;
    var seconds = Double.Parse(pointArray[2]) / 3600;

    return (degrees + minutes + seconds) * multiplier;
}
Matt Cashatt
  • 23,490
  • 28
  • 78
  • 111
4

Since degrees are each worth 1 coordinate total, and minutes are worth 1/60 of a coordinate total, and seconds are worth 1/3600 of a coordinate total, you should be able to put them back together with:

new_coord = deg + min/60 + sec/3600

Beware that it won't be the exact same as the original, though, due to floating-point rounding.

eruciform
  • 7,680
  • 1
  • 35
  • 47
4

Often the western and southern hemispheres are expressed as negative degrees, and seconds contain decimals for accuracy: -86:44:52.892 Remember longitude is the X-coordinate and latitude is the Y-coordinate. This often gets mixed up because people often refer to them lat/lon and X/Y. I modified the code below for the above format.

private double ConvertDegreesToDecimal(string coordinate)
{
    double decimalCoordinate;
    string[] coordinateArray = coordinate.Split(':');
    if (3 == coordinateArray.Length)
    {
        double degrees = Double.Parse(coordinateArray[0]);
        double minutes = Double.Parse(coordinateArray[1]) / 60;
        double seconds = Double.Parse(coordinateArray[2]) / 3600;

        if (degrees > 0)
        {
            decimalCoordinate = (degrees + minutes + seconds);
        }
        else
        {
            decimalCoordinate = (degrees - minutes - seconds);
        }
    }
    return decimalCoordinate;
}
Vidsquid
  • 51
  • 4
4

CoordinateSharp is available as a Nuget package and can handle Coordinate conversions for you. It even does UTM/MGRS conversion and provides solar/lunar times relative to the input location. It's really easy to use!

Coordinate c = new Coordinate(40.465, -75.089);

//Display DMS Format
c.FormatOptions.Format = CoordinateFormatType.Degree_Minutes_Seconds;
c.ToString();//N 40º 27' 54" W 75º 5' 20.4"
c.Latitude.ToString();//N 40º 27' 54"
c.Latitude.ToDouble();//40.465

Coordinate properties are iObservable as as well. So if you change a latitude minute value for example, everything else will update.

Tronald
  • 1,520
  • 1
  • 13
  • 31
  • Beware, it is AGPL License! – Maulik Modi Aug 10 '20 at 07:53
  • It's [split licensed](https://coordinatesharp.com/Licensing). You can purchase an affordable lifetime license for unlimited uses and distributions if you do not meet the AGPL requirements. – Tronald Aug 10 '20 at 16:29
1

The accepted answer to date is inaccurate and doesn't take into account what happens when you add negative numbers to positive numbers. The below code addresses the issue and will correctly convert.

    public double ConvertDegreeAngleToDouble(double degrees, double minutes, double seconds)
    {
        var multiplier = (degrees < 0 ? -1 : 1);
        var _deg = (double)Math.Abs(degrees);
        var result = _deg + (minutes / 60) + (seconds / 3600);
        return result * multiplier;
    }
Redgum
  • 388
  • 5
  • 14
1

For those who prefer regular expression and to handle format like DDMMSS.dddS This function could easily be updated to handle other format.

C#

Regex reg = new Regex(@"^((?<D>\d{1,2}(\.\d+)?)(?<W>[SN])|(?<D>\d{2})(?<M>\d{2}(\.\d+)?)(?<W>[SN])|(?<D>\d{2})(?<M>\d{2})(?<S>\d{2}(\.\d+)?)(?<W>[SN])|(?<D>\d{1,3}(\.\d+)?)(?<W>[WE])|(?<D>\d{3})(?<M>\d{2}(\.\d+)?)(?<W>[WE])|(?<D>\d{3})(?<M>\d{2})(?<S>\d{2}(\.\d+)?)(?<W>[WE]))$");

private double DMS2Decimal(string dms)
            {
                double result = double.NaN;            

                var match = reg.Match(dms);

                if (match.Success)
                {
                    var degrees = double.Parse("0" + match.Groups["D"]);
                    var minutes = double.Parse("0" + match.Groups["M"]);
                    var seconds = double.Parse("0" + match.Groups["S"]);
                    var direction = match.Groups["W"].ToString();
                    var dec = (Math.Abs(degrees) + minutes / 60d + seconds / 3600d) * (direction == "S" || direction == "W" ? -1 : 1);
                    var absDec = Math.Abs(dec);

                    if ((((direction == "W" || direction == "E") && degrees <= 180 & absDec <= 180) || (degrees <= 90 && absDec <= 90)) && minutes < 60 && seconds < 60)
                    {
                        result = dec;
                    }

                }

                return result;

            }
Alobidat
  • 462
  • 7
  • 16