Convert Latitude/Longitude Between Decimal and Degrees/Minutes/Seconds in C#

Latitude and longitude are usually represented in one of two formats: signed decimal and degrees/minutes/seconds (DMS). Signed decimal values range from -90 to 90 for latitude and -180 to 180 for longitude. DMS values, on the other hand, are broken into four parts: degrees, minutes, and seconds–obviously–plus a compass direction.

Converting between the two formats is not terribly difficult if you keep the following formula in mind:

Decimal Degrees = Degrees + minutes/60 + seconds/3600

Computers are good at math and converting things, so let’s write a converter to do the work for us! First, we need to define some types to work with. We have two different formats, so it makes sense for us to have a DecimalLocation and a DmsLocation. We can also get some re-use out of a DmsPoint type, and we’ll need an enumeration for PointType to help with displaying N/S & E/W directional indicators. I threw in some overloads for ToString to help with displaying results, too. Also note that N/S/E/W are determined based on the sign of Degrees for DMS points.

class DecimalLocation
{
    public decimal Latitude { get; set; }
    public decimal Longitude { get; set; }

    public override string ToString()
    {
        return string.Format("{0:f5}, {1:f5}",
            Latitude, Longitude);
    }
}

class DmsLocation
{
    public DmsPoint Latitude { get; set; }
    public DmsPoint Longitude { get; set; }

    public override string ToString()
    {
        return string.Format("{0}, {1}",
            Latitude, Longitude);
    }
}

class DmsPoint
{
    public int Degrees { get; set; }
    public int Minutes { get; set; }
    public int Seconds { get; set; }
    public PointType Type { get; set; }

    public override string ToString()
    {
        return string.Format("{0} {1} {2} {3}",
            Math.Abs(Degrees),
            Minutes,
            Seconds,
            Type == PointType.Lat
                ? Degrees < 0 ? "S" : "N"
                : Degrees < 0 ? "W" : "E");
    }
}

enum PointType
{
    Lat,
    Lon
}

Now that we’ve got our data types out of the way, we can work on the conversion. Our conversion formula shows how to calculate decimal degrees from DMS, so let’s do that first. It’s really straightforward–we just plug the formula into a function and call it for both latitude and longitude.

DecimalLocation Convert(DmsLocation dmsLocation)
{
    if (dmsLocation == null)
    {
        return null;
    }

    return new DecimalLocation
        {
            Latitude = CalculateDecimal(dmsLocation.Latitude),
            Longitude = CalculateDecimal(dmsLocation.Longitude)
        };
}

decimal CalculateDecimal(DmsPoint point)
{
    if (point == null)
    {
        return default(decimal);
    }
    return point.Degrees + (decimal)point.Minutes/60 + (decimal)point.Seconds/3600;
}

Going the other direction is a little more complicated. Ultimately, we’re just working backwards. Peel off the degrees, then calculate minutes, and seconds are left.

DmsLocation Convert(DecimalLocation decimalLocation)
{
    if (decimalLocation == null)
    {
        return null;
    }

    return new DmsLocation
        {
            Latitude = new DmsPoint
                {
                    Degrees = ExtractDegrees(decimalLocation.Latitude),
                    Minutes = ExtractMinutes(decimalLocation.Latitude),
                    Seconds = ExtractSeconds(decimalLocation.Latitude),
                    Type = PointType.Lat
                },
            Longitude = new DmsPoint
                {
                    Degrees = ExtractDegrees(decimalLocation.Longitude),
                    Minutes = ExtractMinutes(decimalLocation.Longitude),
                    Seconds = ExtractSeconds(decimalLocation.Longitude),
                    Type = PointType.Lon
                }
        };
}

int ExtractDegrees(decimal value)
{
    return (int)value;
}

int ExtractMinutes(decimal value)
{
    value = Math.Abs(value);
    return (int)((value - ExtractDegrees(value)) * 60);
}

int ExtractSeconds(decimal value)
{
    value = Math.Abs(value);
    decimal minutes = (value - ExtractDegrees(value)) * 60;
    return (int)Math.Round((minutes - ExtractMinutes(value)) * 60);
}

That’s it–we’ve got some lightweight methods to go between the two formats. Let’s whip up a quick test to verify the conversions:

void Main()
{
    DecimalLocation decimalLocation;
    DmsLocation dmsLocation;

    decimalLocation = new DecimalLocation
        {
            Latitude = 38.898611m,
            Longitude = -77.037778m
        };
    dmsLocation = Convert(decimalLocation);
    Console.WriteLine("{0} -> {1}", decimalLocation, dmsLocation);

    dmsLocation = new DmsLocation
        {
            Latitude = new DmsPoint
                {
                    Degrees = 38,
                    Minutes = 53,
                    Seconds = 55,
                    Type = PointType.Lat
                },
            Longitude = new DmsPoint
                {
                    Degrees = -77,
                    Minutes = 2,
                    Seconds = 16,
                    Type = PointType.Lon
                }
        };
    decimalLocation = Convert(dmsLocation);
    Console.WriteLine("{0} -> {1}", dmsLocation, decimalLocation);
}

