Schedules
A pure-Dart package for generating and managing recurring events.
Features
- Determine if an event occurs on a specific day
- Generate a list of n events
- Generate a list of events until x date
- Math-based algorithms for better performance
Schedule Types
- One-time: An event that occurs only once
- Daily: An event that occurs every n days
- Weekly: An event that occurs on one or more weekdays every n weeks
- Monthly: An event that occurs on one or more days every n months
- MonthlyWeekday: An event that occurs on the x_th weekday every n months
- Yearly: An event that occurs on a particular date every n years
Getting Started
Add the package to your pubspec.yaml:
dependencies:
schedules: ^1.1.0
Or install directly:
dart pub add schedules
Usage
Import the package:
import 'package:schedules/schedules.dart';
Schedule Types
Singular (one-time event)
An event that occurs only once:
final singular = Singular(
date: DateTime(2023, 01, 01),
);
Daily
Repeats every n days:
// Every other day, beginning on January 1, 2023
final daily = Daily(
startDate: DateTime(2023, 01, 01),
frequency: 2,
);
Weekly
Repeats every n weeks on the specified weekdays:
// Every other week on Monday and Thursday,
// beginning on January 1, 2023
final weekly = Weekly(
startDate: DateTime(2023, 01, 01),
frequency: 2,
weekdays: [DateTime.monday, DateTime.thursday],
);
Monthly
Repeats every n months on the specified days:
// Every month on the 1st and 15th,
// beginning on January 1, 2023
final monthly = Monthly(
startDate: DateTime(2023, 01, 01),
frequency: 1,
days: [1, 15],
);
MonthlyWeekday
Repeats every n months on a specific weekday of a specific week:
// First Monday of every month,
// beginning on January 1, 2023
final firstMonday = MonthlyWeekday(
startDate: DateTime(2023, 01, 01),
frequency: 1,
weekday: DateTime.monday,
weekOfMonth: 1, // First occurrence
);
// Last Friday of every other month
final lastFriday = MonthlyWeekday(
startDate: DateTime(2023, 01, 01),
frequency: 2,
weekday: DateTime.friday,
weekOfMonth: -1, // Last occurrence
);
// Third Thursday of every month
final thirdThursday = MonthlyWeekday(
startDate: DateTime(2023, 01, 01),
frequency: 1,
weekday: DateTime.thursday,
weekOfMonth: 3,
);
Parameters:
weekday: The day of the week (1=Monday, 7=Sunday)weekOfMonth: Which occurrence of the weekday (1-5, or -1 for last)frequency: How often in months (1=every month, 2=every other month, etc.)
Week of Month Values:
1= First occurrence (e.g., first Monday)2= Second occurrence (e.g., second Friday)3= Third occurrence (e.g., third Tuesday)4= Fourth occurrence (e.g., fourth Wednesday)5= Fifth occurrence (e.g., fifth Thursday) - only exists in some months-1= Last occurrence (e.g., last Friday) - finds the last occurrence, regardless of count
Yearly
Repeats every n years on the specified date:
// Every 3 years on January 1st,
// beginning on January 1, 2023
final yearly = Yearly(
startDate: DateTime(2023, 01, 01),
frequency: 3,
);
End Dates
All schedule types (except Singular) support an optional end date:
// A schedule that runs every Sunday for 3 months
final projectSchedule = Weekly(
startDate: DateTime(2023, 1, 1),
frequency: 1,
weekdays: [DateTime.sunday],
endDate: DateTime(2023, 3, 31),
);
// This will only return occurrences within the date range
final occurrences = projectSchedule.getOccurrencesUntil(
DateTime(2023, 4, 1),
).toList();
// Contains: [2023-01-01, 2023-01-08, 2023-01-15, 2023-01-22, 2023-01-29,
// 2023-02-05, 2023-02-12, 2023-02-19, 2023-02-26, 2023-03-05,
// 2023-03-12, 2023-03-19, 2023-03-26]
Excluding Dates
Skip specific dates when generating occurrences:
final workSchedule = Weekly(
startDate: DateTime(2023, 1, 1),
frequency: 1,
weekdays: [DateTime.monday, DateTime.wednesday, DateTime.friday],
);
// Exclude holidays and vacation days
final excludedDates = [
DateTime(2023, 1, 2), // New Year's Day (observed)
DateTime(2023, 1, 16), // MLK Day
];
// Get work days for the next 2 weeks, excluding holidays
final workDays = workSchedule.getNextNOccurrences(
6,
exclude: excludedDates,
).toList();
// Contains: [2023-01-04 (Wed), 2023-01-06 (Fri), 2023-01-09 (Mon),
// 2023-01-11 (Wed), 2023-01-13 (Fri)]
Date Ranges
Get all occurrences within a specific date range:
final billSchedule = Monthly(
startDate: DateTime(2023, 1, 1),
frequency: 1,
days: [1, 15], // 1st and 15th of each month
);
// Get bill due dates for Q1 2023
final q1Bills = billSchedule.getOccurrencesUntil(
DateTime(2023, 4, 1),
from: DateTime(2023, 1, 1),
).toList();
// Contains: [2023-01-01, 2023-01-15, 2023-02-01, 2023-02-15, 2023-03-01, 2023-03-15]
// Get bill dates for just February
final febBills = billSchedule.getOccurrencesUntil(
DateTime(2023, 3, 1),
from: DateTime(2023, 2, 1),
).toList();
// Contains: [2023-02-01, 2023-02-15]
API
All schedule types provide these methods:
occursOn(DateTime date)- Check if the schedule occurs on a specific dategetNextNOccurrences(int n, {DateTime? from, Iterable<DateTime>? exclude})- Get the next N occurrencesgetOccurrencesUntil(DateTime end, {DateTime? from, Iterable<DateTime>? exclude})- Get all occurrences until a specific date
Concrete Examples
Payday Schedule
// Bi-weekly paydays on Fridays, starting January 6, 2023
final payday = Weekly(
startDate: DateTime(2023, 1, 6), // First Friday
frequency: 2, // Every 2 weeks
weekdays: [DateTime.friday],
);
// Check if today is payday
final today = DateTime.now();
if (payday.occursOn(today)) {
print('It\'s payday!');
}
// Get paydays for the next 3 months
final nextPaydays = payday.getOccurrencesUntil(
DateTime(2023, 4, 1),
from: DateTime(2023, 1, 1),
).toList();
// Contains: [2023-01-06, 2023-01-20, 2023-02-03, 2023-02-17, 2023-03-03, 2023-03-17]
Medication Reminder
// Take medication daily
final medication = Daily(
startDate: DateTime(2023, 1, 1),
frequency: 1, // Daily
);
// Check if it's medication day
final today = DateTime.now();
if (medication.occursOn(today)) {
print('Take your medication today');
}
// Get next 3 medication days
final nextDoses = medication.getNextNOccurrences(3);
// Output: [2023-01-01, 2023-01-02, 2023-01-03]
Bill Due Dates
// Rent due on the 1st, utilities on the 15th
final rent = Monthly(
startDate: DateTime(2023, 1, 1),
frequency: 1,
days: [1],
);
final utilities = Monthly(
startDate: DateTime(2023, 1, 15),
frequency: 1,
days: [15],
);
// Check if any bills are due today
final today = DateTime.now();
// Get bill due dates for Q1 2023
final q1Bills = [
...rent.getOccurrencesUntil(DateTime(2023, 4, 1), from: DateTime(2023, 1, 1)),
...utilities.getOccurrencesUntil(DateTime(2023, 4, 1), from: DateTime(2023, 1, 1)),
].toList()..sort();
// Contains: [2023-01-01 (rent), 2023-01-15 (utilities), 2023-02-01 (rent),
// 2023-02-15 (utilities), 2023-03-01 (rent), 2023-03-15 (utilities)]
Board Meeting Schedule
// Board meetings on the first Monday of every month
final boardMeeting = MonthlyWeekday(
startDate: DateTime(2023, 1, 1),
frequency: 1,
weekday: DateTime.monday,
weekOfMonth: 1, // First Monday
);
// Team retrospectives on the last Friday of every other month
final retrospective = MonthlyWeekday(
startDate: DateTime(2023, 1, 1),
frequency: 2, // Every 2 months
weekday: DateTime.friday,
weekOfMonth: -1, // Last Friday
);
// Check if today is a meeting day
final today = DateTime.now();
if (boardMeeting.occursOn(today)) {
print('Board meeting today!');
}
// Get next 6 board meetings
final nextMeetings = boardMeeting.getNextNOccurrences(6).toList();
// Contains: [2023-01-02, 2023-02-06, 2023-03-06, 2023-04-03, 2023-05-01, 2023-06-05]
// Get retrospectives for the year
final yearRetrospectives = retrospective.getOccurrencesUntil(
DateTime(2024, 1, 1),
from: DateTime(2023, 1, 1),
).toList();
// Contains: [2023-01-27, 2023-03-31, 2023-05-26, 2023-07-28, 2023-09-29, 2023-11-24]
Work Schedule with Holidays
// Work Monday-Friday
final workDays = Weekly(
startDate: DateTime(2023, 1, 2), // First Monday
frequency: 1,
weekdays: [
DateTime.monday,
DateTime.tuesday,
DateTime.wednesday,
DateTime.thursday,
DateTime.friday,
],
);
// Define holidays
final holidays = [
DateTime(2023, 1, 2), // New Year's Day (observed)
DateTime(2023, 1, 16), // MLK Day
];
// Check if today is a work day (excluding holidays)
final today = DateTime.now();
final isWorkDay = workDays.occursOn(today) && !holidays.any(today.isSameDateAs);
if (isWorkDay) {
print('Today is a work day');
} else {
print('Today is not a work day');
}
// Get work days for first 2 weeks of January, excluding holidays
final workDaysJan = workDays.getOccurrencesUntil(
DateTime(2023, 1, 15),
from: DateTime(2023, 1, 1),
exclude: holidays,
).toList();
// Contains: [2023-01-03 (Tue), 2023-01-04 (Wed), 2023-01-05 (Thu), 2023-01-06 (Fri),
// 2023-01-09 (Mon), 2023-01-10 (Tue), 2023-01-11 (Wed), 2023-01-12 (Thu)]
License
MIT License - see LICENSE file for details.