ByStar

ByStar (by_*) allows you easily and reliably query ActiveRecord and Mongoid objects based on time.

Examples

Post.by_year(2013)# all posts in 2013
Post.before(Date.today)# all posts for before today
Post.yesterday# all posts for yesterday
Post.between_times(Time.zone.now-3.hours,# all posts in last 3 hours
Time.zone.now)@post.next# next post after a given post

Installation

Install this gem by adding this to your Gemfile:

gem'by_star',:git=>"git://github.com/radar/by_star"

Then run bundle install

If you are using ActiveRecord, you're done!

Mongoid users, please include the Mongoid::ByStar module for each model you wish to use the functionality.
This is the convention among Mongoid plugins.

class MyModel
include Mongoid::Document
include Mongoid::ByStar

Finder Methods

Base Scopes

ByStar adds the following finder scopes (class methods) to your model to query time ranges.
These accept a Date, Time, or DateTime object as an argument, which defaults to Time.zone.now if not specified:

between_times(start_time, end_time) Finds all records occurring between the two given times

before(end_time) Finds all records occurring before the given time

after(start_time) Finds all records occurring after the given time

Time Range Scopes

ByStar adds additional shortcut scopes based on commonly used time ranges.
See sections below for detailed argument usage of each:

by_day

by_week

by_weekend 60-hour period from 15:00 Friday to 03:00 Monday

by_fortnight A two-week period, with the first fortnight of the year beginning on 1st January

by_month

by_calendar_month Month as it appears on a calendar; days form previous/following months which are part of the first/last weeks of the given month

by_quarter 3-month intervals of the year

by_year

Relative Scopes

ByStar also adds scopes which are relative to the current time.
Note the past_* and next_* methods represent a time distance from current time (Time.zone.now),
and do not strictly end/begin evenly on a calendar week/month/year (unlike by_* methods which do.)

today Finds all occurrences on today's date

yesterday Finds all occurrences on yesterday's date

tomorrow Finds all occurrences on tomorrow's date

past_day Prior 24-hour period from current time

past_week Prior 7-day period from current time

past_fortnight Prior 14-day period from current time

past_month Prior 30-day period from current time

past_year Prior 365-day period from current time

next_day Subsequent 24-hour period from current time

next_week Subsequent 7-day period from current time

next_fortnight Subsequent 14-day period from current time

next_month Subsequent 30-day period from current time

next_year Subsequent 365-day period from current time

Superlative Finders

Find the oldest or newest records. Returns an object instance (not a relation):

newest

oldest

Instance Methods

In addition, ByStar adds instance methods to return the next / previous record in the timewise sequence.
Returns an object instance (not a relation):

object.next

object.previous

Kernel Extensions

ByStar extends the kernel Date, Time, and DateTime objects with the following instance methods,
which mirror the ActiveSupport methods beginning_of_day, end_of_week, etc:

beginning_of_weekend

end_of_weekend

beginning_of_fortnight

end_of_fortnight

beginning_of_calendar_month

end_of_calendar_month

Lastly, ByStar aliases Rails 3 Date#to_time_in_current_zone to the Rails 4 syntax #in_time_zone, if it has not already been defined.

Usage

Setting the Query Field

By default, ByStar assumes you will use the created_at field to query objects by time.
You may specify an alternate field on all query methods as follows:

Post.by_month("January",field::updated_at)

Alternatively, you may set a default in your model using the by_star_field macro:

For Time-Range type objects, only the start time is considered for previous and next.

by_year

To find records from the current year, simply call the method without any arguments:

Post.by_year

To find records based on a year you can pass it a two or four digit number:

Post.by_year(09)

This will return all posts in 2009, whereas:

Post.by_year(99)

will return all the posts in the year 1999.

You can also specify the full year:

Post.by_year(2009)Post.by_year(1999)

by_month

If you know the number of the month you want:

Post.by_month(1)

This will return all posts in the first month (January) of the current year.

If you like being verbose:

Post.by_month("January")

