ice_cube
ジェムを使用してスケジュールを作成しています。31 日から始まる月次スケジュールを作成すると、31 日未満のすべての月が失われます。それらの月の月末日をスケジュールしたいと思います。私のスケジュールが 30 日に開始する場合、毎月 30 日と 2 月の最終日が必要です。閏年は問題をさらに複雑にします。
29 日、30 日、または 31 日から始まるスケジュールを作成する良い方法は何ですか?
これは、最新の IceCube で修正されています。
IceCube::Schedule.new(Time.parse('Oct 31, 2013 9:00am PDT')) do |s|
s.add_recurrence_rule(IceCube::Rule.monthly(1))
end.first(5)
[2013-10-31 09:00:00 -0700,
2013-11-30 09:00:00 -0800,
2013-12-31 09:00:00 -0800,
2014-01-31 09:00:00 -0800,
2014-02-28 09:00:00 -0800]
通常どおり、29、30、31 で day_of_month を使用してスケジュールを設定できます。次に、関数を使用してスキップされた月を特定し、単一の発生イベントを使用して設定します。確かに少しハックですが、ice_cube の制限を回避します。
これは、特定の年でスキップされる月を決定する簡単なスクリプトです。
require 'date'
def months_less_than_days(days, year = Date.today.year)
months = []
(1..11).each do |m|
eom = (Date.new(year, m+1, 1) - 1)
months << eom if eom.day < days
end
eom = (Date.new(year+1, 1, 1) - 1)
months << eom if eom.day < days
months
end
puts months_less_than_days(31) # => [2013-02-28, 2013-04-30, 2013-06-30, 2013-09-30, 2013-11-30]
これは私のすべての仕様を満たしていますが、醜く、おそらく 1 年以上のスケジュール (私はまだ気にしません) を中断します。
class LeasePaymentSchedule
def self.monthly(a bunch of args)
case start_day
when 31
schedule = IceCube::Schedule.new(start, scheduler_options) do |s|
s.add_recurrence_rule IceCube::Rule.monthly.day_of_month(-1).until(end_time)
end
when 30,29
schedule = IceCube::Schedule.new(start, scheduler_options) do |s|
s.add_recurrence_rule IceCube::Rule.monthly.day_of_month(start_day).until(end_time)
end
schedule.all_occurrences.each do |o|
next unless [1,3,6,8,10].include? o.month
missed = (o + 1.month).yday
# Probably breaks for durations longer than 1 year
schedule.add_recurrence_rule IceCube::Rule.yearly.day_of_year(missed).count(1)
end
else
schedule = IceCube::Schedule.new(start, scheduler_options) do |s|
s.add_recurrence_rule IceCube::Rule.monthly.day_of_month(start_day).until(end_time)
end
end
schedule
end
end
非常に多くの仕様:
Finished in 4.17 seconds
390 examples, 0 failures
-
shared_examples_for :a_schedule do
it 'returns an IceCube Schedule' do
schedule.should be_a IceCube::Schedule
end
it 'should start on the correct day' do
schedule.start_time.should eq expected_start
end
it 'has the right number of occurrences' do
schedule.all_occurrences.size.should eq expected_occurrences
end
end
describe :monthly do
let(:expected_occurrences) { 12 }
let(:expected_start) { date.next_month.beginning_of_day }
let(:schedule) { LeasePaymentSchedule.monthly }
before do
Date.stub(:today).and_return(date)
end
shared_examples_for :on_the_28th do
let(:date) { Time.parse "#{year}-#{month}-28" }
it_behaves_like :a_schedule
end
shared_examples_for :on_the_29th do
let(:date) { Time.parse "#{year}-#{month}-29" }
it_behaves_like :on_the_28th
it_behaves_like :a_schedule
end
shared_examples_for :on_the_30th do
let(:date) { Time.parse "#{year}-#{month}-30" }
it_behaves_like :on_the_29th
it_behaves_like :a_schedule
end
shared_examples_for :on_the_31st do
let(:date) { Time.parse "#{year}-#{month}-31" }
it_behaves_like :on_the_30th
it_behaves_like :a_schedule
end
shared_examples_for :the_whole_year do
context :february do
let(:month) { 2 }
it_behaves_like :on_the_28th
end
[ 4, 7, 9, 11 ].each do |month_num|
let(:month) { month_num }
it_behaves_like :on_the_30th
end
[ 1, 3, 5, 6, 8, 10, 12].each do |month_num|
let(:month) { month_num }
it_behaves_like :on_the_31st
end
end
context :a_leap_year do
let(:year) { 2012 }
context :february_29th do
let(:month) { 2 }
it_behaves_like :on_the_29th
end
it_behaves_like :the_whole_year
end
context :before_a_leap_year do
let(:year) { 2011 }
it_behaves_like :the_whole_year
end
context :nowhere_near_a_leap_year do
let(:year) { 2010 }
it_behaves_like :the_whole_year
end
end
day_of_month(-1)
月末までご利用いただけます。