I have survey responses that I need to display in 2 week increments based on the created_at date. The output should be something like:
{10/1 : 4 10/15: 6 10/29: 3}
...where the first week is created from the earliest created_at date in the survey responses and the same for the last, but the latest created_at. I've seen things like group_by{ |s| s.created_at.month}
but not something for every other week, starting on the Monday of the week. Any help would be much appreciated!
CodePudding user response:
You could calculate the number of days between the current record and the oldest and then use modulo 14:
oldest_date = YourModel.minimum(:created_at).to_date
your_relation.group_by { |record|
(record.created_at.to_date - oldest_date).modulo(14)
}
CodePudding user response:
You could define a method returning the year and the week range, for example:
def by_year_and_by_two_weeks(my_date)
wk = my_date.strftime("%W").to_i/2
wks = [wk, wk.odd? ? wk 1 : wk - 1].sort # <== adjust this
[my_date.year, wks]
end
The %W
in rails uses monday as the first day of the week.
So, when you have your object:
object.created_at #=> 2021-09-19 08:58:16.78053 0200
by_year_and_by_two_weeks(object.created_at) #=> [2021, [17, 18]]
Then you can use the method for grouping.
objects.group_by { |d| by_year_and_by_two_weeks(d.created_at) }
This is an example of result after values transformation to make it readables:
{[2021, [20, 21]]=>[2021-10-14 09:00:17.421142 0200, 2021-10-15 09:00:17.421224 0200, 2021-10-06 09:00:17.421276 0200, 2021-10-10 09:00:17.421328 0200], [2021, [18, 19]]=>[2021-09-22 09:00:17.421385 0200]}
Of course you can change the by_year_and_by_two_weeks
return value as it best fits for you.
CodePudding user response:
Your requirements:
- You want to group on the monday of the starting biweekly period.
- You want the Hash key of the group to be the date of that monday.
I will also add another future-proofing requirement:
- The start and end dates can be anywhere, even accross year boundaries.
If we take these requirements, and then utilize the modulo
idea from spickermann, we can build it like this:
start_date = first_item.created_at.to_date.prev_occurring(:monday)
your_items.group_by { |item|
item_date = item.created_at.to_date
days_from_start = item_date - start_date
biweekly_offset = days_from_start.modulo(14)
biweekly_monday = item_date - biweekly_offset
biweekly_monday
}
Example:
test_dates = [
Date.new(2021, 10, 1),
Date.new(2021, 10, 6),
Date.new(2021, 10, 10),
Date.new(2021, 10, 13),
Date.new(2021, 10, 20),
Date.new(2021, 10, 31)
]
start = test_dates.first.prev_occurring(:monday)
pp test_dates.group_by { |date|
days_from_start = date - start
biweekly_offset = days_from_start.modulo(14)
biweekly_monday = date - biweekly_offset
biweekly_monday
}
Output:
{ Mon, 27 Sep 2021 => [Fri, 01 Oct 2021, Wed, 06 Oct 2021, Sun, 10 Oct 2021],
Mon, 11 Oct 2021 => [Wed, 13 Oct 2021, Wed, 20 Oct 2021],
Mon, 25 Oct 2021 => [Sun, 31 Oct 2021] }