Can Ruby print out time difference (duration) read

2019-01-09 09:02发布

Can Ruby do something like this?

irb(main):001:0> start = Time.now
=> Thu Nov 05 01:02:54 -0800 2009

irb(main):002:0> Time.now - start
=> 25.239

irb(main):003:0> (Time.now - start).duration
=> "25 seconds"

(the duration method doesn't exist now)... and similarly, report

23 minutes and 35 seconds
1 hour and 33 minutes
2 days and 3 hours

(either report the whole duration, up to how many seconds, or report up to 2 numbers and units (if day and hour is reported, then no need to tell how many minutes))

11条回答
男人必须洒脱
2楼-- · 2019-01-09 09:27

Have a look at the Rails DateHelper.distance_of_time_in_words method. It will give you a great starting place. Despite being loaded with magic numbers, the approach should work for you.

查看更多
Rolldiameter
3楼-- · 2019-01-09 09:34

I came with this solution

def formate_duration(started, ended)
  differences = ["secs", "mins", "hours", "days"].reduce([[nil, [(ended - started).round, nil]]]) do |acc, unit|
    mod = unit == "hours" ? 24 : 60
    # will return [ over, unit_value ]
    # over is than used for calculation in next step
    # accumulator is in format [["unit" [ over, value]]] and we are interesting in latest over in each step
    # => This is why main diff is in this place in accumulator
    entry = acc[acc.size-1][1][0].divmod(mod)
    acc << [ unit, entry ]
  end

  # this will do string conversion and reverse in one step
  str = differences.drop(1).reduce("") do |acc, current|
    if (current[1][1] > 0)
      "#{current[1][1]} #{current[0]} #{acc}"
    else acc end
  end

  str.empty? ? "now" : str
end

Be aware that this won't work for differences bigger than 60 days (In that case you will need to add condition)

查看更多
闹够了就滚
4楼-- · 2019-01-09 09:39

Time difference a pretty printed string:

 class Numeric
   def duration
     rest, secs = self.divmod( 60 )  # self is the time difference t2 - t1
     rest, mins = rest.divmod( 60 )
     days, hours = rest.divmod( 24 )

     # the above can be factored out as:
     # days, hours, mins, secs = self.duration_as_arr
     #
     # this is not so great, because it could include zero values:
     # self.duration_as_arr.zip ['Days','Hours','Minutes','Seconds']).flatten.join ' '

     result = []
     result << "#{days} Days" if days > 0
     result << "#{hours} Hours" if hours > 0
     result << "#{mins} Minutes" if mins > 0
     result << "#{secs} Seconds" if secs > 0
     return result.join(' ')
    end
  end

Time difference as an Array:

  class Numeric
    def duration_as_arr
      rest, secs = self.divmod( 60 )
      rest, mins = rest.divmod( 60 )
      days, hours = rest.divmod( 24 )
      [days, hours, mins, secs]
    end
  end

Example:

  x = 1209801.079257
  x.duration
   => "14 Days 3 Minutes 21.079257000004873 Seconds" 
  x.duration_as_arr
   => [14, 0, 3, 21.079257000004873] 
查看更多
你好瞎i
5楼-- · 2019-01-09 09:41

Here's a quick and simple way to implement this. Set predefined measurements for seconds, minutes, hours and days. Then depending on the size of the number, output the appropriate string with the those units. We'll extend Numeric so that you can invoke the method on any numeric class (Fixnum, Bignum, or in your case Float).

class Numeric
  def duration
    secs  = self.to_int
    mins  = secs / 60
    hours = mins / 60
    days  = hours / 24

    if days > 0
      "#{days} days and #{hours % 24} hours"
    elsif hours > 0
      "#{hours} hours and #{mins % 60} minutes"
    elsif mins > 0
      "#{mins} minutes and #{secs % 60} seconds"
    elsif secs >= 0
      "#{secs} seconds"
    end
  end
end
查看更多
我欲成王,谁敢阻挡
6楼-- · 2019-01-09 09:46

There is a gem available https://rubygems.org/gems/time_diff

Which gives the difference in a hash

查看更多
登录 后发表回答