The simplest way to group by:
- day
- week
- month
- day of the week
- hour of the day
- and more (complete list at bottom)
๐ Time zones supported!! the best part (...except for SQLite ๐)
๐ฐ Get the entire series - the other best part
Works with Rails 3.0+
Supports PostgreSQL, MySQL, and SQLite
๐ Goes hand in hand with Chartkick
User.group_by_day(:created_at).count
# {
# 2013-04-16 00:00:00 UTC => 50,
# 2013-04-17 00:00:00 UTC => 100,
# 2013-04-18 00:00:00 UTC => 34
# }
Task.group_by_month(:updated_at).count
# {
# 2013-02-01 00:00:00 UTC => 84,
# 2013-03-01 00:00:00 UTC => 23,
# 2013-04-01 00:00:00 UTC => 44
# }
Goal.group_by_year(:accomplished_at).count
# {
# 2011-01-01 00:00:00 UTC => 7,
# 2012-01-01 00:00:00 UTC => 11,
# 2013-01-01 00:00:00 UTC => 3
# }
The default time zone is Time.zone
. Pass a time zone as the second argument.
User.group_by_week(:created_at, "Pacific Time (US & Canada)").count
# {
# 2013-03-03 08:00:00 UTC => 80,
# 2013-03-10 08:00:00 UTC => 70,
# 2013-03-17 07:00:00 UTC => 54
# }
# equivalently
time_zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"]
User.group_by_week(:created_at, time_zone).count
Note: Weeks start on Sunday by default. For other days, use:
User.group_by_week(:created_at, :start => :mon) # first three letters of day
# must be the last argument
User.group_by_week(:created_at, time_zone, :start => :sat)
# change globally
Groupdate.week_start = :mon
You can also group by the day of the week or hour of the day.
# day of the week
User.group_by_day_of_week(:created_at).count
# {
# 0 => 54, # Sunday
# 1 => 2, # Monday
# ...
# 6 => 3 # Saturday
# }
# hour of the day
User.group_by_hour_of_day(:created_at, "Pacific Time (US & Canada)").count
# {
# 0 => 34,
# 1 => 61,
# ...
# 23 => 12
# }
You can order results with:
User.group_by_day(:created_at).order("day asc").count
User.group_by_week(:created_at).order("week desc").count
User.group_by_hour_of_day(:created_at).order("hour_of_day asc").count
Use it with anywhere you can use group
.
Task.completed.group_by_hour(:completed_at).average(:priority)
Go nuts!
Request.where(page: "/home").group_by_minute(:started_at).maximum(:request_time)
You have two users - one created on May 2 and one on May 5.
User.group_by_day(:created_at).count
# {
# 2013-05-02 00:00:00 UTC => 1,
# 2013-05-05 00:00:00 UTC => 1
# }
Awesome, but you want to see the first week of May. Pass a range as the third argument.
# pretend today is May 7
time_range = 6.days.ago..Time.now
User.group_by_day(:created_at, Time.zone, time_range).count
# {
# 2013-05-01 00:00:00 UTC => 0,
# 2013-05-02 00:00:00 UTC => 1,
# 2013-05-03 00:00:00 UTC => 0,
# 2013-05-04 00:00:00 UTC => 0,
# 2013-05-05 00:00:00 UTC => 1,
# 2013-05-06 00:00:00 UTC => 0,
# 2013-05-07 00:00:00 UTC => 0
# }
User.group_by_day_of_week(:created_at, Time.zone, time_range).count
# {
# 0 => 0,
# 1 => 1,
# 2 => 0,
# 3 => 0,
# 4 => 1,
# 5 => 0,
# 6 => 0
# }
Results are returned in ascending order, so no need to sort.
Also, this form of the method returns a Groupdate::Series instead of an ActiveRecord::Relation. ActiveRecord::Relation method calls (like where
and joins
) should come before this.
Add this line to your application's Gemfile:
gem 'groupdate'
Time zone support must be installed on the server.
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
Use the master version of your JDBC adapter. You will get incorrect results for versions before this commit.
# postgresql
gem "activerecord-jdbcpostgresql-adapter", :github => "jruby/activerecord-jdbc-adapter"
# mysql
gem "activerecord-jdbcmysql-adapter", :github => "jruby/activerecord-jdbc-adapter"
group_by_?
- second
- minute
- hour
- day
- week
- month
- year
- hour_of_day
- day_of_week
SQLite has no concept of timezones outside of primitive "localtime" to UTC conversions. Time zones specified in queries are silently ignored, and columns are implicitly assumed to be, and reported back as, UTC. Don't try to get too clever.
activerecord <= 4.0.0.beta1 and the pg gem returns String objects instead of Time objects. This is fixed on activerecord master
User.group_by_day(:created_at).count
# mysql2
# pg and activerecord master
{2013-04-22 00:00:00 UTC => 1} # Time object
# pg and activerecord <= 4.0.0.beta1
{"2013-04-22 00:00:00+00" => 1} # String
Another data type inconsistency
User.group_by_day_of_week(:created_at).count
# mysql2
{0 => 1, 4 => 1} # Integer
# pg and activerecord <= 4.0.0.beta1
{"0" => 1, "4" => 1} # String
# pg and activerecord master
{0.0 => 1, 4.0 => 1} # Float
These are not a result of groupdate (and unfortunately cannot be fixed by groupdate)
View the changelog
Groupdate follows Semantic Versioning
Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features