pub struct Series<P> { /* private fields */ }Expand description
A series of recurring events.
§Example
use jiff::civil::date;
use recurring::{Event, Series, pattern::hourly};
let start = date(2025, 1, 1).at(0, 0, 0, 0);
let end = date(2025, 1, 1).at(4, 0, 0, 0);
let series = Series::new(start..end, hourly(2));
let mut events = series.iter();
assert_eq!(events.next(), Some(Event::at(date(2025, 1, 1).at(0, 0, 0, 0))));
assert_eq!(events.next(), Some(Event::at(date(2025, 1, 1).at(2, 0, 0, 0))));
assert_eq!(events.next(), None);Implementations§
Source§impl<P> Series<P>where
P: Pattern,
impl<P> Series<P>where
P: Pattern,
Sourcepub fn new<B: RangeBounds<DateTime>>(range: B, pattern: P) -> Series<P>
pub fn new<B: RangeBounds<DateTime>>(range: B, pattern: P) -> Series<P>
Creates a new Series that produces events within the provided range according to the
given recurrence Pattern.
To configure more aspects of the series call .with() on the constructed
Series value. See the documentation of Series::with for more details.
The fallible version of this method is Series::try_new.
§Panics
Panics if the start or end of the range bounds would overflow DateTime::MAX after
normalization or if start >= end.
§Example
use jiff::civil::date;
use recurring::{Series, pattern::hourly};
let series = Series::new(date(2025, 1, 1).at(0, 0, 0, 0).., hourly(2));Sourcepub fn try_new<B: RangeBounds<DateTime>>(
range: B,
pattern: P,
) -> Result<Series<P>, Error>
pub fn try_new<B: RangeBounds<DateTime>>( range: B, pattern: P, ) -> Result<Series<P>, Error>
Creates a new Series that produces events within the provided range according to the
given recurrence Pattern.
To configure more aspects of the series call .with() on the constructed
Series value. See the documentation of Series::with for more details.
The panicking version of this method is Series::new.
§Errors
Returns an Error if the start or end of the range bounds would overflow DateTime::MAX
after normalization or if start >= end.
§Example
use jiff::civil::{DateTime, date};
use recurring::{Series, pattern::hourly};
assert!(Series::try_new(date(2025, 1, 1).at(0, 0, 0, 0).., hourly(2)).is_ok());
assert!(Series::try_new(DateTime::MAX.., hourly(2)).is_err());Sourcepub fn with(&self) -> SeriesWith<P>
pub fn with(&self) -> SeriesWith<P>
Creates a builder for constructing a new Series from the fields of this series.
This method constructs a new Series and will not alter the original so it can still be
used after the returned builder is dropped.
If you don’t have an existing series but want to construct a new one and configure optional
details like the event duration or fixpoint, consider using Series::builder instead.
§Example
Create a new series with the same recurrence pattern, an explict end date and configure the duration of the individual events.
use jiff::{ToSpan, civil::date};
use recurring::{Series, pattern::daily};
let s1 = Series::new(date(2025, 1, 1).at(0, 0, 0, 0).., daily(1));
let s2 = s1.with()
.end(date(2025, 2, 1).at(0, 0, 0, 0))
.event_duration(1.hour())
.build()?;
// s1 is still usable here and was not modified.Sourcepub fn builder<B: RangeBounds<DateTime>>(range: B, pattern: P) -> SeriesWith<P>
pub fn builder<B: RangeBounds<DateTime>>(range: B, pattern: P) -> SeriesWith<P>
Creates a builder for constructing a new Series that produces events within the provided
range according to the given recurrence Pattern.
If you already have a Series from which you would like to derive a new series consider
using Series::with instead.
§Example
use jiff::{ToSpan, civil::date};
use recurring::{Series, pattern::daily};
// An "infinite" series of daily 1-hour lunch meetings starting on January 1st 2025.
let start = date(2025, 1, 1).at(12, 0, 0, 0);
let series = Series::builder(start.., daily(1))
.event_duration(1.hour())
.build()?;Sourcepub fn start(&self) -> DateTime
pub fn start(&self) -> DateTime
Returns the DateTime at which the series starts (inclusive).
This is not necessarily the time of the first event in the series.
Sourcepub fn end(&self) -> DateTime
pub fn end(&self) -> DateTime
Returns the DateTime at which the series ends (exclusive).
Don’t confuse this with the time of the last event in the series. It is merely an upper bound until after which the series will stop yielding events.
If the series has a non-zero event duration configured, this will return initial_end - event_duration.
Sourcepub fn fixpoint(&self) -> DateTime
pub fn fixpoint(&self) -> DateTime
Returns the fixpoint for relative recurrence patterns.
This is used as a starting point for Pattern implementations that are relative to some
point in time.
Unless SeriesWith::fixpoint was called with a specific value, this returns the same
value as Series::start.
Sourcepub fn event_duration(&self) -> Span
pub fn event_duration(&self) -> Span
Returns the duration of individual events in the series.
If this is zero, events will not have an end date.
Sourcepub fn iter(&self) -> Iter<'_, P> ⓘ
pub fn iter(&self) -> Iter<'_, P> ⓘ
Creates an iterator over the events in a the series.
§Example
use jiff::civil::date;
use recurring::{Event, Series, pattern::hourly};
let series = Series::new(date(2025, 1, 1).at(0, 0, 0, 0).., hourly(2));
let mut iter = series.iter();
assert_eq!(iter.next(), Some(Event::at(date(2025, 1, 1).at(0, 0, 0, 0))));
assert_eq!(iter.next(), Some(Event::at(date(2025, 1, 1).at(2, 0, 0, 0))));
// Get events from the end of the series.
assert_eq!(iter.next_back(), Some(Event::at(date(9999, 12, 31).at(22, 0, 0, 0))));
assert_eq!(iter.next_back(), Some(Event::at(date(9999, 12, 31).at(20, 0, 0, 0))));Sourcepub fn range<B: RangeBounds<DateTime>>(&self, range: B) -> Range<'_, P> ⓘ
pub fn range<B: RangeBounds<DateTime>>(&self, range: B) -> Range<'_, P> ⓘ
Creates an iterator over a sub-range of the events in a the series.
The returned iterator will iterate over the intersection of the provided range and the series’ original range.
The fallible version of this method is Series::try_range.
§Panics
Panics if the start or end of the range bounds would overflow DateTime::MAX after
normalization or if start >= end.
§Example
use jiff::civil::date;
use recurring::{Event, Series, pattern::hourly};
let series = Series::new(date(2025, 1, 1).at(0, 0, 0, 0).., hourly(2));
let range = date(2026, 1, 1).at(12, 34, 56, 0)..date(2027, 1, 1).at(12, 34, 56, 0);
let mut iter = series.range(range);
assert_eq!(iter.next(), Some(Event::at(date(2026, 1, 1).at(14, 0, 0, 0))));
assert_eq!(iter.next(), Some(Event::at(date(2026, 1, 1).at(16, 0, 0, 0))));
// Get events from the end of the series sub-range.
assert_eq!(iter.next_back(), Some(Event::at(date(2027, 1, 1).at(12, 0, 0, 0))));
assert_eq!(iter.next_back(), Some(Event::at(date(2027, 1, 1).at(10, 0, 0, 0))));Sourcepub fn try_range<B: RangeBounds<DateTime>>(
&self,
range: B,
) -> Result<Range<'_, P>, Error>
pub fn try_range<B: RangeBounds<DateTime>>( &self, range: B, ) -> Result<Range<'_, P>, Error>
Creates an iterator over a sub-range of the events in a the series.
The returned iterator will iterate over the intersection of the provided range and the series’ original range.
The panicking version of this method is Series::range.
§Errors
Returns an Error if the start or end of the range bounds would overflow DateTime::MAX
after normalization or if start >= end.
§Example
use jiff::civil::date;
use recurring::{Event, Series, pattern::hourly};
let series = Series::new(date(2025, 1, 1).at(0, 0, 0, 0).., hourly(2));
let range = date(2026, 1, 1).at(12, 34, 56, 0)..date(2027, 1, 1).at(12, 34, 56, 0);
let mut iter = series.try_range(range)?;
assert_eq!(iter.next(), Some(Event::at(date(2026, 1, 1).at(14, 0, 0, 0))));
assert_eq!(iter.next(), Some(Event::at(date(2026, 1, 1).at(16, 0, 0, 0))));
// Get events from the end of the series sub-range.
assert_eq!(iter.next_back(), Some(Event::at(date(2027, 1, 1).at(12, 0, 0, 0))));
assert_eq!(iter.next_back(), Some(Event::at(date(2027, 1, 1).at(10, 0, 0, 0))));Sourcepub fn first(&self) -> Option<Event>
pub fn first(&self) -> Option<Event>
Gets the first event in the series.
§Example
use jiff::civil::date;
use recurring::{Event, Series, pattern::hourly};
let series = Series::new(date(2025, 1, 1).at(0, 0, 0, 0).., hourly(2));
assert_eq!(series.first(), Some(Event::at(date(2025, 1, 1).at(0, 0, 0, 0))));Sourcepub fn last(&self) -> Option<Event>
pub fn last(&self) -> Option<Event>
Gets the last event in the series.
If the series does not have an end, this method will return an event close to
DateTime::MAX.
§Example
use jiff::civil::date;
use recurring::{Event, Series, pattern::hourly};
let start = date(2025, 1, 1).at(0, 0, 0, 0);
let end = date(2026, 1, 1).at(0, 0, 0, 0);
let series = Series::new(start..end, hourly(2));
assert_eq!(series.last(), Some(Event::at(date(2025, 12, 31).at(22, 0, 0, 0))));Sourcepub fn contains(&self, instant: DateTime) -> bool
pub fn contains(&self, instant: DateTime) -> bool
Returns true when the series contains an event starting at instant.
§Example
use jiff::civil::date;
use recurring::{Event, Series, pattern::hourly};
let series = Series::new(date(2025, 1, 1).at(0, 0, 0, 0).., hourly(2));
assert!(!series.contains(date(2025, 1, 1).at(0, 35, 0, 0)));
assert!(series.contains(date(2025, 2, 10).at(12, 0, 0, 0)));Sourcepub fn get(&self, instant: DateTime) -> Option<Event>
pub fn get(&self, instant: DateTime) -> Option<Event>
Gets an event in the series.
Returns Some(_) if there’s an event starting at instant, otherwise None.
§Example
use jiff::civil::date;
use recurring::{Event, Series, pattern::hourly};
let series = Series::new(date(2025, 1, 1).at(0, 0, 0, 0).., hourly(2));
assert!(series.get(date(2025, 1, 1).at(1, 0, 0, 0)).is_none());
assert!(series.get(date(2026, 12, 31).at(14, 0, 0, 0)).is_some());Sourcepub fn get_containing(&self, instant: DateTime) -> Option<Event>
pub fn get_containing(&self, instant: DateTime) -> Option<Event>
Gets the event containing instant.
Returns None if there’s no event in the series that start at instant or contains it (if
series events have a duration).
§Example
use jiff::{ToSpan, civil::date};
use recurring::{Event, Series, pattern::hourly};
let series_start = date(2025, 1, 1).at(0, 0, 0, 0);
let series_end = date(2025, 2, 1).at(0, 0, 0, 0);
let series = Series::new(series_start..series_end, hourly(1))
.with()
.event_duration(30.minutes())
.build()?;
assert_eq!(
series.get_containing(series_start - 1.minute()),
None,
);
assert_eq!(
series.get_containing(series_start),
Some(Event::new(series_start, series_start + 30.minutes())),
);
assert_eq!(
series.get_containing(series_start + 31.minutes()),
None,
);
assert_eq!(
series.get_containing(series_start + 1.hour().minutes(20)),
Some(Event::new(series_start + 1.hour(), series_start + 1.hour().minutes(30))),
);
assert_eq!(
series.get_containing(series_end),
None,
);Sourcepub fn get_next_after(&self, instant: DateTime) -> Option<Event>
pub fn get_next_after(&self, instant: DateTime) -> Option<Event>
Gets the next event after instant.
Returns None if instant is close to the series end and there’s no more event between
instant and the series end.
§Example
use jiff::{ToSpan, civil::{date, DateTime}};
use recurring::{Event, Series, pattern::hourly};
let series_start = date(2025, 1, 1).at(0, 0, 0, 0);
let series_end = date(2025, 2, 1).at(0, 0, 0, 0);
let series = Series::new(series_start..series_end, hourly(1));
assert_eq!(
series.get_next_after(series_start - 1.minute()),
Some(Event::at(series_start)),
);
assert_eq!(
series.get_next_after(series_start),
Some(Event::at(series_start + 1.hour())),
);
assert_eq!(
series.get_next_after(series_start + 1.minute()),
Some(Event::at(series_start + 1.hour())),
);
assert_eq!(
series.get_next_after(series_end - 1.hour().minutes(1)),
Some(Event::at(series_end - 1.hour())),
);
assert_eq!(
series.get_next_after(series_end - 1.hour()),
None,
);
assert_eq!(
series.get_next_after(series_end),
None,
);Sourcepub fn get_previous_before(&self, instant: DateTime) -> Option<Event>
pub fn get_previous_before(&self, instant: DateTime) -> Option<Event>
Gets the previous event before instant.
Returns None if instant is less than or equal to the series start.
§Example
use jiff::{ToSpan, civil::{DateTime, date}};
use recurring::{Event, Series, pattern::hourly};
let series_start = date(2025, 1, 1).at(0, 0, 0, 0);
let series = Series::new(series_start.., hourly(1));
assert_eq!(series.get_previous_before(series_start), None);
assert_eq!(series.get_previous_before(series_start - 1.minute()), None);
assert_eq!(
series.get_previous_before(series_start + 29.minute()),
Some(Event::at(series_start)),
);
assert_eq!(
series.get_previous_before(series_start + 1.hour()),
Some(Event::at(series_start)),
);
assert_eq!(
series.get_previous_before(series_start + 1.hour().seconds(1)),
Some(Event::at(series_start + 1.hour())),
);
assert_eq!(
series.get_previous_before(DateTime::MAX),
Some(Event::at(date(9999, 12, 31).at(23, 0, 0, 0))),
);Sourcepub fn get_closest_to(&self, instant: DateTime) -> Option<Event>
pub fn get_closest_to(&self, instant: DateTime) -> Option<Event>
Gets the series event with the start time closest to instant.
The returned event may start before, at or after instant.
§Example
use jiff::{ToSpan, civil::date};
use recurring::{Event, Series, pattern::hourly};
let series_start = date(2025, 1, 1).at(0, 0, 0, 0);
let series = Series::new(series_start.., hourly(1));
assert_eq!(
series.get_closest_to(series_start),
Some(Event::at(series_start)),
);
assert_eq!(
series.get_closest_to(series_start - 1.minute()),
Some(Event::at(series_start)),
);
assert_eq!(
series.get_closest_to(series_start + 29.minutes()),
Some(Event::at(series_start)),
);
assert_eq!(
series.get_closest_to(series_start + 30.minutes()),
Some(Event::at(series_start + 1.hour())),
);Sourcepub fn split_off<S: Into<SeriesSplit>>(
&mut self,
options: S,
) -> Result<Series<P>, Error>
pub fn split_off<S: Into<SeriesSplit>>( &mut self, options: S, ) -> Result<Series<P>, Error>
Splits off a part of the series.
If splitting succeeds, the original series’ end is adjusted towards the cutoff point.
Note that this routine is generic and accepts anything that implements Into<SeriesSplit>.
Some notable implementations are:
From<DateTime> for SeriesSplitwill construct a series split configuration which splits the series at a given datetime. TheDate,Zonedand&Zonedtypes can be used instead ofDateTimeas well.From<(SplitMode, T)> for SeriesSplit where T: Into<SeriesSplit>will construct a series split configuration using a certainSplitMode. This enables splitting at the next, previous or closest event.
§Errors
Returns an error if the SeriesSplit fails to find a cutoff point according to its
SplitMode or if splitting the series would result in either of the series to have
start >= end. It is guaranteed that the original series was not altered if this method
returns an error.
§Example: split at an exact datetime
use jiff::{ToSpan, civil::{date, DateTime}};
use recurring::{Event, Series, pattern::hourly};
let start = date(2025, 1, 1).at(0, 0, 0, 0);
let mut s1 = Series::new(start.., hourly(1));
let cutoff_point = date(2025, 4, 1).at(12, 34, 56, 0);
let s2 = s1.split_off(cutoff_point)?;
assert_eq!(s2.first(), Some(Event::at(date(2025, 4, 1).at(13, 0, 0, 0))));
assert_eq!(s1.end(), cutoff_point);§Example: split at the next event after a datetime
use jiff::{ToSpan, civil::{date, DateTime}};
use recurring::{Event, Series, pattern::hourly};
use recurring::series::SplitMode;
let start = date(2025, 1, 1).at(0, 0, 0, 0);
let mut s1 = Series::new(start.., hourly(1));
let instant = date(2025, 4, 1).at(12, 34, 56, 0);
// Use `SplitMode::NextAfter` to split at the next event after `instant`.
let s2 = s1.split_off((SplitMode::NextAfter, instant))?;
assert_eq!(s2.first(), Some(Event::at(date(2025, 4, 1).at(13, 0, 0, 0))));
assert_eq!(s1.end(), date(2025, 4, 1).at(13, 0, 0, 0));