diff --git a/app/models/recurring_todos/abstract_repeat_pattern.rb b/app/models/recurring_todos/abstract_repeat_pattern.rb index e678c9e4..45332d99 100644 --- a/app/models/recurring_todos/abstract_repeat_pattern.rb +++ b/app/models/recurring_todos/abstract_repeat_pattern.rb @@ -188,31 +188,39 @@ module RecurringTodos raise "x should be 1-4 for first-fourth or 5 for last. You supplied #{x}" unless (0..5).include?(x) if x == 5 - # 5 means 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 - # convert back to local timezone - Time.zone.local(last_day.year, last_day.month, last_day.day) + return find_last_day_x_of_month(weekday, month, year) else - # 1-4th -> count upwards last -> count backwards. use UTC to avoid strange - # timezone oddities where last_day -= 1.day seems to shift tz+0100 to - # tz+0000 - start = Time.utc(year,month,1) - n = x - while n > 0 - while start.wday() != weekday - start+= 1.day - end - n -= 1 - start += 1.day unless n==0 - end - # convert back to local timezone - Time.zone.local(start.year, start.month, start.day) + return find_xth_day_of_month(x, weekday, month, year) end end + def find_last_day_x_of_month(weekday, month, year) + # 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 + # convert back to local timezone + Time.zone.local(last_day.year, last_day.month, last_day.day) + end + + def find_xth_day_of_month(x, weekday, month, year) + # 1-4th -> count upwards last -> count backwards. use UTC to avoid strange + # timezone oddities where last_day -= 1.day seems to shift tz+0100 to + # tz+0000 + start = Time.utc(year,month,1) + n = x + while n > 0 + while start.wday() != weekday + start+= 1.day + end + n -= 1 + start+= 1.day unless n==0 + end + # convert back to local timezone + Time.zone.local(start.year, start.month, start.day) + end + end end \ No newline at end of file diff --git a/test/models/recurring_todos/abstract_repeat_pattern_test.rb b/test/models/recurring_todos/abstract_repeat_pattern_test.rb index 998eb83c..d0bcf98b 100644 --- a/test/models/recurring_todos/abstract_repeat_pattern_test.rb +++ b/test/models/recurring_todos/abstract_repeat_pattern_test.rb @@ -103,9 +103,9 @@ module RecurringTodos def test_determine_start Timecop.travel(2013,1,1) do rt = create_recurring_todo - assert_equal "2013-01-01 00:00:00 UTC", rt.send(:determine_start, nil).to_s, "no previous date, use today" - assert_equal "2013-01-01 00:00:00 UTC", rt.send(:determine_start, nil, 1.day).to_s, "no previous date, use today without offset" - assert_equal "2013-01-02 00:00:00 UTC", rt.send(:determine_start, Time.zone.now, 1.day).to_s, "use previous date and offset" + assert_equal "2013-01-01 00:00:00", rt.send(:determine_start, nil).to_s(:db), "no previous date, use today" + assert_equal "2013-01-01 00:00:00", rt.send(:determine_start, nil, 1.day).to_s(:db), "no previous date, use today without offset" + assert_equal "2013-01-02 00:00:00", rt.send(:determine_start, Time.zone.now, 1.day).to_s(:db), "use previous date and offset" end end @@ -113,14 +113,14 @@ module RecurringTodos rt = create_recurring_todo # march 2014 has 5 saturdays, the last will return the 5th - assert_equal "2014-03-01 00:00:00 UTC", rt.send(:get_xth_day_of_month, 1, 6, 3, 2014).to_s - assert_equal "2014-03-22 00:00:00 UTC", rt.send(:get_xth_day_of_month, 4, 6, 3, 2014).to_s - assert_equal "2014-03-29 00:00:00 UTC", rt.send(:get_xth_day_of_month, 5, 6, 3, 2014).to_s + assert_equal "2014-03-01 00:00:00", rt.send(:get_xth_day_of_month, 1, 6, 3, 2014).to_s(:db) + assert_equal "2014-03-22 00:00:00", rt.send(:get_xth_day_of_month, 4, 6, 3, 2014).to_s(:db) + assert_equal "2014-03-29 00:00:00", rt.send(:get_xth_day_of_month, 5, 6, 3, 2014).to_s(:db) # march 2014 has 4 fridays, the last will return the 4th - assert_equal "2014-03-07 00:00:00 UTC", rt.send(:get_xth_day_of_month, 1, 5, 3, 2014).to_s - assert_equal "2014-03-28 00:00:00 UTC", rt.send(:get_xth_day_of_month, 4, 5, 3, 2014).to_s - assert_equal "2014-03-28 00:00:00 UTC", rt.send(:get_xth_day_of_month, 5, 5, 3, 2014).to_s + assert_equal "2014-03-07 00:00:00", rt.send(:get_xth_day_of_month, 1, 5, 3, 2014).to_s(:db) + assert_equal "2014-03-28 00:00:00", rt.send(:get_xth_day_of_month, 4, 5, 3, 2014).to_s(:db) + assert_equal "2014-03-28 00:00:00", rt.send(:get_xth_day_of_month, 5, 5, 3, 2014).to_s(:db) assert_raise(RuntimeError, "should check on valid weekdays"){ rt.send(:get_xth_day_of_month, 5, 9, 3, 2014) } assert_raise(RuntimeError, "should check on valid count x"){ rt.send(:get_xth_day_of_month, 6, 5, 3, 2014) }