antnavdev/recurrence

Featured

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.

Live Demo

See it in action

This project is deployed and available to explore right now.

Launch Live Site

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 pattern objects, no visitor hierarchy. 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 unrecognisable 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 personal operations dashboard managing chores, fitness, plants, and job applications. Deployed on a home server.

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

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