dates-streaks-and-statistics
Builds calendar-day logic: local date keys, an injected clock, midnight, DST, streaks, stats.
Skill by zakariaf
Chalk Labs
Need help deploying dates-streaks-and-statistics?
Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/zakariaf-dates-streaks-and-statistics
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: productivity
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 26, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Node.js package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/dates-streaks-and-statistics
What's inside
- Skill name
dates-streaks-and-statistics- Description
- Builds calendar-day logic: local date keys, an injected clock, midnight, DST, streaks, stats. Use when code reads today, counts days, shows a streak or stats, or a date is a day off. Not for seeds (seeded-determinism-and-golden-vectors).
- License
- MIT
- Instructions
- 211 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Files (56)
- SKILL.md
- shared.json · assets/
- complete-task.ts · examples/
- local-date.test.ts · examples/
- local-date.ts · examples/
- stats-cells.test.ts · examples/
- stats-cells.ts · examples/
- use-streak-card-model.ts · examples/
- calendar-days.md · references/
- checkers.md · references/
- statistics.md · references/
- streaks.md · references/
- check-calendar-code.mjs · scripts/
- check-lib.mjs · scripts/
- check-streaks-and-stats.mjs · scripts/
- app-modules.mjs · scripts/lib/
- calendar-checks.mjs · scripts/lib/
- day-logic-contract.mjs · scripts/lib/
- load-error.mjs · scripts/lib/
- source-scan.mjs · scripts/lib/
- stats-checks.mjs · scripts/lib/
- streak-checks.mjs · scripts/lib/
- selftest.mjs · scripts/
- day-logic.json · templates/contracts/
- day-logic.schema.json · templates/contracts/
- split-countdown.test.ts · templates/src/core/countdown/
- split-countdown.ts · templates/src/core/countdown/
- date-key.test.ts · templates/src/core/dates/
- date-key.ts · templates/src/core/dates/
- activity-stats.test.ts · templates/src/core/stats/
- activity-stats.ts · templates/src/core/stats/
- record-completion.test.ts · templates/src/core/stats/
- record-completion.ts · templates/src/core/stats/
- stats-summary.test.ts · templates/src/core/stats/
- stats-summary.ts · templates/src/core/stats/
- day-streak.test.ts · templates/src/core/streaks/
- day-streak.ts · templates/src/core/streaks/
- streak-summary.test.ts · templates/src/core/streaks/
- streak-summary.ts · templates/src/core/streaks/
- use-next-day-countdown.test.ts · templates/src/hooks/
- use-next-day-countdown.ts · templates/src/hooks/
- use-today.test.ts · templates/src/hooks/
- use-today.ts · templates/src/hooks/
- clock-port.ts · templates/src/services/clock/
- fake-clock.test.ts · templates/src/services/clock/
- fake-clock.ts · templates/src/services/clock/
- system-clock-adapter.test.ts · templates/src/services/clock/
- system-clock-adapter.ts · templates/src/services/clock/
- package.json · tests/bases/app/
- tsconfig.json · tests/bases/app/
- CASES.json · tests/fixtures/check-calendar-code/
- SUITE.json · tests/fixtures/check-calendar-code/
- EXPECT.txt · tests/fixtures/check-calendar-code/good/
- CASES.json · tests/fixtures/check-streaks-and-stats/
- SUITE.json · tests/fixtures/check-streaks-and-stats/
- EXPECT.txt · tests/fixtures/check-streaks-and-stats/good/
SKILL.md (first lines)
# Dates, streaks and statistics
Every "today", "due today", streak, countdown and statistic in an Expo app is computed on the user's
local civil-date keys from one injected clock, survives midnight, DST, travel and a clock set back,
is folded by pure tested functions in one write per event, and reaches the screen as a finished
summary on iOS and Android alike; two checkers prove it on the app's own code.
## Rules that must hold
1. **A day is a local civil-date key from `clock.today()`, and day arithmetic is integer maths on
keys.** `DateKey` `'YYYY-MM-DD'` through `src/core/dates/date-key.ts` (`addDays`, `daysBetween`,
`isoWeekday`); never `toISOString().slice(0, 10)` or `getUTC*` for a day, never `new Date(key)` or
`Date.parse(key)`, never a key built by hand from `getFullYear()`/`getMonth()`/`getDate()` outside
`src/services/clock/` (a picker's `Date` converts through `local-date.ts` there), never a duration
divided by 86,400,000. Why: the UTC day is wrong for hours every day outside UTC, a date-only string
parses as UTC midnight, and a local day lasts 23, 24 or 25 hours. (`utc-day`, `date-only-parse`,
`local-day-key`, `day-ms-arithmetic`, `date-math`)
2. **Only the clock adapter reads the wall clock; day, streak and statistics code receives time as
values.** `ClockPort` (`nowMs`, `today`, `msUntilNextLocalDay`; architecture-and-boundaries owns
it) is the one source; no `Date`, `Date.now`, `Math.random`, `Intl.DateTimeFormat` or `toLocale*`
in day code. Why: one reader makes every rule a millisecond test with the fake clock, and two
devices never disagree about the day. (`wall-clock`, `clock-countdown`)
3. **"Today" is read on every render, never cached.** `useToday()` re-renders at local midnight (a
timer armed from `msUntilNextLocalDay()`, at most a minute long) and when the app returns to the
foreground; handlers call `clock.today()` again; no `useState`, `useRef`, `useMemo` or module
constant, no effect that copies `today()` into state. Why: a screen left open overnight, or resumed the next morning, otherwise shows
yesterday. (`today-cached`, `today-hook`)
4. **An event belongs to the local day it started**, captured then and passed into every fold, which
never re-reads the clock. Why: a session finished after midnight would otherwise count for a day the
user never started it on. (`completion-record`)
5. **Streaks follow one pure model.** The first event of a day marks it and repeats change nothing; the
streak lives while the last active day is today or yesterday; a longer gap restarts it at 1; the
best is kept; a clock set back (or a flight west) never removes a done day or counts one twice; a
derived streak agrees with the stored one. Grace, freezes and repairs are product data recorded as
days, never branches in the rule. Why: these are the rules users check by hand.
(`streak-first-of-day`, `streak-rule`, `streak-clock-back`, `streak-week`, `streak-derive`)
6. **Every number has one source of truth.** Derive it on read from rows the app keeps forever, or, when
the detail is pruned, capped or deletable, store it as a counter updated by the same fold;
never count a pruned window (`Object.keys(byDay).length`) and never store a copy of what you derive.
Why: a 400-day streak must not read 60, and two sources drift. (`streak-prune`, `stats-best`,
`view-stats`)
7. **A completion updates its row, the streak and the statistics in one transaction, before the
confirmation shows.** One pure `recordCompletion(progress, completion)`; practice (a sample, a
tutorial, a replay of a scored day) records nothing; a repeat on an active day counts in the
statistics and leaves the streak untouched; folds never mutate their input. Why: a kill between two
writes leaves a streak that contradicts the history. (`completion-record`, `fold-immutable`)
8. **Statistics fold by fixed rules.** Totals, successes, failures and time add up; any failure resets
the run of successes and the longest is kept; per-day buckets cover a fixed window counted back from
the newest day; custom counters have stable kebab-case ids (stored keys) and fold by `'sum'` or
`'max'` over the final committed steps, so undone steps never count. Why: a renamed id orphans a
stored total, and an undo must not inflate a record. (`stats-counts`, `stats-run`, `stats-days`,
`stats-counters`)
9. **Screens only format a pure summary.** `buildStreakSummary` / `buildStatsSummary` produce every
number, mark and flag (seven days oldest first with ISO weekdays, rates as 0..1 with a zero guard,
whole-unit durations, `isEmpty` for a new user; statistics take the streak counts from
`streakCountsOf`, never the streak section); components and hooks do no day arithmetic and read
no raw buckets; labels and digits come from the i18n layer. Why: maths in a view is untested and
differs between screens. (`day-maths-in-ui`, `view-streak`, `view-stats`)
10. **The time to the next day comes from `msUntilNextLocalDay()`.** `useNextDayCountdown()` with
whole-minute snapshots and minutes rounded up by the pure `splitCountdown` in
`src/core/countdown/` (never "0 h 0 min" before midnight); never
`86_400_000 - nowMs % 86_400_000`. Why: only the adapter knows the zone and DST, and the modulo
form is the time to midnight in London. (`view-countdown`, `day-maths-in-ui`)
## Workflow
1. **Read the reference for the task:**
| Task | Read |
|---|---|
| "today", due days, midnight, DST, time zones, a date picker, a server date, a countdown, a date off by one | [references/calendar-days.md](references/calendar-days.md) |
| a streak, a week strip, a daily check-in or daily challenge | [references/streaks.md](references/streaks.md) |
| statistics, counters, the completion write, a stats screen, "Reset statistics" | [references/statistics.md](references/statistics.md) |
| a checker failure, the contract, SKIP or NOT APPLICABLE lines, multi-package | [references/checkers.md](references/checkers.md) |
2. **Check the prerequisites.** The clock port, its system adapter and fake, and the composition root
(`useServices`, `createTestServices`) come from architecture-and-boundaries; `date-key.ts` from
seeded-determinism-and-golden-vectors; the render helpers (`@test/render-with-providers`) from
unit-and-component-tests. This skill carries synced copies of the clock and date-key files in
`templates/src/services/clock/` and `templates/src/core/dates/`: copy them only when the app lacks
them, and never edit them in the app (the skills that own them change them).
3. **Copy the templates the app needs** to the paths their first lines name: always
`templates/src/hooks/` (`use-today.ts`, `use-next-day-countdown.ts`, tests) and
`templates/src/core/countdown/` (the pure `splitCountdown` the countdown hook imports); for streaks
`templates/src/core/streaks/`; for statistics `activity-stats.ts` and `stats-summary.ts` from
`templates/src/core/stats/`, plus `record-completion.ts` only when the app has streaks too (it is
the one file that imports both folders); and `templates/contracts/day-logic.json` with its schema,
setting a module to `null` when the app does not have it (the checkers refuse a module whose
dependency is `null`). Each module ships with its test.
4. **Decide what counts.** Write the qualifying rule once in feature logic (`completionOf(task, today)`
in [examples/complete-task.ts](examples/complete-task.ts)): which event marks a day, what is a
success, which items are practice, which counters exist (kebab-case ids, `'sum'` or `'max'`).
5. **Wire the write.** The handler reads `clock.today()`, folds with `recordCompletion`, and writes the
row and the progress in one repository transaction through `updateAndPublish`
([examples/complete-task.ts](examples/complete-task.ts); persistence-and-migrations owns the table
and its migration, state-management-zustand the store and the publish).
6. **Wire the screens.** A model hook reads `useToday()`, the stored sections through selectors and
`useNextDayCountdown()`, builds the summary and formats it with the i18n layer
([examples/use-streak-card-model.ts](examples/use-streak-card-model.ts),
[examples/stats-cells.ts](examples/stats-cells.ts)); the component renders only what it gets.
7. **Test first for any rule change**, then run
`npx jest src/core/streaks src/core/stats src/core/dates src/services/clock src/hooks --ci --selectProjects unit`
(paths before the flag) and `npm run typecheck`.
8. **Run the checks** from the repo root: `node ${CLAUDE_SKILL_DIR}/scripts/check-streaks-and-stats.mjs .`
and `node ${CLAUDE_SKILL_DIR}/scripts/check-calendar-code.mjs .`; fix every `FAIL` line (file, rule
and fix are printed) and rerun until both print `RESULT: PASS`.
## Definition of done
- [ ] No day is computed from a UTC string, a `getUTC*` getter, a key parsed with `new Date(key)` or
milliseconds divided by a day; every exception carries `// not-a-calendar-day: <why>`.
- [ ] Only `src/services/clock/*-adapter.ts` reads the wall clock (`Date.now()`, `new Date()`); day, streak and statistics code takes keys
and numbers as arguments.
- [ ] Every screen that shows a day reads `useToday()`; handlers read `clock.today()` again; the
countdown reads `useNextDayCountdown()`.
- [ ] The streak, statistics and completion modules are the templates or pass the same tests;
`contracts/day-logic.json` names each module or sets it to `null`, never naming a module whose
dependency is `null`.
- [ ] A completion is one transaction (row + progress) published after the commit, before theFrom zakariaf/ReactNative-Skills, MIT.
More from zakariaf/ReactNative-Skills
- 0.606score
debug-menu-and-test-hooks
zakariaf
Gates test-only code behind one literal TEST_ONLY switch: debug menu, debug link, simulated clock and offline.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
accessibility-as-code
zakariaf
Enforces a11y labels, 44pt targets, 200% text, VoiceOver, TalkBack.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
adaptive-layout
zakariaf
Lays screens out by window, not device: breakpoints, master-detail panes, readable widths, grids.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
admob-ads-and-consent
zakariaf
Builds AdMob ads behind a port - banners, interstitials, rewarded, UMP consent then ATT, pacing, ADS_MODE test IDs.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
analytics-and-consent
zakariaf
Gates analytics on opt-in consent: no SDK before a yes, typed events without personal data, ATT.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
android-release-play
zakariaf
Ships Android App Bundles to Google Play: upload key, Play App Signing, AAB gate, versionCode, tracks, rollout.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
architecture-and-boundaries
zakariaf
Places app code in the src/ layout and checks import boundaries: one-way zones, pure core, ports with fakes, one composition root.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
async-safety
zakariaf
Prevents silent async bugs: effect races, stale results, lost promises, leaked listeners and timers, AbortSignal gaps.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
audio-and-haptics-feedback
zakariaf
Builds SFX and haptics behind ports.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
auth-and-secure-storage
zakariaf
Builds sign-in - tokens in expo-secure-store, shared refresh, protected routes, OAuth PKCE, Apple sign-in.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
background-tasks
zakariaf
Builds expo-background-task jobs: idempotent, budgeted runs.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
canvas-gestures-and-hit-testing
zakariaf
Turns canvas taps, swipes, drags and aim into typed intents: one gesture module, hit-testing on the drawn layout.
SkillAFreshness: A★ 11Claude Code +9
Signals
- Stars
- 11
- Forks
- 2
- Open issues
- 0
- Last commit (this folder)
- Oct 17, 2026 (13 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/zakariaf/ReactNative-Skills
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from zakariaf
- 0.606score
admob-ads-and-consent
zakariaf
Builds AdMob ads behind a port - banners, interstitials, rewarded, UMP consent then ATT, pacing, ADS_MODE test IDs.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
accessibility-as-code
zakariaf
Enforces a11y labels, 44pt targets, 200% text, VoiceOver, TalkBack.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
canvas-gestures-and-hit-testing
zakariaf
Turns canvas taps, swipes, drags and aim into typed intents: one gesture module, hit-testing on the drawn layout.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
adaptive-layout
zakariaf
Lays screens out by window, not device: breakpoints, master-detail panes, readable widths, grids.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
debug-menu-and-test-hooks
zakariaf
Gates test-only code behind one literal TEST_ONLY switch: debug menu, debug link, simulated clock and offline.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
analytics-and-consent
zakariaf
Gates analytics on opt-in consent: no SDK before a yes, typed events without personal data, ATT.
SkillAFreshness: A★ 11Claude Code +9
Done for you
Rather not set it up yourself?
Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.
See how we build AI agents →Read the case studies
Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.
- launches shipped
- 50+
- launches shipped
- media placements
- 500+
- media placements
- founders on every account
- 2
- founders on every account
Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block
Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.
Get dates-streaks-and-statistics running in your business
Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.
Cite this page
dates-streaks-and-statistics skill. Agent Mart. https://agentmart.dev/skills/zakariaf-dates-streaks-and-statistics (last updated 2026-10-24)