Seb*_*ien 4 ruby ruby-on-rails date
我必须使用Ruby在两个日期之间按顺序获取所有月份名称.例如,我想得到:
['jan','feb','mars']
Run Code Online (Sandbox Code Playgroud)
当我在之间进行差异时:
1st january and March 15th
Run Code Online (Sandbox Code Playgroud)
我也希望它在日期差异大于一年时起作用.
任何的想法?
the*_*Man 10
我会去:
d1 = Date.parse('jan 1 2011')
d2 = Date.parse('dec 31 2012')
(d1..d2).map{ |m| m.strftime('%Y%m') }.uniq.map{ |m| Date::ABBR_MONTHNAMES[ Date.strptime(m, '%Y%m').mon ] }
=> ["Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"]
Run Code Online (Sandbox Code Playgroud)
要么:
(d1..d2).map{ |m| m.strftime('%Y%m') }.uniq.map{ |m| Date::ABBR_MONTHNAMES[ m[/\d\d$/ ].to_i ] }
Run Code Online (Sandbox Code Playgroud)
这可能会快一点.
问题是年界.您必须跟踪年份和月份,而不仅仅是月份,否则您将在删除日期时删除所有重复的月份索引uniq.我选择了YYYYMM格式,以获得正确的粒度.
require 'benchmark'
require 'date'
d1 = Date.parse('jan 1 2011')
d2 = Date.parse('dec 31 2012')
n = 100
Benchmark.bm(8) do |x|
x.report('strptime') { n.times { (d1..d2).map{ |m| m.strftime('%Y%m') }.uniq.map{ |m| Date::ABBR_MONTHNAMES[ Date.strptime(m, '%Y%m').mon ] } } }
x.report('regex') { n.times { (d1..d2).map{ |m| m.strftime('%Y%m') }.uniq.map{ |m| Date::ABBR_MONTHNAMES[ m[/\\d\\d$/ ].to_i ] } } }
end
user system total real
strptime 3.060000 0.020000 3.080000 ( 3.076614)
regex 2.820000 0.010000 2.830000 ( 2.829366)
Run Code Online (Sandbox Code Playgroud)
编辑:
让它变得更有趣.
我有一些代码味道一直困扰着我.我不喜欢使用Date.strftime和Date.strptime,所以我又针对这个问题进行了另一次尝试:这里有两个运行速度更快的解决方案,以及基准测试:
require 'benchmark'
require 'date'
def regex_months_between(d1, d2)
d1, d2 = [d1, d2].map{ |d| Date.parse(d) }.minmax
(d1..d2).map{ |m| m.strftime('%Y%m') }.uniq.map{ |m| Date::ABBR_MONTHNAMES[ m[/\d\d$/ ].to_i ] }
end
def months_between1(d1, d2)
d1, d2 = [d1, d2].map{ |d| Date.parse(d) }.minmax
months = (d2.mon - d1.mon) + (d2.year - d1.year) * 12
month_names = []
months.times{ |m|
month_names << Date::ABBR_MONTHNAMES[(d1 >> m).mon]
}
month_names << Date::ABBR_MONTHNAMES[d2.mon]
month_names
end
def months_between2(d1, d2)
d1, d2 = [d1, d2].map{ |d| Date.parse(d) }.minmax
months = (d2.mon - d1.mon) + (d2.year - d1.year) * 12
(d1.mon ... (d1.mon + months)).each_with_object(Date::ABBR_MONTHNAMES[d1.mon, 1]) { |month_offset, month_names_array|
month_names_array << Date::ABBR_MONTHNAMES[(d1 >> month_offset).mon]
}
end
puts regex_months_between('jan 1 2011', 'dec 31 2012').join(', ')
puts months_between1('jan 1 2011', 'dec 31 2012').join(', ')
puts months_between2('jan 1 2011', 'dec 31 2012').join(', ')
n = 100
Benchmark.bm(3) do |b|
b.report('rmb') { n.times { regex_months_between('jan 1 2011', 'dec 31 2012') } }
b.report('mb1') { n.times { months_between1('jan 1 2011', 'dec 31 2012') } }
b.report('mb2') { n.times { months_between2('jan 1 2011', 'dec 31 2012') } }
end
Run Code Online (Sandbox Code Playgroud)
输出看起来像:
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
user system total real
rmb 2.810000 0.010000 2.820000 ( 2.820732)
mb1 0.060000 0.000000 0.060000 ( 0.057763)
mb2 0.060000 0.000000 0.060000 ( 0.057112)
Run Code Online (Sandbox Code Playgroud)
有趣." rmb"现在正在落后.从测试中拉出它并使环圈100x上升:
n = 10_000
Benchmark.bm(3) do |b|
b.report('mb1') { n.times { months_between1('jan 1 2011', 'dec 31 2012') } }
b.report('mb2') { n.times { months_between2('jan 1 2011', 'dec 31 2012') } }
end
Run Code Online (Sandbox Code Playgroud)
这使:
user system total real
mb1 5.570000 0.060000 5.630000 ( 5.615789)
mb2 5.570000 0.040000 5.610000 ( 5.611323)
Run Code Online (Sandbox Code Playgroud)
这基本上是两种新方式之间的关系.作为肛门,我会去,mb2因为如果我这样做数百万次,它会更快一些,但你的里程可能会有所不同.