From f1f03bb6d27c405986a0d4ab16b9123810a4b059 Mon Sep 17 00:00:00 2001 From: MAEDA Go Date: Wed, 14 Oct 2026 16:06:38 +0900 Subject: [PATCH 2/2] Make working_days consistent with add_working_days when the start or end date is a non-working day --- app/models/issue.rb | 5 +++-- lib/redmine/utils/date_calculation.rb | 17 ++++++++++++++--- test/unit/issue_test.rb | 6 ++++++ .../lib/redmine/utils/date_calculation_test.rb | 15 +++++++++------ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/app/models/issue.rb b/app/models/issue.rb index 0a7cc5ed3..ba1f97e29 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -1414,9 +1414,10 @@ class Issue < ApplicationRecord (start_date && due_date) ? due_date - start_date : 0 end - # Returns the duration in working days + # Returns the duration in working days, counted from the first working day + # on or after start_date in the same way as #reschedule_on does def working_duration - (start_date && due_date) ? working_days(start_date, due_date) : 0 + (start_date && due_date) ? working_days(next_working_date(start_date), due_date) : 0 end def soonest_start(reload=false) diff --git a/lib/redmine/utils/date_calculation.rb b/lib/redmine/utils/date_calculation.rb index 14dbfcde6..8b5c72a4b 100644 --- a/lib/redmine/utils/date_calculation.rb +++ b/lib/redmine/utils/date_calculation.rb @@ -20,20 +20,31 @@ module Redmine module Utils module DateCalculation - # Returns the number of working days between from and to + # Returns the number of working days after from up to and including to, + # so that add_working_days(from, working_days(from, to)) is the last + # working day on or before to + # + # Example: when Saturday and Sunday are non-working days, + # working_days(Sat 2012-10-20, Sun 2012-10-28) returns 5 + # (Mon 2012-10-22 to Fri 2012-10-26), and + # add_working_days(Sat 2012-10-20, 5) returns Fri 2012-10-26 def working_days(from, to) days = (to - from).to_i if days > 0 + # Count by whole weeks first. Any 7 consecutive days contain the + # same number of working days, wherever the weeks start. weeks = days / 7 result = weeks * (7 - non_working_week_days.size) + # Remainder loop: check day by day the remaining days, starting + # from the day after from days_left = days - weeks * 7 start_cwday = from.cwday days_left.times do |i| - unless non_working_week_days.include?(((start_cwday + i - 1) % 7) + 1) + unless non_working_week_days.include?(((start_cwday + i) % 7) + 1) result += 1 end end - result - non_working_dates_count(from, to) + result - non_working_dates_count(from + 1, to + 1) else 0 end diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index b22595c75..c9475b5da 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -2438,6 +2438,12 @@ class IssueTest < ActiveSupport::TestCase issue.reschedule_on '2012-10-13'.to_date assert_equal '2012-10-15'.to_date, issue.start_date assert_equal '2012-10-25'.to_date, issue.due_date + + # Starting on Saturday, from Monday 2012-10-15 to Friday 2012-10-19 + issue = Issue.new(:start_date => '2012-10-13', :due_date => '2012-10-19') + issue.reschedule_on '2012-10-22'.to_date + assert_equal '2012-10-22'.to_date, issue.start_date + assert_equal '2012-10-26'.to_date, issue.due_date end end diff --git a/test/unit/lib/redmine/utils/date_calculation_test.rb b/test/unit/lib/redmine/utils/date_calculation_test.rb index 6ba39aff7..d6fb362db 100644 --- a/test/unit/lib/redmine/utils/date_calculation_test.rb +++ b/test/unit/lib/redmine/utils/date_calculation_test.rb @@ -35,14 +35,17 @@ class Redmine::Utils::DateCalculationTest < ActiveSupport::TestCase def test_working_days_with_non_working_week_days with_settings :non_working_week_days => %w(6 7) do - assert_working_days 14, '2012-10-09', '2012-10-27' + assert_working_days 13, '2012-10-09', '2012-10-27' assert_working_days 4, '2012-10-09', '2012-10-15' - assert_working_days 4, '2012-10-09', '2012-10-14' + assert_working_days 3, '2012-10-09', '2012-10-14' assert_working_days 3, '2012-10-09', '2012-10-12' assert_working_days 8, '2012-10-09', '2012-10-19' assert_working_days 8, '2012-10-11', '2012-10-23' - assert_working_days 2, '2012-10-14', '2012-10-17' - assert_working_days 11, '2012-10-14', '2012-10-30' + assert_working_days 3, '2012-10-14', '2012-10-17' + assert_working_days 12, '2012-10-14', '2012-10-30' + # From Saturday and Sunday to Friday 2012-10-26 + assert_working_days 5, '2012-10-20', '2012-10-26' + assert_working_days 5, '2012-10-21', '2012-10-26' end end @@ -76,9 +79,9 @@ class Redmine::Utils::DateCalculationTest < ActiveSupport::TestCase # Registered on a non-working week day, should not be counted twice NonWorkingDate.create!(:date => '2012-10-13') with_settings :non_working_week_days => %w(6 7) do - assert_working_days 13, '2012-10-09', '2012-10-27' + assert_working_days 12, '2012-10-09', '2012-10-27' assert_working_days 1, '2012-10-09', '2012-10-11' - assert_working_days 0, '2012-10-10', '2012-10-11' + assert_working_days 1, '2012-10-10', '2012-10-11' assert_working_days 3, '2012-10-11', '2012-10-16' end end -- 2.55.0