HiveBrain v1.2.0
Get Started
← Back to all entries
snippetrubyModerate

Convert total minutes into "Hours:minute:seconds" for marathon data

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
totalmarathonconvertintohourssecondsforminutesdataminute

Problem

The point of the script below is to read in the 10th column which is the total number of minutes a runner took to finish the marathon and convert it into form of "hours:minutes:seconds". Is there a better way?

require 'csv'

File.open('bostonmarathon-2012-results.txt', 'w') {  |f| 
  skip = true
  CSV.foreach("bostonmarathon-2012-results.csv") do |row|
    if skip
      skip = false
    else
      total_seconds = row[10].to_f * 60
      seconds = total_seconds % 60
      minutes = (total_seconds / 60) % 60
      hours = total_seconds / (60 * 60)

      f.puts(format("%02d:%02d:%02d", hours, minutes, seconds))
    end
  end
}


Time starts as in total minutes in decimal format: 142.93

Example Data:

division,name,city,gender,age,official,bib,overall,state,genderdiv,net,country
4 / 26,"Soejima, Masazumi",Fukuoka City,M,41,83.45,W1,4 / 35,,4 / 26,83.45,JPN
14 / 4335,"Gebremariam, Gebregziabher",Tigray,M,27,142.93,2,14 / 21616,,14 / 12621,142.93,ETH
6 / 26,"Van Dyk, Ernst F.",Paarl,M,39,84.38,W2,6 / 35,,6 / 26,84.38,RSA
2 / 26,"Fearnley, Kurt H.",Hamilton,M,31,81.65,W3,2 / 35,,2 / 26,81.65,AUS
3 / 26,"Hokinoue, Kota",Iizuka,M,38,83.43,W4,3 / 35,,3 / 26,83.43,JPN

Solution

-
Use do...end for multiline blocks. You're already doing it for the innermost block, but not the File.open block for some reason

-
CSV.foreach accepts a hash of options. One of them is :headers which you can set to true or :first_row. This will

  • skip the header row when iterating (so you can skip skip and the if..else-branching), and



  • let you refer to a column by its header text instead of an opaque numerical index.



For the time-formatting you can use #divmod to get both quotient and remainder of a division in one go. Add some array destructuring, and you get this:

hours, remainder = total_seconds.divmod(60**2)
minutes, seconds = remainder.divmod(60)


Pretty clean, I think.

Alternatively, here's a hacky(!) idea. You could just treat the seconds as a regular unix timestamp, and do something like

Time.at(total_seconds).strftime("%k:%M:%S")


The assumption here is of course that no one took more than 24 hours to complete the marathon. If they did, the hour would of course roll over. It seems like an ok assumption in this particular case, but it's obviously not something that'd work for any context. It's kinda clever, but it's definitely a hack.

Code Snippets

hours, remainder = total_seconds.divmod(60**2)
minutes, seconds = remainder.divmod(60)
Time.at(total_seconds).strftime("%k:%M:%S")

Context

StackExchange Code Review Q#55948, answer score: 11

Revisions (0)

No revisions yet.