Skip to content

Commit 60e69b7

Browse files
author
Koen Zwikstra
authored
Refactors occurrences extensions with date filtering (#16)
* refactors inRange extension to occurrences with optional date range parameters * updates readme
1 parent 194e8a1 commit 60e69b7

File tree

11 files changed

+1961
-2032
lines changed

11 files changed

+1961
-2032
lines changed

README.md

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ A Dart library for parsing and working with iCalendar (.ics) files. Built with R
1616
- [Working with Timezones](#working-with-timezones)
1717
- [Recurring Events](#recurring-events)
1818
- [Filtering Events by Date Range](#filtering-events-by-date-range)
19-
- [Chronological ordering across multiple events](#chronological-ordering-across-multiple-events)
19+
- [Getting All Occurrences](#getting-all-occurrences)
20+
- [Chronological Ordering Across Multiple Events](#chronological-ordering-across-multiple-events)
2021
- [Streaming Large Files](#streaming-large-files)
2122
- [Conditional Parsing with Stream Parser](#conditional-parsing-with-stream-parser)
2223
- [Custom Property Parsers](#custom-property-parsers)
@@ -87,6 +88,12 @@ print('Summary: ${event.summary ?? "Untitled"}');
8788
print('Location: ${event.location ?? "No location"}');
8889
print('Description: ${event.description ?? ""}');
8990
91+
// Extension properties
92+
print('Is recurring: ${event.isRecurring}');
93+
print('Is all-day: ${event.isAllDay}');
94+
print('Is multi-day: ${event.isMultiDay}');
95+
print('Duration: ${event.effectiveDuration}');
96+
9097
// Attendees
9198
for (final attendee in event.attendees) {
9299
print('Attendee: ${attendee.address}');
@@ -144,26 +151,45 @@ for (final occurrence in event.occurrences().take(10)) {
144151

145152
### Filtering Events by Date Range
146153

147-
Use the `inRange` extension to filter events that occur within a specific date range. This works correctly with multi-day events, all-day events, and recurring events. Results are always returned in chronological order, regardless of the order in the source file.
154+
Use the `occurrences` extension to filter events that occur within a specific date range. This works correctly with multi-day events, all-day events, and recurring events. Results are always returned in chronological order, regardless of the order in the source file.
148155

149156
```dart
150157
final start = CalDateTime.date(2024, 3, 1);
151158
final end = CalDateTime.date(2024, 3, 31);
152159
153160
// Get all event occurrences in March 2024
154-
final occurrencesInMarch = calendar.events.inRange(start, end);
161+
final occurrencesInMarch = calendar.events.occurrences(
162+
start: start,
163+
end: end,
164+
);
155165
156166
for (final result in occurrencesInMarch) {
157167
print('${result.event.summary}: ${result.occurrence}');
158168
}
159169
160170
// Works with todos and journals too
161-
final todoOccurrences = calendar.todos.inRange(start, end);
171+
final todoOccurrences = calendar.todos.occurrences(
172+
start: start,
173+
end: end,
174+
);
175+
```
176+
177+
### Getting All Occurrences
178+
179+
When you need all occurrences across multiple components without filtering by date range, simply call `occurrences()` without parameters. Use `.take()` to limit results when working with recurring events that could generate infinite occurrences.
180+
181+
```dart
182+
// Get all occurrences without date filtering
183+
final allOccurrences = calendar.events.occurrences();
184+
185+
for (final result in allOccurrences.take(20)) {
186+
print('${result.event.summary}: ${result.occurrence}');
187+
}
162188
```
163189

164-
### Chronological ordering across multiple events
190+
### Chronological Ordering Across Multiple Events
165191

166-
The `inRange` extension automatically sorts event occurrences chronologically, regardless of the order they appear in the source iCalendar file.
192+
The `occurrences` extension automatically sorts event occurrences chronologically, regardless of the order they appear in the source iCalendar file.
167193

168194
```dart
169195
final ics = '''
@@ -197,7 +223,10 @@ final calendar = parser.parseFromString(ics);
197223
final start = CalDateTime.date(2024, 3, 1);
198224
final end = CalDateTime.date(2024, 3, 31);
199225
200-
for (final result in calendar.events.inRange(start, end)) {
226+
for (final result in calendar.events.occurrences(
227+
start: start,
228+
end: end,
229+
)) {
201230
print('${result.occurrence}: ${result.event.summary}');
202231
}
203232

lib/src/semantic/extensions/calendar_types.dart

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,7 @@ extension CalDateTimeExtensions on CalDateTime {
2626

2727
/// The day of the year (1-365 or 1-366 in leap years).
2828
int get dayOfYear {
29-
final startOfYear = copyWith(
30-
month: 1,
31-
day: 1,
32-
hour: 0,
33-
minute: 0,
34-
second: 0,
35-
);
29+
final startOfYear = CalDateTime.date(year, 1, 1);
3630
return native.difference(startOfYear.native).inDays + 1;
3731
}
3832

lib/src/semantic/extensions/components.dart

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,10 @@ extension EventComponentExtensions on EventComponent {
9797
/// Generates all occurrences of the event based on its recurrence
9898
/// rules, exclusions (EXDATE), and additional dates (RDATE).
9999
///
100+
/// [start] and [end] can be provided to limit the occurrences.
101+
///
100102
/// Returns an empty iterable if the event has no start date.
101-
Iterable<CalDateTime> occurrences() {
103+
Iterable<CalDateTime> occurrences({CalDateTime? start, CalDateTime? end}) {
102104
if (dtstart == null) return const Iterable<CalDateTime>.empty();
103105

104106
final iterator = RecurrenceIterator(
@@ -107,7 +109,11 @@ extension EventComponentExtensions on EventComponent {
107109
exdates: exdates,
108110
rdates: rdates,
109111
);
110-
return iterator.occurrences();
112+
return iterator.occurrences(
113+
start: start,
114+
end: end,
115+
duration: effectiveDuration,
116+
);
111117
}
112118
}
113119

@@ -156,8 +162,10 @@ extension TodoComponentExtensions on TodoComponent {
156162
/// Generates all occurrences of the todo based on its recurrence
157163
/// rules, exclusions (EXDATE), and additional dates (RDATE).
158164
///
165+
/// [start] and [end] can be provided to limit the occurrences.
166+
///
159167
/// Returns an empty iterable if the todo has no start date.
160-
Iterable<CalDateTime> occurrences() {
168+
Iterable<CalDateTime> occurrences({CalDateTime? start, CalDateTime? end}) {
161169
if (dtstart == null) return const Iterable<CalDateTime>.empty();
162170

163171
final iterator = RecurrenceIterator(
@@ -166,7 +174,11 @@ extension TodoComponentExtensions on TodoComponent {
166174
exdates: exdates,
167175
rdates: rdates,
168176
);
169-
return iterator.occurrences();
177+
return iterator.occurrences(
178+
start: start,
179+
end: end,
180+
duration: effectiveDuration,
181+
);
170182
}
171183
}
172184

@@ -179,8 +191,10 @@ extension JournalComponentExtensions on JournalComponent {
179191
/// Generates all occurrences of the journal based on its recurrence
180192
/// rules, exclusions (EXDATE), and additional dates (RDATE).
181193
///
194+
/// [start] and [end] can be provided to limit the occurrences.
195+
///
182196
/// Returns an empty iterable if the journal has no start date.
183-
Iterable<CalDateTime> occurrences() {
197+
Iterable<CalDateTime> occurrences({CalDateTime? start, CalDateTime? end}) {
184198
if (dtstart == null) return const Iterable<CalDateTime>.empty();
185199

186200
final iterator = RecurrenceIterator(
@@ -189,7 +203,7 @@ extension JournalComponentExtensions on JournalComponent {
189203
exdates: exdates,
190204
rdates: rdates,
191205
);
192-
return iterator.occurrences();
206+
return iterator.occurrences(start: start, end: end);
193207
}
194208
}
195209

@@ -201,13 +215,15 @@ extension TimeZoneSubComponentExtensions on TimeZoneSubComponent {
201215

202216
/// Generates all occurrences of the timezone component based on its recurrence
203217
/// rules, exclusions (EXDATE), and additional dates (RDATE).
204-
Iterable<CalDateTime> occurrences() {
218+
///
219+
/// [start] and [end] can be provided to limit the occurrences.
220+
Iterable<CalDateTime> occurrences({CalDateTime? start, CalDateTime? end}) {
205221
final iterator = RecurrenceIterator(
206222
dtstart: dtstart,
207223
rrule: rrule,
208224
rdates: rdates,
209225
);
210-
return iterator.occurrences();
226+
return iterator.occurrences(start: start, end: end);
211227
}
212228
}
213229

0 commit comments

Comments
 (0)