Chronological: The 'Start' of Your Fun Will Never 'End'
Chronological is your one-stop solution for handling time ranges in your classes.
Have an item that is only available between two dates/times? In these situations, there is quite a bit of logic which is common among use cases and that's what Chronological provides.
Supported Rubies
- MRI Ruby 1.9.2
- MRI Ruby 1.9.3
- JRuby (in 1.9 compat mode)
Installation
First:
gem install chronologicalThen in your script:
require 'chronological'Finally in your class:
include Chronologicalor from IRB
irb -r 'chronological'
Basic Usage
The easiest way to use Chronological is to just let it know which strategy you would like to use for the time range for that particular object.
class MyTimeRangeClass
include Chronological
timeframe :type => :absolute
endThis will look for a started_at and an ended_at method on your object and
will base all of its dynamic methods on those.
Now you can use any of the methods that Chronological adds to your class:
Range Status Predicates
-
started?- Whether it is currently on or after the start date -
ended?- Whether it is currently on or after the end date -
not_yet_ended?- Whether it is currently before the end date -
in_progress?(aliased toactive?) - Whether it is between the start and end dates -
inactive?- The inverse ofin_progress?/active?
Scheduling Validity Predicates
-
scheduled?- Whether all of the pieces needed to determine a timeframe have been set -
partially_scheduled?- Whether any of the pieces needed to determine a timeframe have been set
Range Type Predicates
-
same_day?- Whether the starting time and the ending time are on the same day -
one_day?- Whether the starting time and the ending time are less than 24 hours apart -
multi_day?- Whether the starting time and the ending time are on different days
Other Methods
-
duration- A Hash containing the days, hours, minutes and seconds
Scopes
Each of these methods also has a corresponding ActiveRelation method that will represents all of the items that meet the requirements of that method.
startedendednot_yet_ended-
in_progress(also aliased toactive?) scheduledpartially_scheduledone_daymulti_day
Example
If this is true:
range_instance = InstanceWithTimeRange.create
range_instance.started? #=> trueThen this would also be the case:
expect { InstanceWithTimeRange.started }.to include range_instance #=> trueOrdering
-
by_duration(:asc)- Sort the results by the length of the duration -
by_date(:asc)- Intelligently sort based on the start and end date
Advanced Usage
Note 1: All durations and offsets are represented in seconds. Note 2: All 'Defaults' are in the same order as the 'Options' above them.
Strategies
Chronological is extremely flexible and can handle multiple strategies for calculating your time range information.
If you choose to use our default field names, you can simply pass the strategy in as a symbol and it will Just Work(tm).
class MyTimeRangeClass
timeframe :type => :duration_until_end
endAlternatively, you can pass in the specific set of options per strategy as a hash and set the values to the field names you want Chronological to use.
class MyTimeRangeClass
timeframe :ending_time => :available_until,
:duration => :length_of_availability
endAbsolute
Options: starting_time and ending_time
Defaults: started_at and ended_at
Example: The concert starts at 5:30pm and ends at 11:30pm
Relative
Options: base_of_offset, starting_offset and ending_offset
Defaults: base_of_range_offset, start_of_range_offset and end_of_range_offset
Example: You can buy the ticket anytime between 1-2 weeks before the event starts
Dual Relative
Options: base_of_starting_offset, starting_offset, base_of_ending_offset and ending_offset
Defaults: base_of_range_starting_offset, start_of_range_offset, base_of_range_ending_offset and end_of_range_offset
Example: The coupon is active from 2 hours after the first sale until 3 hours before the store closes
Duration From Start
Options: starting_time, duration
Defaults: started_at and duration_in_seconds
Example: The donut shop opens at 7am but only for 30 minutes
Duration Until End
Options: ending_time, duration
Defaults: ended_at and duration_in_seconds
Example: Your 'roadie' pass will only get you backstage for the 30 minutes before the band goes on stage at 9pm
Duration From Relative Start
Options: base_of_starting_offset, starting_offset and duration
Defaults: base_of_range_starting_offset, start_of_range_offset and duration_in_seconds
Example: The party will start 30 minutes after the concert ends and last for 4 hours
Duration Until A Relative End
Options: base_of_ending_offset, ending_offset and duration
Defaults: base_of_range_ending_offset, end_of_range_offset and duration_in_seconds
Example: The secret vault will be open for 3 hours and will relock 15 minutes prior to the office opening
Determining Absolute Dates
Other than the 'Absolute' strategy above, any of those combinations will calculate the absolute dates of the time range and make them available via these accessors:
started_atended_atstarted_onended_on
If you want to override the fields that Chronological creates to access those values, simply pass in the option with the name of the field you would like.
Example
class MyTimeRangeClass
timeframe :base_of_offset => :event_start_time,
:starting_offset => :starting_availability_offset
:ending_offset => :ending_availability_offset,
:starting_time => :custom_start_field
:ending_time => :custom_end_field
endNote: The :base_of_offset option can be anything that has accessor
methods for the field.
Advanced Method Usage
Range Status As Of A Given Date
All range status methods can take an :as_of option which will replace the
default behavior which is Time.now.utc. Using this option you can more easily
see if an instance (or instances) would be started, ended, etc as of a given
date.
All range status methods can also take a :base_of option this is only
meaningful for strategies which utilize an offset for either the start
time or the end time which will calculate the absolute time based on
that time rather than any time stored within the instance.
Affected methods:
started?ended?not_yet_ended?-
in_progress?(oractive?) inactive?
Affected scopes:
startedendednot_yet_ended-
in_progress(oractive) inactive?
range_instance = MyTimeRangeClass.create
range_instance.ended? #=> false
range_instance.ended? :as_of => 42.years.from_now #=> true
MyTimeRangeClass.ended #=> []
MyTimeRangeClass.ended :as_of => 42.years.from_now #=> [range_instance]Duration Components
When calling duration on a Chronological, by default it will return
the days, hours, minutes and seconds in a Hash. If you need a specific
combination of these pieces, you can pass them in an :in options like
so:
# range_instance's total duration is 5 days, 1 hour, 44 minutes and 23 seconds
range_instance.duration :in => [:days, :hours, :seconds]
#=> { :days => 5, :hours => 1, :seconds => 2663 }
range_instance.duration :in => [:days, :hours, :minutes]
#=> { :days => 5, :hours => 1, :minutes => 44 }
range_instance.duration :in => [:hours, :minutes, :seconds]
#=> { :hours => 121, :minutes => 44, :seconds => 23 }Affected methods:
Is It Scheduled?
Even though Chronological does not handle anything having to do with time
zones, it is valid however, to assume there will be use cases where,
without a time zone, the model should not be considered scheduled.
If you wish to account for this, pass in the :time_zone option to
timeframe and give it the field name that contains the time zone you
wish to use. For example:
class MyTimeRangeClass
timeframe :starting_time => :started_at,
:ending_time => :ended_at,
:time_zone => :time_zone
end
range_instance = MyTimeRangeClass.new
range_instance.started_at = 5.minutes.from_now
range_instance.ended_at = 30.minutes.from_now
range_instance.scheduled? # => false
range_instance.time_zone = 'Alaska'
range_instance.scheduled? # => trueIssues
If you have problems, please create a Github issue.
Credits
greenwich is maintained by Chrrpy, LLC
The names and logos for Chirrpy are trademarks of Chrrpy, LLC
Contributors
License
chronological is Copyright © 2012 Chirrpy. It is free software, and may be redistributed under the terms specified in the LICENSE file.