DRing
DRing

Reputation: 7039

How to handle time duration input in rails app

Im trying to figure out the best way to handle time fields. I have cook time and prep time for a recipe app Im working on and I would like it if I could allow users to basically write in the text field however they choose and and then convert that to a duration to store and then use the rails distance_of_time_in_words function to display it. Havent been able to find anything to point me in the right direction for this

EDIT: So im trying to use the Minutizer below but I keep getting

undefined method `minutize' for Chronic:Module

I created a new module chronic.rb with the code below and saved it in my app/libs folder

Then I have include Chronic in my model but I cant get rid of the error above

Upvotes: 0

Views: 584

Answers (1)

Raj
Raj

Reputation: 22956

Try this Pull Request in Chronic gem - https://github.com/mojombo/chronic/pull/231

It is able to handle the following duration:

  • one and a half minutes
  • half an hour
  • 1.5 hours
  • & even more

Pasting the code (PR by https://github.com/TalkativeTree) here since it might get deleted:

  class Minutizer

    def minutize(text)
      text = pre_normalize(text)
      extract_time(text)
    end

    def pre_normalize(text)
      text.gsub!(/half an/, 'a half')
      text.gsub!(/half a/, 'a half')
      text = Numerizer.numerize(text.downcase)
      text.gsub!(/an hour/, '1 hour')
      text.gsub!(/a hour/, '1 hour')
      text.gsub!(/a day/, '1 minute')
      text.gsub!(/a minute/, '1 day')
      text.gsub!(/a week/, '1 week')
      # used to catch halves not covered by Numerizer. Use for the conversion of 'an hour and a half' Previous gsubs will have changed it to '1 hour and haAlf' by this point.
      text.gsub!(/(\d+)\s?\w+?\s?and haAlf/) do |m|
        m.gsub!(/\A\d+/, ($1.to_f + 0.5).to_s )
      end
      text.gsub!(/\s?and haAlf/, '')
      text.gsub!(/haAlf/, "0.5")
      text.gsub!(/(seconds|secnds|second|secnd|secs)/, 'sec')
      text.gsub!(/(minutes|minute|mintues|mintes|mintue|minte)/, 'min')
      text.gsub!(/(horus|hours|huors|huor|hrs|hr)/, 'hour')
      text.gsub!(/(days|day|dy)/, 'day')
      text.gsub!(/(weeks|wks|wk)/, 'week')
      text
    end

    def extract_time(text)
      minutes = extract(text, 'week')
      minutes += extract(text, 'day')
      minutes += extract(text, 'hour')
      minutes += extract(text, 'min')
      minutes += extract(text, 'sec')
    end

    def extract(text, option)
      total = text.match(/(\d+.\d+|\d+)\s?(#{option})/)

      return 0 unless total
      digitize_time(total[1], option)
    end

    def digitize_time(time, option)
      case option
      when 'week'
        multiplier = 7 * 24 * 60
      when 'day'
        multiplier = 24 * 60
      when 'hour'
        multiplier = 60
      when 'min'
        multiplier = 1
      when 'sec'
        multiplier = 1.to_f/60
      end

      return multiplier * time.to_f
    end
  end

Just save the above file somewhere and try this below:

You also need 'numerizer' gem installed for minutizer to work.

☁  Documents  irb
2.3.0 :001 > require './minutizer.rb'
 => true
2.3.0 :002 > require 'numerizer'
 => true
2.3.0 :003 >  Minutizer.new.minutize('1.5 hours')
 => 90.0
2.3.0 :004 >

Upvotes: 1

Related Questions