This will return all posts created in January of the current year.

If you want to find all posts in January of last year just do

Post.by_month(1,:year=>2007)

or

Post.by_month("January",:year=>2007)

This will perform a find using the column you've specified.

If you have a Time object you can use it to find the posts:

Post.by_month(Time.local(2012,11,24))

This will find all the posts in November 2012.

by_calendar_month

Finds records for a given month as shown on a calendar. Includes all the results of by_month, plus any results which fall in the same week as the first and last of the month. Useful for working with UI calendars which show rows of weeks.

Post.by_calendar_month

Parameter behavior is otherwise the same as by_month. Also, :start_day option is supported to specify the start day of the week (:monday, :tuesday, etc.)

by_fortnight

Fortnight numbering starts at 0. The beginning of a fortnight is Monday, 12am.

To find records from the current fortnight:

Post.by_fortnight

To find records based on a fortnight, you can pass in a number (representing the fortnight number) or a time object:

Post.by_fortnight(18)

This will return all posts in the 18th fortnight of the current year.

Post.by_fortnight(18,:year=>2012)

This will return all posts in the 18th fortnight week of 2012.

Post.by_fortnight(Time.local(2012,1,1))

This will return all posts from the first fortnight of 2012.

by_week

Week numbering starts at 0. The beginning of a week is Monday, 12am.

To find records from the current week:

Post.by_week

To find records based on a week, you can pass in a number (representing the week number) or a time object:

Post.by_week(36)

This will return all posts in the 37th week of the current year (remember week numbering starts at 0).

Post.by_week(36,:year=>2012)

This will return all posts in the 37th week of 2012.

Post.by_week(Time.local(2012,1,1))

This will return all posts from the first week of 2012.

You may pass in a :start_day option (:monday, :tuesday, etc.) to specify the starting day of the week. This may also be configured in Rails.

by_weekend

If the time passed in (or the time now is a weekend) it will return posts from 12am Saturday to 11:59:59PM Sunday. If the time is a week day, it will show all posts for the coming weekend.

Post.by_weekend(Time.now)

by_day and today

To find records for today:

Post.by_dayPost.today

To find records for a certain day:

Post.by_day(Time.local(2012,1,1))

You can also pass a string:

Post.by_day("next tuesday")

This will return all posts for the given day.

by_quarter

Finds records by 3-month quarterly period of year. Quarter numbering starts at 1. The four quarters of the year begin on Jan 1, Apr 1, Jul 1, and Oct 1 respectively.

To find records from the current quarter:

Post.by_quarter

To find records based on a quarter, you can pass in a number (representing the quarter number) or a time object:

Post.by_quarter(4)

This will return all posts in the 4th quarter of the current year.

Post.by_quarter(2,:year=>2012)

This will return all posts in the 2nd quarter of 2012.

Post.by_week(Time.local(2012,1,1))

This will return all posts from the first quarter of 2012.

Version Support

ByStar is tested against the following versions:

Ruby 1.9.3+

Rails/ActiveRecord 3.0+

Mongoid 3.0+

Note that ByStar automatically adds the following version compatibility shims:

ActiveSupport 3.x: Date#to_time_in_current_zone is aliased to Date#in_time_zone from version 4+

Mongoid 3.x: Adds support for Criteria#reorder method from version 4+

Testing

Test Setup

Specify a database by supplying a DB environmental variable:

bundle exec rake spec DB=sqlite

You can also take an ORM-specific test task for a ride:

bundle exec rake spec:active_record

Have an Active Record or Mongoid version in mind? Set the environment variables
ACTIVE_RECORD_VERSION and MONGOID_VERSION to a version of your choice. A
version number provided will translate to ~> VERSION, and the string master
will grab the latest from Github.

Test Implementation

ByStar tests use TimeCop to lock the system Time.now at Jan 01, 2014, and seed
objects with fixed dates according to spec/fixtures/shared/seeds.rb.
Note that the timezone is randomized on each run to shake-out timezone related quirks.