Skip to content

Instantly share code, notes, and snippets.

@laurynas
Created August 11, 2010 20:52
Show Gist options
  • Save laurynas/519740 to your computer and use it in GitHub Desktop.
Save laurynas/519740 to your computer and use it in GitHub Desktop.
Convert decimal to degrees, minutes, seconds sexagesimal (used for GPS coordinates)
class Float
# Convert decimal to degrees, minutes, seconds sexagesimal
# (used for GPS coordinates)
def to_sexagesimal
degrees = abs.floor
x = (abs - degrees) * 60
minutes = x.floor
seconds = (((x - minutes) * 60) * 100).round.to_f / 100
sign = self < 0 ? '-' : ''
"#{sign}#{degrees}°#{minutes}'#{seconds}\""
end
end
@svoop
Copy link

svoop commented Jan 13, 2018

Please watch what happens if you feed the float 4.883333333333333 to your method: 4°52'60.0". Kinda right, but really wrong as well.

@svoop
Copy link

svoop commented Jan 13, 2018

Try this one instead:

refine Float do
  # Convert DD angle to DMS with the degrees zero padded to +padding+ length
  def to_dms(padding=3)
    degrees = self.abs.floor
    minutes = ((self.abs - degrees) * 60).floor
    seconds = (self.abs - degrees - minutes.to_f / 60) * 3600
    minutes, seconds = minutes + 1, 0 if seconds.round(2) == 60
    degrees, minutes = degrees + 1, 0 if minutes == 60
    %Q(%s%0#{padding}d°%02d'%05.2f") % [
      ('-' if self.negative?),
      self.abs.truncate,
      minutes.abs.truncate,
      seconds.abs
    ]
  end
end

refine String do
  # Convert DMS angle to DD or +nil+ if the format is not recognized
  def to_dd
    if self =~ /\A(-)?(\d{1,3})[° ]?(\d{2})[' ]?(\d{2}\.?\d{0,2})"?\z/
      ("#{$1}1".to_i * ($2.to_f + ($3.to_f/60) + ($4.to_f/3600)))
    end
  end
end

You can test all possible DMS notations for roundtrip symmetry:

describe "Float#to_dms"
  it "must do all possible roundtrip conversions" do
    2.times.with_index do |degrees|
      60.times.with_index do |minutes|
        60.times.with_index do |seconds|
          100.times.with_index do |fractions|
            subject = %q(%03d°%02d'%02d.%02d") % [degrees, minutes, seconds, fractions]
            subject.to_dd.to_dms.must_equal subject
          end
        end
      end
    end
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment