[GIS] converting coordinates from unusual DMS format to decimal

coordinatesr

So I've been shared a dataset with what to me is an unusual format for degree min second data.
In their own words:

    The coordinates provided are longitude and latitude in degrees minutes and seconds.
    So for example, coordinates recorded in the spreadsheet as 
    X_Long: -10.0135 Y_Lat:  53.5726, can be taken as Longitude: 10º 01'35" W, 
    Latitude: 53º 57'26" N using standard notation.

I need to get this into decimal. Any quick way to do this ?

Edit:

in trying to solve this I made a following code:

    # Fake data
    X_Long <- as.numeric(c(-2.4564, -1.0134, -8.01))

    long.temp <- abs(X_Long - trunc(X_Long))
    long.min <- trunc(long.temp*100)
    long.sec <- trunc(as.integer((long.temp*100 - long.min)*100))

Its giving me weird rounding errors:

    > X_Long
    [1] -2.4564 -1.0134 -8.0100
    > long.temp
    [1] 0.4564 0.0134 0.0100
    > long.min
    [1] 45  1  0
    > long.sec
    [1] 63 34 99

This seems to be coming from the trunc function – compare results here

    > long.temp*100
    [1] 45.64  1.34  1.00
    > trunc(long.temp*100)
    [1] 45  1  0

Anyone know why this is happening ?

Best Answer

How about:

fun <- function(x, ...) {
   ## determine sign, this complicates the whole thing 
   sgn <- grepl("^-", x)
   ## split on the "." separator
   parts <- strsplit(x, "\\.")
   ## extract the minute/seconds digits, convert to numeric, scale, and sign
   ifelse(sgn, -1, 1) * sapply(parts, function(x)   sum(abs(as.numeric(c(x[1L], substr(x[2L], 1, 2), substr(x[2L], 3, 5))) / c(1, 60, 3600))))
}

The code would be a lot neater without having to find the sign up front and apply it to the sum. (Well I can't see a neater way).

fun("-10.0135")
[1]  -10.02639

fun("53.5726")
[1] 53.95722

It's vectorized:

fun(c("-10.0135", "53.5726", "-35.0020"))
[1] -10.02639  53.95722 -35.00556

You probably want checks for sensible inputs, treating lon/lat separately etc.

Check round-tripping (here we have to separate for lon/lat)

  require(sp)
  dd2dms(fun("-10.0135"))
  [1] 10d1'35"W

  dd2dms(fun(c("53.5726", "-35.0020")), NS = TRUE)
  [1] 53d57'26"N 35d0'20"S 
Related Question