如何在Ruby中将时间缩短到最近的15分钟?

Rea*_*nly 63 ruby

有一种简单的方法可以将时间缩短到最近的15分钟吗?

这就是我目前正在做的事情.有更简单的方法吗?

t = Time.new
rounded_t = Time.local(t.year, t.month, t.day, t.hour, t.min/15*15)
Run Code Online (Sandbox Code Playgroud)

Rya*_*ary 127

你说"向下",所以我不确定你是否真的在寻找圆形或地板,但这里是两个代码.如果你向Time类添加round_offfloor方法,我认为这样的东西读得很好.额外的好处是您可以更容易地随时分区.

require 'active_support/core_ext/numeric' # from gem 'activesupport'

class Time
  # Time#round already exists with different meaning in Ruby 1.9
  def round_off(seconds = 60)
    Time.at((self.to_f / seconds).round * seconds).utc
  end

  def floor(seconds = 60)
    Time.at((self.to_f / seconds).floor * seconds).utc
  end
end

t = Time.now                    # => Thu Jan 15 21:26:36 -0500 2009
t.round_off(15.minutes)         # => Thu Jan 15 21:30:00 -0500 2009
t.floor(15.minutes)             # => Thu Jan 15 21:15:00 -0500 2009
Run Code Online (Sandbox Code Playgroud)

