rrule Ruby Library

repository·master·Indexed 41 days ago

https://github.com/square/ruby-rrule

A 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.

Tokens
1.9K
Snippets
12
Records
12
Agent score
51%

What's inside rrule

  1. Handle exceptions (EXDATEs) in recurrences

    master

    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]
  2. Generate recurrence instances

    master

    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.

    Configuration Options for RRule::Rule.new

    • dtstart: 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')])
  3. Create an RRule instance

    master

    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 syntax
    rrule = RRule::Rule.new('FREQ=DAILY;COUNT=3')
    rrule = RRule.parse('FREQ=DAILY;COUNT=3')
  4. Check if an RRule is finite

    master

    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? # => false
  5. Parse an RRule string with RRule.parse

    master

    Use 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')
  6. Convert RRule options to human-readable strings with Humanizer

    master

    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"
  7. Generate recurrence instances with RRule::Rule

    master

    The 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.next
  8. Initialize an RRule::Rule instance

    master

    Use 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)
  9. Error handling with InvalidRRule

    master

    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