diff --git a/app/models/user.rb b/app/models/user.rb index 5421b56ce..d13c27b2f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -120,7 +120,10 @@ class User < ApplicationRecord where("username ILIKE ? OR email ILIKE ? OR document_number ILIKE ?", search, search, search) end scope :between_ages, ->(from, to, at_time: Time.current) do - where(date_of_birth: (at_time - to.years).beginning_of_year..(at_time - from.years).end_of_year) + start_date = at_time - (to + 1).years + 1.day + end_date = at_time - from.years + + where(date_of_birth: start_date.beginning_of_day..end_date.end_of_day) end before_validation :clean_document_number diff --git a/spec/models/budget/stats_spec.rb b/spec/models/budget/stats_spec.rb index d076d9c0b..54a133428 100644 --- a/spec/models/budget/stats_spec.rb +++ b/spec/models/budget/stats_spec.rb @@ -159,7 +159,7 @@ describe Budget::Stats do describe "#participants_by_age" do it "returns the age groups hash" do [21, 22, 23, 23, 34, 42, 43, 44, 50, 51].each do |age| - create(:user, date_of_birth: budget.phases.balloting.ends_at - age.years) + create(:user, date_of_birth: budget.phases.balloting.ends_at - age.years - rand(0..11).months) end allow(stats).to receive(:participants).and_return(User.all) @@ -182,7 +182,7 @@ describe Budget::Stats do budget = travel_to(50.years.ago) { create(:budget, :finished) } [21, 22, 23, 23, 34, 42, 43, 44, 50, 51].each do |age| - create(:user, date_of_birth: budget.phases.balloting.ends_at - age.years) + create(:user, date_of_birth: budget.phases.balloting.ends_at - age.years - rand(0..11).months) end stats = Budget::Stats.new(budget) diff --git a/spec/models/poll/stats_spec.rb b/spec/models/poll/stats_spec.rb index 9bf5f56c2..7b962a2c0 100644 --- a/spec/models/poll/stats_spec.rb +++ b/spec/models/poll/stats_spec.rb @@ -169,7 +169,7 @@ describe Poll::Stats do it "returns stats based on what happened when the voting took place" do travel_to(100.years.ago) do [16, 18, 32, 32, 33, 34, 64, 65, 71, 73, 90, 99, 105].each do |age| - create(:user, date_of_birth: age.years.ago) + create(:user, date_of_birth: age.years.ago - rand(0..11).months) end create(:poll, starts_at: 1.minute.from_now, ends_at: 2.minutes.from_now) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index f3e59ffd6..62a0663be 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -438,6 +438,80 @@ describe User do expect(User.between_ages(51, 100).count).to eq 1 end + it "does not consider that people born in the same year share the same age" do + april_1st_user = create(:user, date_of_birth: Time.zone.local(2001, 4, 1)) + april_2nd_user = create(:user, date_of_birth: Time.zone.local(2001, 4, 2)) + april_3rd_user = create(:user, date_of_birth: Time.zone.local(2001, 4, 3)) + + travel_to "2021-04-02" do + expect(User.between_ages(18, 19)).to eq [april_3rd_user] + expect(User.between_ages(20, 21)).to match_array [april_1st_user, april_2nd_user] + expect(User.between_ages(19, 20)).to match_array [april_1st_user, april_2nd_user, april_3rd_user] + end + end + + it "works on leap years with users born on leap years" do + leap_day_user = create(:user, date_of_birth: Time.zone.local(2000, 2, 29)) + march_1st_user = create(:user, date_of_birth: Time.zone.local(2000, 3, 1)) + + travel_to "2024-02-28" do + expect(User.between_ages(22, 23)).to match_array [leap_day_user, march_1st_user] + expect(User.between_ages(23, 24)).to match_array [leap_day_user, march_1st_user] + expect(User.between_ages(24, 25)).to eq [] + end + + travel_to "2024-02-29" do + expect(User.between_ages(22, 23)).to eq [march_1st_user] + expect(User.between_ages(23, 24)).to eq [leap_day_user, march_1st_user] + expect(User.between_ages(24, 25)).to eq [leap_day_user] + end + + travel_to "2024-03-01" do + expect(User.between_ages(22, 23)).to eq [] + expect(User.between_ages(23, 24)).to match_array [leap_day_user, march_1st_user] + expect(User.between_ages(24, 25)).to match_array [leap_day_user, march_1st_user] + end + end + + it "works on non-leap years with users born on leap years" do + leap_day_user = create(:user, date_of_birth: Time.zone.local(2000, 2, 29)) + march_1st_user = create(:user, date_of_birth: Time.zone.local(2000, 3, 1)) + + travel_to "2023-02-28" do + expect(User.between_ages(21, 22)).to match_array [leap_day_user, march_1st_user] + expect(User.between_ages(22, 23)).to match_array [leap_day_user, march_1st_user] + expect(User.between_ages(23, 24)).to eq [] + end + + travel_to "2023-03-01" do + expect(User.between_ages(21, 22)).to eq [] + expect(User.between_ages(22, 23)).to match_array [leap_day_user, march_1st_user] + expect(User.between_ages(23, 24)).to match_array [leap_day_user, march_1st_user] + end + end + + it "works on leap years with users born on non-leap years" do + march_1st_user = create(:user, date_of_birth: Time.zone.local(2001, 3, 1)) + + travel_to "2024-02-28" do + expect(User.between_ages(21, 22)).to eq [march_1st_user] + expect(User.between_ages(22, 23)).to eq [march_1st_user] + expect(User.between_ages(23, 24)).to eq [] + end + + travel_to "2024-02-29" do + expect(User.between_ages(21, 22)).to eq [march_1st_user] + expect(User.between_ages(22, 23)).to eq [march_1st_user] + expect(User.between_ages(23, 24)).to eq [] + end + + travel_to "2024-03-01" do + expect(User.between_ages(21, 22)).to eq [] + expect(User.between_ages(22, 23)).to match_array [march_1st_user] + expect(User.between_ages(23, 24)).to match_array [march_1st_user] + end + end + it "returns users between certain ages on a reference date" do reference_date = 20.years.ago