Recurring events are a common feature in apps like calendars, task managers, and scheduling systems. However, implementing this functionality can get complicated, especially when users want events to repeat at different frequencies, on specific days, or for a limited number of times. The rrule
library is a powerful tool that makes managing recurring events simple and reliable.
In this article, we’ll show you how to use the rrule
library in Node.js to handle recurring events, convert them into plain text for users, and store them in a database for long-term use.
Why Use rrule
?
Imagine you’re building a feature where users can set up events that repeat:
- Daily, weekly, or monthly
- On specific days of the week (e.g., Monday, Wednesday, Friday)
- A certain number of times or until a specific date
Coding all of this manually can lead to complex and error-prone logic. The rrule
library simplifies everything by letting you define recurrence rules with just a few lines of code.
Getting Started with rrule
Before we begin, install the required libraries:
npm install rrule moment-timezone
rrule
: Helps generate and handle recurring event rules.moment-timezone
: Ensures events are time-zone-aware, especially useful for global applications.
Creating Recurring Events
Here’s how you can define a recurring event using rrule
:
const { RRule } = require('rrule');
const moment = require('moment-timezone');
// Function to create an RRule
const createRRule = (input) => {
return new RRule({
freq: input.repeatEveryUnit === 'day'
? RRule.DAILY
: input.repeatEveryUnit === 'week'
? RRule.WEEKLY
: RRule.MONTHLY,
interval: input.repeatEvery, // How often it repeats
count: input.endType === 'after' ? input.occurrences : null, // Number of times it repeats
until: input.endType === 'on' ? moment(input.endDate).toDate() : null, // End date
dtstart: moment(input.startDate).toDate(), // Start date
byweekday: input.repeatOn ? input.repeatOn.map(day => RRule[day.toUpperCase()]) : null, // Days of the week
});
};
// Example input
const input = {
repeatEveryUnit: 'week', // Repeat weekly
repeatEvery: 1, // Every 1 week
endType: 'after', // End after 10 occurrences
occurrences: 10,
startDate: '2023-05-15T10:00:00', // Start date
endDate: null, // Not used since we’re ending after 10 times
repeatOn: ['mo', 'we', 'fr'], // Monday, Wednesday, Friday
};
// Create the rule
const rule = createRRule(input);
// Output the rule as a string
console.log(rule.toString());
How It Works
freq
: Specifies how often the event repeats (daily, weekly, or monthly).interval
: Sets the gap between recurrences.count
: Limits the number of occurrences (e.g., 10 times).until
: Specifies an end date for the recurrence.byweekday
: Specifies days of the week for the recurrence (e.g., Monday, Wednesday, Friday).
In this example, the rule defines a recurring event that happens every week on Monday, Wednesday, and Friday, starting on May 15, 2023, and repeats 10 times.
Making Rules User-Friendly
While the rule works perfectly for computers, users need to see it in plain English. The rrule
library provides a method to convert rules into readable text:
const readableText = (rule) => rule.toText();
console.log(readableText(rule));
For the above example, this will generate:
"Repeats every week on Monday, Wednesday, and Friday 10 times"
This is great for displaying the recurrence details to users in a simple format.
Storing Recurring Rules in a Database
Once you’ve created a recurring rule, you’ll likely need to save it in a database so it can be retrieved later. The rrule
library makes this easy by letting you store the rule as a string.
Here’s how to save and retrieve recurring rules using a PostgreSQL database and MikroORM.
Step 1: Define the Database Table (Entity)
We’ll define an Event
entity where we store the rule:
import { Entity, PrimaryKey, Property } from 'mikro-orm';
@Entity()
export class Event {
@PrimaryKey()
id!: number; // Unique identifier for the event
@Property({ type: 'text' })
name!: string; // Name or title of the event
@Property({ type: 'text' })
rrule!: string; // Recurrence rule stored as a string
}
Step 2: Save the Rule in the Database
Here’s how you can generate a rule, serialize it, and save it:
const { MikroORM } = require('@mikro-orm/core');
const { Event } = require('./entities/Event');
const orm = await MikroORM.init({
entities: [Event],
dbName: 'my_database',
type: 'postgresql',
});
const em = orm.em.fork();
const input = {
repeatEveryUnit: 'week',
repeatEvery: 1,
endType: 'after',
occurrences: 10,
startDate: '2023-05-15T10:00:00',
endDate: null,
repeatOn: ['mo', 'we', 'fr'],
};
const rule = createRRule(input);
const event = new Event();
event.name = 'Weekly Team Meeting';
event.rrule = rule.toString();
await em.persistAndFlush(event);
Step 3: Retrieve and Use the Rule
When you need the recurring rule later, you can fetch it from the database and rebuild it:
const savedEvent = await em.findOne(Event, { id: 1 });
if (savedEvent) {
const rule = RRule.fromString(savedEvent.rrule);
console.log(rule.toText()); // Display the rule in plain text
}
This makes it easy to manage recurring events in your application while keeping the database clean and efficient.
Wrapping Up
The rrule
library takes the hassle out of managing recurring events. It provides a clean way to define recurrence patterns, make them human-readable, and save them for later use. With this approach, you can confidently build powerful scheduling features into your applications.
We specialize in creating complex custom software solutions. If you’re looking for expert development services, feel free to reach out to us!
About Boopesh Mahendran
Boopesh is one of the Co-Founders of CyberMind Works and the Head of Engineering. An alum of Madras Institute of Technology with a rich professional background, he has previously worked at Adobe and Amazon. His expertise drives the innovative solutions at CyberMind Works.
