Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有效地截断Ruby时间对象_Ruby_Date_Time_Truncate - Fatal编程技术网

有效地截断Ruby时间对象

有效地截断Ruby时间对象,ruby,date,time,truncate,Ruby,Date,Time,Truncate,我试图找到一种有效的方法,根据给定的分辨率截断Ruby时间对象 class Time def truncate resolution t = to_a case resolution when :min t[0] = 0 when :hour t[0] = t[1] = 0 when :day t[0] = t[1] = 0 t[2] = 1 when :month t[0]

我试图找到一种有效的方法,根据给定的分辨率截断Ruby时间对象

class Time
  def truncate resolution
    t = to_a
    case resolution
    when :min   
      t[0] = 0
    when :hour
      t[0] = t[1] = 0
    when :day
      t[0] = t[1] = 0
      t[2] = 1
    when :month 
      t[0] = t[1] = 0
      t[2] = t[3] = 1
    when :week  
      t[0] = t[1] = 0
      t[2] = 1
      t[3] -= t[6] - 1
    when :year
      t[0] = t[1] = 0
      t[2] = t[3] = t[4] = 1
    end

    Time.local *t
  end
end

有人知道实现相同任务的更快版本吗?

这已经在Rails的ActiveSupport库中为您实现了。请参阅
change
方法,以及\uu*方法开头的各种

如果您不需要Greg建议的ActiveSupport,我想您可以这样做

t = to_a
if resolution==:week
  t[0] = t[1] = 0
  t[2] = 1
  t[3] -= t[6] - 1
else
  len = [:sec, :min, :hour, :day, :month, :year].index(resolution)
  t.fill(0, 0,len)
  t.fill(1, 3,len-3)
end
Time.local *t

但我不知道这是否更快…

多亏了你们两位。因为我不使用Rails,所以我复制了代码来执行性能基准测试

require 'benchmark'

class Time
  def truncate resolution
    t = to_a
    case resolution
    when :min   
      t[0] = 0
    when :hour
      t[0] = t[1] = 0
    when :day
      t[0] = t[1] = t[2] = 0
    when :week  
      t[0] = t[1] = t[2] = 0
      t[3] -= t[6] - 1
    when :month 
      t[0] = t[1] = t[2] = 0
      t[3] = 1
    when :year
      t[0] = t[1] = t[2] = 0
      t[3] = t[4] = 1
    end

    Time.local *t 
  end

  def truncate2 resolution
    opts = {}

    case resolution
    when :min   
      opts[:sec] = 0
    when :hour
      opts[:sec] = opts[:min] = 0
    when :day
      opts[:sec] = opts[:min] = opts[:hour] = 0
    when :week  
      opts[:sec] = opts[:min] = opts[:hour] = 0
      opts[:day] = wday - 1 if wday != 1
    when :month 
      opts[:sec] = opts[:min] = opts[:hour] = 0
      opts[:day] = 1
    when :year
      opts[:sec] = opts[:min] = opts[:hour] = 0
      opts[:day] = opts[:month] = 1
    end

    change opts 
  end

  def truncate3 resolution
    t = to_a
    if resolution == :week
      t[0] = t[1] = 0
      t[2] = 1
      t[3] -= t[6] - 1
    else
      len = [:sec, :min, :hour, :day, :month, :year].index(resolution)
      t.fill(0, 0, len)
      t.fill(1, 3, len-3)
    end

    Time.local *t
  end    

  def change opts 
    Time.local(
      opts[:year]  || year,
      opts[:month] || month,
      opts[:day]   || day,
      opts[:hour]  || hour,
      opts[:min]   || (opts[:hour] ? 0 : min),
      opts[:sec]   || ((opts[:hour] || opts[:min]) ? 0 : sec),
    )
  end
end

Resolutions = [:sec, :min, :hour, :day, :week, :month, :year]

# Correctness check.
puts Resolutions.map { |r| "#{r}: #{Time.now.truncate r}" } << "\n"
puts Resolutions.map { |r| "#{r}: #{Time.now.truncate2 r}" } << "\n"
puts Resolutions.map { |r| "#{r}: #{Time.now.truncate3 r}" } << "\n"

n = 100000
now = Time.now

Benchmark.bm(10) do |x|
  x.report("truncate") { n.times { Resolutions.each { |r| now.truncate  r } } }
  x.report("truncate2") { n.times { Resolutions.each { |r| now.truncate2 r } } }
  x.report("truncate3") { n.times { Resolutions.each { |r| now.truncate3 r } } }
end

Benchmark.bm(10) do |x|
  Resolutions.each do |unit| 
    x.report("#{unit}") { n.times { now.truncate unit } }
    x.report("#{unit}2") { n.times { now.truncate2 unit } }
    x.report("#{unit}3") { n.times { now.truncate3 unit } }
  end
end
似乎我的第一个截断版本仍然是最有效的,除了今年的情况。不过,
truncate
truncate3
在今年有一个小怪癖。它显示为

2008-12-31 23:00:00 -0800
而不是

2009-01-01 00:00:00 -0700

知道为什么吗?

您不必使用Rails来使用ActiveSupport goodies。除了想使用像1.day3.minutesTime这样的东西之外,我还遇到了这个确切的问题

irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'activesupport'
=> true
irb(main):003:0> 1.day
=> 1 day
irb(main):004:0> 3.minutes
=> 180 seconds
irb(main):005:0> Time.now.beginning_of_day
=> Sun Jun 28 00:00:00 -0400 2009
irb(main):006:0>

年份案例的问题可能是,带有10个参数的Time.local被过度指定,我不确定时间库如何处理冲突:YDAY、WDAY是冗余的,isDst可能与“PDT”和“PST”不同步。消除错误的一种方法是执行
Time.local t.reverse[4,6]
这正是我想要的答案。非常感谢。我将
Time.local(*t)
切换到
self.class.gm(*t)
使用UTC,如果它是
Time
的子类,它将使用自己的类。我没有看到任何少于一天的“开始”方法。格雷格·坎贝尔的回答中提到的“改变”方法更加通用。
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'activesupport'
=> true
irb(main):003:0> 1.day
=> 1 day
irb(main):004:0> 3.minutes
=> 180 seconds
irb(main):005:0> Time.now.beginning_of_day
=> Sun Jun 28 00:00:00 -0400 2009
irb(main):006:0>