我想得到:
60s
格式sec==60
(dd==0 && hh==0 && mm==0
)
{li} 1min 30s
格式sec==90
(dd==0 && hh==0
)
我这样做了:
def sec_int2str(sec)
mm, ss = sec.divmod(60)
hh, mm = mm.divmod(60)
dd, hh = hh.divmod(24)
if dd==0 && hh==0 && mm==0
"#{ss}s"
elsif dd==0 && hh==0
"#{mm}min #{ss}s"
elsif dd==0
"#{hh}h #{mm}min #{ss}s"
else
"#{dd}d #{hh}h #{mm}min #{ss}s"
end
end
但逻辑太复杂了。我怎样才能简单地转换?
答案 0 :(得分:2)
正如您已经确定的那样,您基本上一遍又一遍地执行相同的操作(Numeric#divmod
),但是间隔不同(60,60,24)。因此,对我来说,一个简单的解决方案是将这些间隔与相应的标签一起放在数据结构中:
UNITS = {
"s" => 60,
"min" => 60,
"h" => 24,
"d" => Float::INFINITY
}.freeze
请注意Float::INFINITY
用于“顶级”间隔。现在我们可以使用Enumerable#reduce
迭代区间和标签,在每次迭代中将先前的divmod
商除以新区间:
def sec_int2str(quo)
UNITS.reduce([]) do |memo, (unit, int)|
break memo if quo == 0
break memo.unshift("#{quo}#{unit}") if quo == int
quo, rem = quo.divmod(int)
memo.unshift("#{rem.to_i}#{unit}")
end.join(' ')
end
如您所见,如果商为0,则第一个break
会提前结束迭代,因此我们不会得到0d 0h ...
。如果商等于当前间隔,则第二个break
结束迭代,因此我们得到60s
而不是1h 0s
(和24h ...
而不是1d 0h ...
)。
让我们测试一下:
secs = 1
mins = 60 * secs
hrs = 60 * mins
days = 24 * hrs
[ 60 * secs,
90 * secs,
60 * mins,
90 * mins + 15 * secs,
6 * hrs + 55 * mins + 30 * secs,
1 * days + 10 * secs,
75 * hrs + 30 * mins
].each do |num|
printf("%6d => %s\n", num, sec_int2str(num))
end
输出:
60 => 60s
90 => 1min 30s
3600 => 60min 0s
5415 => 1h 30min 15s
24930 => 6h 55min 30s
86410 => 24h 0min 10s
271800 => 3d 3h 30min 0s
看起来不错!
答案 1 :(得分:1)
根据how to convert 270921sec into days + hours + minutes + sec ? (ruby),您可以获取传入的秒数并获得hh
mm
和ss
。
然后你可以:
[
hh>0 && "#{hh} hours",
mm>0 && "#{mm} minutes",
ss>0 && "#{ss} seconds",
].join ', '
当然你可以得到" 2小时,4秒和#34;如果分钟为零,则不在此。