diff --git a/app/controllers/application.rb b/app/controllers/application.rb index b08dc0be..31a370e0 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -170,11 +170,12 @@ class ApplicationController < ActionController::Base # set dates todo.recurring_todo_id = rt.id todo.due = rt.get_due_date(date) - # make sure that show_from is not in the past + show_from_date = rt.get_show_from_date(date) if show_from_date.nil? todo.show_from=nil else + # make sure that show_from is not in the past todo.show_from = show_from_date < Time.zone.now ? nil : show_from_date end diff --git a/app/models/recurring_todo.rb b/app/models/recurring_todo.rb index fbe2f07a..fdd230e7 100644 --- a/app/models/recurring_todo.rb +++ b/app/models/recurring_todo.rb @@ -495,12 +495,14 @@ class RecurringTodo < ActiveRecord::Base def get_xth_day_of_month(x, weekday, month, year) if x == 5 - # last -> count backwards - last_day = Time.zone.local(year, month, Time.days_in_month(month)) + # last -> count backwards. use UTC to avoid strange timezone oddities + # where last_day -= 1.day seems to shift tz+0100 to tz+0000 + last_day = Time.utc(year, month, Time.days_in_month(month)) while last_day.wday != weekday last_day -= 1.day end - return last_day + # convert back to local timezone + return Time.zone.local(last_day.year, last_day.month, last_day.day) else # 1-4th -> count upwards start = Time.zone.local(year,month,1) @@ -524,7 +526,8 @@ class RecurringTodo < ActiveRecord::Base case self.recurrence_selector when 0 # specific day of a specific month if start.month > month || (start.month == month && start.day >= day) - # if there is no next month n and day m in this year, search in next year + # if there is no next month n and day m in this year, search in next + # year start = Time.zone.local(start.year+1, month, 1) else # if there is a next month n, stay in this year diff --git a/test/functional/recurring_todos_controller_test.rb b/test/functional/recurring_todos_controller_test.rb index 150bce59..2bd67e67 100644 --- a/test/functional/recurring_todos_controller_test.rb +++ b/test/functional/recurring_todos_controller_test.rb @@ -79,7 +79,7 @@ class RecurringTodosControllerTest < ActionController::TestCase recurring_todo_1 = RecurringTodo.find(1) assert recurring_todo_1.completed? - # remove remaining todo + # remove remaining todo todo = Todo.find_by_recurring_todo_id(1) todo.recurring_todo_id = 2 todo.save @@ -124,5 +124,60 @@ class RecurringTodosControllerTest < ActionController::TestCase # show_from should be nil since now+4.days-10.days is in the past assert_equal nil, new_todo.show_from end + + def test_last_sunday_of_march + # this test is a duplicate of the unit test. Only this test covers the + # codepath in the controllers + + login_as(:admin_user) + + orig_rt_count = RecurringTodo.count + orig_todo_count = Todo.count + + put :create, + "context_name"=>"library", + "project_name"=>"Build a working time machine", + "recurring_todo" => + { + "daily_every_x_days"=>"1", + "daily_selector"=>"daily_every_x_day", + "description"=>"new recurring pattern", + "end_date" => "", + "ends_on" => "no_end_date", + "monthly_day_of_week" => "1", + "monthly_every_x_day" => "22", + "monthly_every_x_month2" => "1", + "monthly_every_x_month" => "1", + "monthly_every_xth_day"=>"1", + "monthly_selector"=>"monthly_every_x_day", + "notes"=>"with some notes", + "number_of_occurences" => "", + "recurring_period"=>"yearly", + "recurring_show_days_before"=>"0", + "recurring_target"=>"due_date", + "start_from"=>"", + "weekly_every_x_week"=>"1", + "weekly_return_monday"=>"w", + "yearly_day_of_week"=>"0", + "yearly_every_x_day"=>"22", + "yearly_every_xth_day"=>"5", + "yearly_month_of_year2"=>"3", + "yearly_month_of_year"=>"10", + "yearly_selector"=>"yearly_every_xth_day" + }, + "tag_list"=>"one, two, three, four" + + # check new recurring todo added + assert_equal orig_rt_count+1, RecurringTodo.count + # check new todo added + assert_equal orig_todo_count+1, Todo.count + + # find the newly created todo + new_todo = Todo.find_by_description("new recurring pattern") + assert !new_todo.nil? + + # the date should be 29 march 2009 + assert_equal Time.zone.local(2009,3,29), new_todo.due + end end diff --git a/test/unit/recurring_todo_test.rb b/test/unit/recurring_todo_test.rb index 82ba1cb5..80106554 100644 --- a/test/unit/recurring_todo_test.rb +++ b/test/unit/recurring_todo_test.rb @@ -197,6 +197,15 @@ class RecurringTodoTest < Test::Rails::TestCase assert_equal due_date1, due_date2 end + def test_last_sunday_of_march + @yearly.recurrence_selector = 1 + @yearly.every_other2 = 3 # march + @yearly.every_other3 = 5 # last + @yearly.every_count = 0 # sunday + due_date = @yearly.get_due_date(Time.zone.local(2008,10,1)) # oct 1st + assert_equal Time.zone.local(2009,3,29), due_date # march 29th + end + def test_start_from_in_future # every_day should return start_day if it is in the future @every_day.start_from = @in_three_days