AntNavDev/recurrence

A standalone PHP 8.2+ library that evaluates whether a recurring rule string is due on a given date, extracted from Bridge and published on Packagist.

Open Source

Available on Packagist

Install via Composer and use it in any PHP project.

View on Packagist

Overview

About This Project

AntNavDev/recurrence is a small, framework-agnostic PHP 8.2 library with a single job: given a rule string and a date, tell you whether something is due. It was extracted from Bridge's chore scheduler, where the same logic lived directly on the Chore model. Publishing it as a standalone package made it independently testable and reusable across projects.

The problem it solves

Bridge generates the day's chore list at midnight via a scheduled command. Every chore stores a plain VARCHAR rule string (daily, weekly:mon,wed, biweekly:mon, monthly:15, monthly:last, interval:7) and the scheduler needs to decide which ones are due on today's date. The logic has to be stateless: a missed or late chore must never cause the schedule to drift.

Design

The entire library is one class, Recurrence, with one public method: isDueOn(Carbon $date): bool. All six rule variants are parsed with str_starts_with and explode. No regex, no external parsing library. The implementation is intentionally flat.

Rules that require a reference point (biweekly and interval) accept an $anchorDate as a constructor argument. Biweekly chores are anchored to ISO week boundaries: the algorithm counts full weeks between the anchor's Monday and the target's Monday using Carbon's diffInWeeks(), then checks whether the result is even. This means the anchor date itself is always an "on" week, and the schedule never drifts regardless of when the chore was last completed.

Interval rules compute the day difference between anchor and target with diffInDays() and check divisibility. An interval of zero or negative is treated as "never due" rather than an exception, a deliberate choice to handle misconfigured records gracefully at runtime.

Error handling

Two exception types: InvalidRuleException (extends \InvalidArgumentException) for unrecognizable rule strings, and \LogicException when biweekly or interval is evaluated without an anchor date. Invalid monthly sub-values (e.g. monthly:foo) also raise InvalidRuleException.

Testing

The test suite covers all six rule variants across normal cases, boundary conditions (last day of month, leap year February 29, zero/negative intervals, anchor-week alignment), wrong-day-of-week rejections, and both exception paths. All tests pass against PHP 8.2+ and PHPUnit 11.

Dependencies

The only runtime dependency is nesbot/carbon ^3.0. No Laravel, no Symfony, no service providers.

Stack

Tech Stack

Explore

More Projects

All projects
Bridge
Screenshots
Featured

Bridge

A self-hosted household operations dashboard managing chore rotations, fitness tracking, and plant care, built for daily use and running 24/7 on a home server.

PHP Laravel Livewire MySQL +3 more
View details
Dinner With Lucy
Live

Dinner With Lucy

A recipe and cookbook manager with fraction-accurate ingredient scaling, star ratings, and cookbook collections.

PHP Laravel Livewire MySQL +2 more
View details
CronosPulse
Live
Featured

CronosPulse

A real-time geophysical dashboard surfacing USGS earthquake data, volcano monitoring, NWS flood alerts, and stream gauge readings.

PHP Laravel Livewire MySQL +5 more
View details