注意: ActiveSupport仅用于pretty 15.minutes参数.如果您不想要该依赖项,请15 * 60改用.

  • 并不是说Time对象已经具有[round](http://www.ruby-doc.org/core-2.0/Time.html#method-i-round)方法,所以这可能会破坏一些现有代码。(`p t.round(5).iso8601(10)#=>“ 2010-03-30T05:43:25.1234600000Z”`) (2认同)
  • 如果需要*下一次* 15分钟间隔,请尝试使用`ceil` def round_up(seconds = 60)Time.at((self.to_f / seconds).ceil * seconds)end的版本 (2认同)

cms*_*sjr 22

我不太熟悉ruby的语法,但你可以使用modulo 向下舍入到最接近的15分钟.(即x - (x modulo 15)).我猜想语法会是这样的

t.min - ( t.min % 15)
Run Code Online (Sandbox Code Playgroud)

这将使您的可能值集合为0,15,30和45.假设0 <= t.min <= 59.


Jar*_*erg 21

我想我会发布另一个解决方案,提供向上和向下舍入到最接近的秒数.哦,这并没有像其他一些解决方案那样改变时区.

class Time
  def round(sec=1)
    down = self - (self.to_i % sec)
    up = down + sec

    difference_down = self - down
    difference_up = up - self

    if (difference_down < difference_up)
      return down
    else
      return up
    end
  end
end

t = Time.now                             # => Mon Nov 15 10:18:29 +0200 2010
t.round(15.minutes)                      # => Mon Nov 15 10:15:00 +0200 2010
t.round(20.minutes)                      # => Mon Nov 15 10:20:00 +0200 2010
t.round(60.minutes)                      # => Mon Nov 15 10:00:00 +0200 2010
Run Code Online (Sandbox Code Playgroud)

在x.minutes功能的示例中使用了ActiveSupport.您可以使用15*60代替.

基于该解决方案,可以容易地实现地板和天花板.

  • 这是这里唯一合乎逻辑的"舍入"示例.谢谢亚诺 (2认同)

Chu*_*uck 11

由于Ruby允许Times上的算术(以秒为单位),你可以这样做:

t = Time.new
rounded_t = t-t.sec-t.min%15*60
Run Code Online (Sandbox Code Playgroud)


Bri*_*pel 11

我写了Rounding gem来处理这些案例.

四舍五入的时间就像召唤时间一样简单floor_to.也支持(ceil_toround_to)舍入和舍入到最近.

require "rounding"

Time.current.floor_to(15.minutes) # => Thu, 07 May 2015 16:45:00 UTC +00:00
Time.current.ceil_to(15.minutes)  # => Thu, 07 May 2015 17:00:00 UTC +00:00
Time.current.round_to(15.minutes) # => Thu, 07 May 2015 16:45:00 UTC +00:00
Run Code Online (Sandbox Code Playgroud)

保留原始时间的时区(在这种情况下为UTC).您不需要加载ActiveSupport - 您可以编写floor_to(15*60)它,它将正常工作.gem使用Rational数字来避免舍入错误.您可以通过提供抵消来舍入到最近的星期一round_to(1.week, Time.parse("2015-5-4 00:00:00 UTC")).我们在生产中使用它.

我写了一篇博文,解释了更多内容.希望你觉得它有用.


jew*_*eer 8

我找到了一个非常易读的解决方

这会将你的时间缩短到最后的15分钟.您可以更改15.minutes为每个时间刻度.

Time.at(Time.now.to_i - (Time.now.to_i % 15.minutes))
Run Code Online (Sandbox Code Playgroud)


Tim*_*imo 7

前言

这里有很多解决方案,我开始怀疑它们的效率(您的效率可能不是这个问题中最重要的方面)。我从这里拿了一些,然后自己扔了一些。(注意,虽然 OP 要求四舍五入到最接近的 15 分钟,但为了更简单的样本,我只用 1 分钟/60 秒完成了比较和样本)。

设置

Benchmark.bmbm do |x|
  x.report("to_f, /, floor, * and Time.at") { 1_000_000.times { Time.at((Time.now.to_f / 60).floor * 60) } }
  x.report("to_i, /, * and Time.at") { 1_000_000.times { Time.at((Time.now.to_i / 60) * 60) } }
  x.report("to_i, %, - and Time.at") { 1_000_000.times { t = Time.now.to_i; Time.at(t - (t % 60)) } }
  x.report("to_i, %, seconds and -") { 1_000_000.times { t = Time.now; t - (t.to_i % 60).seconds } }
  x.report("to_i, % and -") { 1_000_000.times { t = Time.now; t - (t.to_i % 60) } }
end
Run Code Online (Sandbox Code Playgroud)

结果

Rehearsal -----------------------------------------------------------------
to_f, /, floor, * and Time.at   4.380000   0.010000   4.390000 (  4.393235)
to_i, /, * and Time.at          3.270000   0.010000   3.280000 (  3.277615)
to_i, %, - and Time.at          3.220000   0.020000   3.240000 (  3.233176)
to_i, %, seconds and -         10.860000   0.020000  10.880000 ( 10.893103)
to_i, % and -                   4.450000   0.010000   4.460000 (  4.460001)
------------------------------------------------------- total: 26.250000sec

                                    user     system      total        real
to_f, /, floor, * and Time.at   4.400000   0.020000   4.420000 (  4.419075)
to_i, /, * and Time.at          3.220000   0.000000   3.220000 (  3.226546)
to_i, %, - and Time.at          3.270000   0.020000   3.290000 (  3.275769)
to_i, %, seconds and -         10.910000   0.010000  10.920000 ( 10.924287)
to_i, % and -                   4.500000   0.010000   4.510000 (  4.513809)
Run Code Online (Sandbox Code Playgroud)

分析结果

怎么办?好吧,事情可能会在您的硬件上运行得更快或更慢,所以不要相信我的电脑。如您所见,另一件事是,除非我们在数百万次操作的规模上执行这些操作,否则就处理能力而言,您使用哪种方法不会有太大区别(但是,请注意,例如大多数云计算解决方案提供非常少的处理能力,因此在这种环境中数百万可能是数百或数万)。

最慢,但可能是最易读的解决方案

从这个意义上说,使用它们中最慢的显然t = Time.now; t - (t.to_i % 60).seconds是合理的,因为 .seconds 在那里很酷。

不是那么慢,几乎是可读的解决方案

但是,由于实际上根本不需要它,并且操作成本是没有它的两倍,我不得不说我的选择是t = Time.now; t - (t.to_i % 60). 在我看来,它足够快,并且比此处介绍的任何其他解决方案可读性高一百万倍。这就是为什么我认为它是满足您休闲地板需求的最佳解决方案,尽管它比其他三个要慢得多。

尴尬,不是特别慢或快

此页面上投票最多的解决方案是此页面Time.at((Time.now.to_f / 60).floor * 60)上所有解决方案中最慢的(在此答案之前),并且明显慢于前 2 个解决方案。使用浮点数只是为了能够消除小数点也似乎很不合逻辑。对于四舍五入部分可以,但四舍五入对我来说听起来像是“地板”。如果它的对应物可能是四舍五入或“天花板”,那就是像t = Time.now; t - (60 - t.to_i % 60) % 60Time.at((Time.now.to_f / 60).ceil * 60)。to_i 解决方案在这里需要的双模看起来有点讨厌,所以即使它明显更快,在这里我更喜欢 ceil 方法。(基准附在这篇文章的最后)

对于需要速度的人

并列(差异是如此微不足道以至于您无法真正宣布获胜者)在测试中表现最好的两个,其中两个 to_i 变体使用稍微不同的操作组合,然后将整数转换回 Time 对象。如果您赶时间,这些是您应该使用的:

Time.at((Time.now.to_i / 60) * 60) 
t = Time.now.to_i; Time.at(t - (t % 60))
Run Code Online (Sandbox Code Playgroud)

设置四舍五入/ceil 基准

Benchmark.bmbm do |x|
  x.report("to_f, /, ceil, * and Time.at") { 1_000_000.times { Time.at((Time.now.to_f / 60).ceil * 60) } }
  x.report("to_i, %, -, %, + and Time.at") { 1_000_000.times { t = Time.now; t + (60 - t.to_i % 60) % 60 } }
end
Run Code Online (Sandbox Code Playgroud)

四舍五入/ceil 基准的结果

Rehearsal ----------------------------------------------------------------
to_f, /, ceil, * and Time.at   4.410000   0.040000   4.450000 (  4.446320)
to_i, %, -, %, + and Time.at   3.910000   0.020000   3.930000 (  3.939048)
------------------------------------------------------- total: 8.380000sec

                                   user     system      total        real
to_f, /, ceil, * and Time.at   4.420000   0.030000   4.450000 (  4.454173)
to_i, %, -, %, + and Time.at   3.860000   0.010000   3.870000 (  3.884866)
Run Code Online (Sandbox Code Playgroud)


Sha*_*ese 5

你可以这样做:

Time.at(t.to_i/(15*60)*(15*60))
Run Code Online (Sandbox Code Playgroud)