// output:
//    38.89861, -77.03778 -> 38 53 55 N, 77 2 16 W
//    38 53 55 N, 77 2 16 W -> 38.89861, -76.96222

The converted values are off slightly, presumably due to some loss of precision, but the values produced are in the same general vicinity. (See here, here, and here.)

Full example:

void Main()
{
    DecimalLocation decimalLocation;
    DmsLocation dmsLocation;

    decimalLocation = new DecimalLocation
        {
            Latitude = 38.898611m,
            Longitude = -77.037778m
        };
    dmsLocation = Convert(decimalLocation);
    Console.WriteLine("{0} -> {1}", decimalLocation, dmsLocation);

    dmsLocation = new DmsLocation
        {
            Latitude = new DmsPoint
                {
                    Degrees = 38,
                    Minutes = 53,
                    Seconds = 55,
                    Type = PointType.Lat
                },
            Longitude = new DmsPoint
                {
                    Degrees = -77,
                    Minutes = 2,
                    Seconds = 16,
                    Type = PointType.Lon
                }
        };
    decimalLocation = Convert(dmsLocation);
    Console.WriteLine("{0} -> {1}", dmsLocation, decimalLocation);
}

class DecimalLocation
{
    public decimal Latitude { get; set; }
    public decimal Longitude { get; set; }

    public override string ToString()
    {
        return string.Format("{0:f5}, {1:f5}",
            Latitude, Longitude);
    }
}

class DmsLocation
{
    public DmsPoint Latitude { get; set; }
    public DmsPoint Longitude { get; set; }

    public override string ToString()
    {
        return string.Format("{0}, {1}",
            Latitude, Longitude);
    }
}

class DmsPoint
{
    public int Degrees { get; set; }
    public int Minutes { get; set; }
    public int Seconds { get; set; }
    public PointType Type { get; set; }

    public override string ToString()
    {
        return string.Format("{0} {1} {2} {3}",
            Math.Abs(Degrees),
            Minutes,
            Seconds,
            Type == PointType.Lat
                ? Degrees < 0 ? "S" : "N"
                : Degrees < 0 ? "W" : "E");
    }
}

enum PointType
{
    Lat,
    Lon
}

DecimalLocation Convert(DmsLocation dmsLocation)
{
    if (dmsLocation == null)
    {
        return null;
    }

    return new DecimalLocation
        {
            Latitude = CalculateDecimal(dmsLocation.Latitude),
            Longitude = CalculateDecimal(dmsLocation.Longitude)
        };
}

DmsLocation Convert(DecimalLocation decimalLocation)
{
    if (decimalLocation == null)
    {
        return null;
    }

    return new DmsLocation
        {
            Latitude = new DmsPoint
                {
                    Degrees = ExtractDegrees(decimalLocation.Latitude),
                    Minutes = ExtractMinutes(decimalLocation.Latitude),
                    Seconds = ExtractSeconds(decimalLocation.Latitude),
                    Type = PointType.Lat
                },
            Longitude = new DmsPoint
                {
                    Degrees = ExtractDegrees(decimalLocation.Longitude),
                    Minutes = ExtractMinutes(decimalLocation.Longitude),
                    Seconds = ExtractSeconds(decimalLocation.Longitude),
                    Type = PointType.Lon
                }
        };
}

decimal CalculateDecimal(DmsPoint point)
{
    if (point == null)
    {
        return default(decimal);
    }
    return point.Degrees + (decimal)point.Minutes/60 + (decimal)point.Seconds/3600;
}

int ExtractDegrees(decimal value)
{
    return (int)value;
}

int ExtractMinutes(decimal value)
{
    value = Math.Abs(value);
    return (int)((value - ExtractDegrees(value)) * 60);
}

int ExtractSeconds(decimal value)
{
    value = Math.Abs(value);
    decimal minutes = (value - ExtractDegrees(value)) * 60;
    return (int)Math.Round((minutes - ExtractMinutes(value)) * 60);
}

Author: Adam Prescott

I'm enthusiastic and passionate about creating intuitive, great-looking software. I strive to find the simplest solutions to complex problems, and I embrace agile principles and test-driven development.

7 thoughts on “Convert Latitude/Longitude Between Decimal and Degrees/Minutes/Seconds in C#”

  1. Brilliant stuff. Thanks for putting all of this code together so completely. I changed the Seconds in your DmsPoint Class to a decimal and changed the ExtractSeconds function to get rid of the rounding to bump up the accuracy for when I use the results with M$’s BING Maps SDK.

  2. Hi admin, i must say you have very interesting posts
    here. Your page can go viral. You need initial traffic boost only.

    How to get it? Search for: Mertiso’s tips go viral

  3. I often visit your page and have noticed that you don’t update it
    often. More frequent updates will give your blog higher rank & authority in google.

    I know that writing articles takes a lot of time, but
    you can always help yourself with miftolo’s tools which will shorten the time of
    creating an article to a few seconds.

  4. I see you don’t monetize your page, don’t waste your traffic, you can earn additional cash every
    month. You can use the best adsense alternative for any type of website (they
    approve all websites), for more info simply search in gooogle:
    boorfe’s tips monetize your website

Leave a comment