Install the rrule gem
masterTo use this library in your Ruby project, add the following line to your Gemfile:
gem 'rrule'Then run bundle install.
repository·master·Indexed 41 days ago
https://github.com/square/ruby-rruleA minimalist Ruby library for expanding RRULE strings into recurrence instances, fully compliant with the iCalendar spec (RFC 2445). It provides the RRule::Rule class for generating timestamps via #all, #between, and #from, as well as RRule::Humanizer for converting recurrence options into natural language strings.
To use this library in your Ruby project, add the following line to your Gemfile:
gem 'rrule'Then run bundle install.
To exclude specific dates from a recurrence pattern, pass an array of dates to the exdate option when initializing RRule::Rule.new.
rrule = RRule::Rule.new('FREQ=DAILY;COUNT=3', dtstart: Time.new(2016, 7, 1), exdate: [DateTime.parse('2016-07-02 00:00:00 -0700')])
rrule.all
# => [2016-07-01 00:00:00 -0700, 2016-07-03 00:00:00 -0700]Use the following methods to expand an RRULE into specific timestamps:
#all: Returns all instances defined by the rule. You can pass a limit: option to restrict the number of returned instances.#between(start_time, end_time): Returns instances that fall within the specified time range.#from(start_time): Returns all instances starting from a specific date/time.RRule::Rule.newdtstart: Sets the start date/time of the recurrence. If not provided, it defaults to the current time.tzid: An explicit timezone string (e.g., 'America/Los_Angeles') to ensure daylight saving time boundaries are respected. Use this unless evaluating in UTC.exdate: An array of dates to be excluded from the recurrence (EXDATEs).# Generate all instances
rrule.all
# Generate instances in a range
rrule.between(Time.new(2016, 6, 23), Time.new(2016, 6, 24))
# Generate instances starting from a specific date
rrule.from(Time.new(2016, 1, 2))
# Limit the number of instances
rrule.all(limit: 2)
# Initialize with options
rrule = RRule::Rule.new('FREQ=DAILY;COUNT=3', dtstart: Time.new(2016, 7, 1), tzid: 'America/Los_Angeles', exdate: [DateTime.parse('2016-07-02 00:00:00 -0700')])You can create an RRule::Rule object using an RRULE string via the constructor or the RRule.parse method.
rrule = RRule::Rule.new('FREQ=DAILY;COUNT=3')
rrule = RRule.parse('FREQ=DAILY;COUNT=3') # alternate syntaxrrule = RRule::Rule.new('FREQ=DAILY;COUNT=3')
rrule = RRule.parse('FREQ=DAILY;COUNT=3')Use is_finite? to determine if the recurrence rule has a defined end point. A rule is considered finite if it contains either a COUNT or an UNTIL option.
rule = RRule::Rule.new('FREQ=DAILY;COUNT=10')
rule.is_finite? # => true
rule_infinite = RRule::Rule.new('FREQ=DAILY')
rule_infinite.is_finite? # => falseUse RRule.parse to create a new RRule::Rule instance from a standard iCalendar recurrence rule string. You can pass additional options to the method to configure the rule parsing.
rule = RRule.parse('FREQ=WEEKLY;BYDAY=MO,WE,FR')The RRule::Humanizer class provides a way to transform an RRule's configuration options into a natural language string (e.g., converting an interval and frequency into "every 2 weeks").
To use it, initialize the class with an rrule object and an options hash containing the RRule parameters. You can then call .to_s on the instance to get the humanized description.
Note: The Humanizer uses method_missing to dynamically handle option access. If you attempt to access an option that is not present in the provided options hash, it will return nil rather than raising an error.
# Assuming you have an rrule object and its corresponding options hash
rrule = RRule::RRule.new(...)
options = { freq: :weekly, interval: 2 }
humanizer = RRule::Humanizer.new(rrule, options)
puts humanizer.to_s
# => "every 2 weeks"The humanize method returns a human-readable string representation of the recurrence rule.
rule = RRule::Rule.new('FREQ=WEEKLY;COUNT=5')
puts rule.humanizeThe RRule::Rule class includes Enumerable, allowing you to iterate over recurrence instances. Use the following methods to retrieve dates:
all(limit: nil): Returns all occurrences up to the rule's UNTIL or COUNT limit. Use limit to cap the number of returned instances.between(start_date, end_date, limit: nil): Returns occurrences that fall within the specified range.from(start_date, limit:): Returns occurrences starting from a specific date, up to a maximum number of results defined by limit.each(floor_date: nil): An enumerator that yields occurrences. If COUNT or INTERVAL options are present, iteration starts from dtstart to ensure relative calculations are correct.rule = RRule::Rule.new('FREQ=MONTHLY;BYMONTHDAY=1;COUNT=3')
# Get all instances
rule.all.each { |date| puts date }
# Get instances within a range
rule.between(Time.new(2023, 1, 1), Time.new(2023, 12, 31))
# Get the next occurrence
next_date = rule.nextUse RRule::Rule.new to create a recurrence rule object. You can pass a raw RRule string (e.g., FREQ=WEEKLY;COUNT=10) and an optional dtstart (start date/time). The class handles parsing the RRule string into options.
Parameters:
rrule (String): The RRule string. It can optionally include the RRULE: prefix.dtstart (Time/Date, optional): The start date of the recurrence. Defaults to Time.now.tzid (String, optional): The timezone ID. Defaults to 'UTC'.exdate (Array, optional): An array of dates/times to exclude from the recurrence. Defaults to [].max_year (Integer, optional): A safety limit for the maximum year to prevent infinite loops. Defaults to 9999.rule = RRule::Rule.new('FREQ=WEEKLY;COUNT=5', dtstart: Time.now)The to_s method returns the original RRule string used to initialize the object.
rule = RRule::Rule.new('FREQ=WEEKLY')
rule.to_s # => 'FREQ=WEEKLY'When parsing an RRule string that does not conform to the expected format, the library raises an RRule::InvalidRRule error. You should rescue this error when handling untrusted input strings.
begin
RRule.parse('INVALID_STRING')
rescue RRule::InvalidRRule => e
puts "Failed to parse: #{e.message}"
end