Skip to content

Add period-completeness helpers#16

Merged
mcaselli merged 8 commits into
masterfrom
feature/period-completeness
Jul 15, 2026
Merged

Add period-completeness helpers#16
mcaselli merged 8 commits into
masterfrom
feature/period-completeness

Conversation

@mcaselli

@mcaselli mcaselli commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a shared, business-day-aware period-completeness toolkit, and aligns the existing most_recent_* helpers with it.

New functions

  • period_is_complete(date, unit, as_of, calendar, week_start) — is the period (week/month/quarter/year) containing each date complete as of the cutoff as_of? A period is complete once no business days remain after as_of up to and including the period end, evaluated in a QuantLib calendar.
    • calendar = "WeekendsOnly" (default): complete once only weekends remain.
    • a national calendar (e.g. "UnitedStates"): holiday-accurate.
    • calendar = "Null": pure calendar-day semantics (period_end_date(date) <= as_of).
  • period_start_date() / period_end_date() — canonical first/last calendar day of the period. Business-day calendars only ever inform completeness, never the returned dates.
  • filter_complete_periods(data, date_col, ...) — keep only rows whose period is complete; as_of defaults to max(date_col) so completeness tracks how current the data is.
  • last_complete_period_start() / last_complete_period_end() — boundaries of the most recent complete period as of a cutoff.
  • scale_alpha_logical() — ggplot2 alpha scale to fade the in-progress period; pairs with period_is_complete().

as_of has no wall-clock default

period_is_complete() and last_complete_period_*() require an explicit as_of — there is no Sys.Date() default. Completeness is a data-currency judgment, and this work runs mostly on cached extracts, so silently keying off the wall clock would misread stale data (e.g. marking a past-but-partial month complete). Pass Sys.Date() to opt into wall-clock behaviour. filter_complete_periods(), which sees the data frame, defaults as_of to max(date_col).

max(date) is deliberately not a default for period_is_complete(): its date argument is frequently period anchors from group_by(month = period_start_date(...)), where the max is the latest bucket start, not how current the data is.

Behaviour change: most_recent_*

most_recent_monday() / most_recent_sunday()'s ref_date argument is renamed as_of, for a consistent reference-date name across the temporal helpers (both name the date that state is evaluated as of). Their current-date default is unchanged and positional calls are unaffected — only callers passing ref_date = by name need to switch to as_of =.

Notes

  • Built on the existing qlcal engine (bizdays_between()) and calendar scoping.
  • week_start defaults to getOption("lubridate.week.start", 7) so the package defers to the session's week convention.
  • Vectorizes correctly over a date span (a fix over a prior implementation that mis-judged future periods when as_of sat on its own period's last business day).
  • Vignette gains a Period completeness section whose examples are chosen so each illustrated argument visibly changes the output — e.g. a holiday example on the July-4th work week, where "UnitedStates" reports the week complete but the default "WeekendsOnly" does not.

Tests

test-period_completeness.R (33 test_that blocks) covers weekend/holiday month-end edges, as_of on the period end, "Null" equivalence, the vectorization regression, last_complete_period_* step-back, filter_complete_periods default / guarded as_of, required-as_of errors, NA propagation, leap-February, year-end, and week_start; plus a named-as_of test for most_recent_*. Full suite: 275 pass, 0 failures, 0 warnings. R CMD check: 0 errors, 0 warnings (2 environmental NOTEs).

Provides a shared, business-day-aware toolkit for reporting on partial
periods, replacing logic that was re-implemented per project.

`period_is_complete()` tests whether the period (week/month/quarter/
year) containing each date is complete as of a cutoff, using a QuantLib
calendar (default "WeekendsOnly"; "UnitedStates" for holiday accuracy;
"Null" for pure calendar-day semantics). Also adds
`period_start_date()`/`period_end_date()` (canonical calendar
boundaries), `filter_complete_periods()` (drops the in-progress trailing
period; as_of defaults to the data max and an earlier as_of is an error),
`last_complete_period_start()`/`last_complete_period_end()`, and
`scale_alpha_logical()` for fading incomplete periods in ggplots.

Completeness is judged on business days only; returned dates are always
canonical calendar boundaries. NA dates propagate to NA and are dropped
by filter_complete_periods(). Vectorizes correctly over a span of dates.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@mcaselli
mcaselli force-pushed the feature/period-completeness branch from e9ad12f to 714ba21 Compare July 14, 2026 18:58
Michael Caselli and others added 7 commits July 14, 2026 15:14
Restrict the period-completeness family to week/month/quarter/year.
"day" had no real use case here: the boundary functions are no-ops for
it (start and end both equal the input date), and business-day
completeness produces misleading results for single days (a Sunday reads
complete as of the preceding Saturday). "Is a day complete" is just
date <= as_of and needs none of this machinery. Invalid units, including
"day", now error via validate_period_unit().

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Add a "Period completeness" section covering period_start_date()/
period_end_date(), period_is_complete(), the scale_alpha_logical()
alpha-fade for in-progress periods, filter_complete_periods(), and
last_complete_period_end()/start(), worked through example_sales (whose
final month is partial). Bridges from the existing dashed-final-period
behavior of plot_accounts_by_status().

Scale back the business-day-of-period burn-up section: replace the
by-market faceted example (a near-duplicate of the global one) with a
one-line pointer, to keep the vignette focused.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
The monthly example passed as_of = max(order_date) to period_is_complete(),
silently duplicating filter_complete_periods()'s default cutoff and
obscuring which behavior is the default. Restructure as a two-part
example: first filter_complete_periods() with defaults (December, still
in progress, drops out), then a counter-example supplying an as_of in
the next period ("data complete through January 1") so the trailing
month counts as complete. The alpha-fade chart now states it reuses that
same latest-date cutoff. Also correct the note that period_is_complete()
defaults as_of to the current date.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Replace the filter_complete_periods() summaries with the more transparent
group_by(month) |> summarise() style, in two pieces. The first omits
as_of, so completeness is judged as of today and every historical month
(including the partial December) reads complete; the second passes
as_of = latest order date and a UnitedStates holiday calendar, correctly
flagging December incomplete. Each summary shows month, units,
last_order_in_period, and complete, making the reasoning visible.
filter_complete_periods() is kept as a brief row-filter shortcut.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
period_is_complete(), last_complete_period_start(), and
last_complete_period_end() no longer default as_of to the current
date. Completeness is a data-currency judgment, so silently keying it
off Sys.Date() misreads cached/stale data (e.g. marking a past-but-
partial month complete). Callers now state the reference explicitly;
pass Sys.Date() to opt into wall-clock. filter_complete_periods() is
unchanged (still defaults as_of to the max of its date column).

For a consistent temporal-helper surface, rename most_recent_monday()
/ most_recent_sunday()'s ref_date argument to as_of (same concept: the
date state is evaluated as of). Their current-date default is kept;
positional calls are unaffected, only named ref_date = callers.

Vignette recast to two references (wall-clock vs latest data date);
tests added for the required-as_of errors and the as_of argument.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Drop the design-decision prose and the two inert examples (Sys.Date()
where everything reads complete, and a UnitedStates calendar that
changed nothing at as_of = 2024-12-20). Replace with examples whose
output visibly reflects the argument shown: a vector as_of returning
TRUE/TRUE/FALSE, and a holiday example on the July-4th work week where
"UnitedStates" reports complete but "WeekendsOnly" does not.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@mcaselli
mcaselli merged commit 331b969 into master Jul 15, 2026
7 checks passed
@mcaselli
mcaselli deleted the feature/period-completeness branch July 15, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant