Skip to main content

Series

Struct Series 

Source
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,

Source

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));
Source

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());
Source

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

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()?;
Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn pattern(&self) -> &P

Returns a reference to the recurrence pattern used by the series.

Source

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))));
Source

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))));
Source

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))));
Source

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))));
Source

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))));
Source

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)));
Source

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());
Source

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,
);
Source

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,
);
Source

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))),
);
Source

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())),
);
Source

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 SeriesSplit will construct a series split configuration which splits the series at a given datetime. The Date, Zoned and &Zoned types can be used instead of DateTime as well.
  • From<(SplitMode, T)> for SeriesSplit where T: Into<SeriesSplit> will construct a series split configuration using a certain SplitMode. 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));

Trait Implementations§

Source§

impl<P: Clone> Clone for Series<P>

Source§

fn clone(&self) -> Series<P>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<P: Debug> Debug for Series<P>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'a, P> IntoIterator for &'a Series<P>
where P: Pattern,

Source§

type Item = Event

The type of the elements being iterated over.
Source§

type IntoIter = Iter<'a, P>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more

Auto Trait Implementations§

§

impl<P> Freeze for Series<P>
where P: Freeze,

§

impl<P> RefUnwindSafe for Series<P>
where P: RefUnwindSafe,

§

impl<P> Send for Series<P>
where P: Send,

§

impl<P> Sync for Series<P>
where P: Sync,

§

impl<P> Unpin for Series<P>
where P: Unpin,

§

impl<P> UnsafeUnpin for Series<P>
where P: UnsafeUnpin,

§

impl<P> UnwindSafe for Series<P>
where P: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.