我正在尝试提出一种根据给定分辨率截断Ruby Time对象的有效方法。
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
有没有人知道实现相同任务的更快版本?
答案 0 :(得分:6)
这已经在Rails的ActiveSupport库Time extensions中实现了。请参阅change
方法以及各种at_beginning_of_*
方法。
答案 1 :(得分:2)
感谢你们两位。由于我不使用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
结果如下:
sec: 2009-05-26 13:44:20 -0700
min: 2009-05-26 13:44:00 -0700
hour: 2009-05-26 13:00:00 -0700
day: 2009-05-26 00:00:00 -0700
week: 2009-05-25 00:00:00 -0700
month: 2009-05-01 00:00:00 -0700
year: 2008-12-31 23:00:00 -0800
sec: 2009-05-26 13:44:20 -0700
min: 2009-05-26 13:44:00 -0700
hour: 2009-05-26 13:00:00 -0700
day: 2009-05-26 00:00:00 -0700
week: 2009-05-01 00:00:00 -0700
month: 2009-05-01 00:00:00 -0700
year: 2009-01-01 00:00:00 -0800
sec: 2009-05-26 13:44:20 -0700
min: 2009-05-26 13:44:00 -0700
hour: 2009-05-26 13:00:00 -0700
day: 2009-05-26 00:00:00 -0700
week: 2009-05-25 01:00:00 -0700
month: 2009-05-01 00:00:00 -0700
year: 2008-12-31 23:00:00 -0800
user system total real
truncate 5.910000 0.020000 5.930000 ( 5.947453)
truncate2 6.180000 0.020000 6.200000 ( 6.232918)
truncate3 6.150000 0.020000 6.170000 ( 6.253931)
user system total real
sec 0.720000 0.000000 0.720000 ( 0.749040)
sec2 0.830000 0.010000 0.840000 ( 0.863029)
sec3 0.800000 0.000000 0.800000 ( 0.820477)
min 0.700000 0.000000 0.700000 ( 0.709238)
min2 0.860000 0.010000 0.870000 ( 0.860168)
min3 0.770000 0.000000 0.770000 ( 0.795734)
hour 0.680000 0.000000 0.680000 ( 0.705306)
hour2 0.850000 0.010000 0.860000 ( 0.867235)
hour3 0.740000 0.000000 0.740000 ( 0.746338)
day 0.720000 0.000000 0.720000 ( 0.724324)
day2 0.890000 0.010000 0.900000 ( 0.894312)
day3 0.780000 0.000000 0.780000 ( 0.788007)
week 0.730000 0.000000 0.730000 ( 0.736604)
week2 0.910000 0.000000 0.910000 ( 0.910925)
week3 0.600000 0.000000 0.600000 ( 0.611683)
month 0.720000 0.000000 0.720000 ( 0.719515)
month2 0.880000 0.010000 0.890000 ( 0.888045)
month3 0.780000 0.000000 0.780000 ( 0.789726)
year 1.540000 0.010000 1.550000 ( 1.565335)
year2 0.830000 0.000000 0.830000 ( 0.849737)
year3 1.600000 0.010000 1.610000 ( 1.644958)
似乎我的第一个截断版本仍然是最有效的,除了年份案例。尽管truncate
和truncate3
在一年中有一个小怪癖。它显示为
2008-12-31 23:00:00 -0800
而不是
2009-01-01 00:00:00 -0700
任何想法为什么?
答案 2 :(得分:1)
如果你不想像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
不知道它是否更快......
答案 3 :(得分:1)
您不必使用Rails来使用ActiveSupport好东西。除了想要使用 1.day 或 3.minutes 或 Time.now.beginning__of__day 等内容之外,我遇到了这个问题。 p>
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>