【问题标题】:Transforming seconds (Floats) to hours/seconds/minutes将秒(浮点数)转换为小时/秒/分钟
【发布时间】:2013-04-12 15:22:44
【问题描述】:

我有一个浮点数,它代表秒。所以,我可以有 38.93 秒。如果可能的话,我正在寻找“最重要的”方法来获得小时,或者如果小时是不可能的,或者分钟和小时是不可能的,只有几秒钟。当我说可能时,我的意思是:

如果少于 3600 秒,则为分钟或秒。如果少于 60 秒,则为秒。

现在我做了几个 if 看看应该是什么,但我认为可能必须有一种更清洁的方法。

if input > 3600
   return input/3600, 'hours'
elseif input < 3600 && input > 60
   return input/60, 'minutes'
else 
   return input, 'seconds'

谢谢

【问题讨论】:

  • 38.93 不是 Fixnum。
  • 大卫,对不起,我的意思是浮动

标签: ruby time


【解决方案1】:

恕我直言,带有范围的 case 语句会更简洁:

def some_method_name(input)
  case input
  when 0...60
    input, 'seconds'
  when 60...3600
    input/60, 'minutes'
  else
    input/3600, 'hours'
  end
end

另一种方法是先提取小时、分钟和秒:

def some_method_name(input)
  hours, seconds = input.divmod(3600)
  minutes, seconds = seconds.divmod(60)

  if hours > 0
    hours, 'hours'
  elsif minutes > 0
    minutes, 'minutes'
  else
    seconds, 'seconds'
  end
end

在 Rails 中,您当然会使用内置的 pluralization

【讨论】:

    【解决方案2】:

    这种方法的优点是能够灵活地指定所需的单位间隔。如果您愿意,可以很容易地添加几周、大约几个月、几年。它还修复了奇异值的复数。

    TimeInt = Struct.new :name, :secs
    INTERVALS = [ TimeInt[:days, 60*60*24], TimeInt[:hours, 60*60],
                  TimeInt[:minutes, 60], TimeInt[:seconds, 1] ]
    
    def time_with_adaptive_units(secs)
      ti = INTERVALS.find { |ti| secs >= ti.secs } || INTERVALS.last
      val, name = (secs.to_f/ti.secs).round, ti.name.to_s
      name.sub!(/s$/,'') if val == 1
      "#{val} #{name}"
    end
    
    [5] pry(main)> time_with_adaptive_units(1)
    => "1 second"
    [6] pry(main)> time_with_adaptive_units(45)
    => "45 seconds"
    [7] pry(main)> time_with_adaptive_units(450)
    => "7 minutes"
    [8] pry(main)> time_with_adaptive_units(4500)
    => "1 hour"
    [9] pry(main)> time_with_adaptive_units(45000)
    => "12 hours"
    [10] pry(main)> time_with_adaptive_units(450000)
    => "5 days"
    

    【讨论】:

    • 这很好!我应该在哪里定义结构?使用 Rails,我想把方法放在 ApplicationHelper 中。如果我在方法本身内部定义结构,则会出现“动态常量分配”错误。
    • @HommerSmith 如果这是您唯一使用它的地方,我会在方法定义的正上方定义 Struct 和 INTERVALS。它只是让 INTERVALS 数据自我标注的小伙伴。
    【解决方案3】:

    我能想到的有:

    total_seconds = 23456
    intervals = [3600, 60, 1].inject({rem: total_seconds, parts:[]}) do |memo, factor|
        count = (memo[:rem] / factor).floor
        memo[:rem] = memo[:rem] - (count * factor)
        memo[:parts] << count
        memo
    end
    

    你可以用

    完成它
    itervals[:parts].zip(['hours', 'minutes', 'seconds']).map{|p| p.join(' ')}.join(', ')
    

    您还可以看到,如果您愿意,将其扩展到几天、几周、几个月、几年、几十年和几个世纪是微不足道的:D

    【讨论】:

      【解决方案4】:
      input = 4000 #input in seconds
      h = {(60..3599) => ["input/60",'Minutes'], (0..59) => ["input",'Seconds'],(3600..Float::INFINITY) => ["input/3600",'Hours']}
      h.each_pair {|k,v| p "#{v.last} is #{eval(v.first)}" if k.include? input}
      
      input = 1100 #input in seconds
      h = {(60..3599) => ["input/60",'Minutes'], (0..59) => ["input",'Seconds'],(3600..Float::INFINITY) => ["input/3600",'Hours']}
      h.each_pair {|k,v| p "#{v.last} is #{eval(v.first)}" if k.include? input}
      
      input = 14 #input in seconds
      h = {(60..3599) => ["input/60",'Minutes'], (0..59) => ["input",'Seconds'],(3600..Float::INFINITY) => ["input/3600",'Hours']}
      h.each_pair {|k,v| p "#{v.last} is #{eval(v.first)}" if k.include? input}
      

      输出:

      "Hours is 1"
      "Minutes is 18"
      "Seconds is 14"
      

      【讨论】:

      • 这看起来不错,但我只想返回“小时”或“分钟”或“秒”,而不是三个
      猜你喜欢
      • 2021-10-29
      • 1970-01-01
      • 1970-01-01
      • 2012-06-15
      • 2015-06-02
      • 2011-09-01
      • 1970-01-01
      相关资源
      最近更新 更多