Use when a codebase needs time zone, DST and leap-year test coverage derived from its own date and time code. Finds where times are stored, computed, displayed, scheduled or billed, picks the edge cases that matter and writes test stubs using the language's fake-clock library.
86%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Time-related bugs are scattered across the codebase - storage, display, business logic, scheduled jobs. The test matrix needs to systematically exercise the canonical edge cases at each touchpoint.
# Generic
grep -rn 'datetime\|Date\|Instant\|time.time\|moment\.\|dayjs\|chrono' \
--include='*.{py,js,ts,java,kt,rb,go,rs,cs}' .
# Per-language
grep -rn 'datetime.now\|datetime.utcnow\|Date.now\|Instant.now' .
grep -rn 'tz\|timezone\|zoneinfo\|ZoneId' .
grep -rn 'cron\|schedule' .Categorise each match:
| Category | Examples | Test needs |
|---|---|---|
| Storage | DB columns; serialised dates | RFC 3339 round-trip (offset or Z preserved) |
| Business logic | Age calculation; duration; expiry | DST, leap-day, monotonic |
| Display | User-facing dates | Per-user-tz formatting |
| Cron / scheduled | Periodic jobs | DST transition behaviour per dst-transition-reference |
| Billing | Period boundaries | DST + month-end + leap year |
| Audit / logging | Timestamp emission | Monotonic; leap-second tolerance |
| External API | Third-party datetime strings | Tolerant parsing |
For each touchpoint, pull the test cases matching its category from references/test-catalog.md, which lists the storage, business-logic, cron, billing, and display tests to exercise.
All per-language fake-clock harnesses live in fake-clock-testing:
| Language | fake-clock-testing reference |
|---|---|
| Python (freezegun) | references/python.md |
| JS/TS (Jest + Sinon fake timers) | references/js.md |
| Ruby (timecop) | references/ruby.md |
| JVM (Clock / InstantSource) | references/jvm.md |
| .NET (TimeProvider / FakeTimeProvider) | references/dotnet.md |
| C / native binary (libfaketime) | references/libfaketime.md |
For each (category, touchpoint, language) cell, generate test stubs:
# tests/time/matrix.yaml
matrix:
- touchpoint: BillingService.createCharge
category: billing
tests:
- dst-fall-back
- leap-year-feb-29
- month-end-rollover
- timezone-multi-tenant
language: java
harness: jvm-clock-injection
- touchpoint: ScheduledTask.runDaily
category: cron
tests:
- dst-spring-forward
- dst-fall-back
- leap-day
language: ruby
harness: timecop
# ...# tests/time/test_billing_service.py
import pytest
from freezegun import freeze_time
from billing import BillingService
@freeze_time("2024-02-29T00:00:00Z")
def test_billing_handles_leap_day():
charge = BillingService.create_charge_for_month(2024, 2)
assert charge.days_in_period == 29
@freeze_time("2025-02-28T00:00:00Z")
def test_billing_handles_non_leap_february():
charge = BillingService.create_charge_for_month(2025, 2)
assert charge.days_in_period == 28
@freeze_time("2026-11-01T05:30:00Z") # Just past fall-back in NY
def test_billing_period_spans_dst_fall_back():
# Period from Nov 1 00:00 to Nov 2 00:00 in New_York
# is 25 hours of UTC due to fall-back
period = BillingService.month_period(year=2026, month=11, zone="America/New_York")
assert period.duration.total_seconds() == 30 * 24 * 3600 + 3600 # 1 extra hourVerify before recording coverage: run the emitted files
(pytest tests/time/, mvn test, etc.) and assert every DST and
leap-day case produces its expected pass (or the expected failure for a
known-bug reproduction). If a case errors instead of asserting, the
fake-clock wiring is wrong - fix the harness mapping (Step 3) or add the
missing TZ / zone for local-time cases - and re-run until the matrix is
green.
# Time Test Matrix Coverage
## Touchpoints covered
| Service | Category | Tests | File |
|---|---|---|---|
| BillingService | billing | leap-day, dst-fall-back, month-end | tests/time/test_billing.py |
| ScheduledTask | cron | dst-spring-forward, leap-day | tests/time/test_cron.py |
| API serialiser | storage | rfc-3339-round-trip | tests/time/test_api_format.py |
## Coverage gaps
- BillingService - leap-second tolerance: deferred (low likelihood)
- Display layer: per-user-TZ rendering - manual QA only
## How to add a new touchpoint
1. Run inventory grep (Step 1).
2. Categorise (Step 2).
3. Update matrix.yaml.
4. Generate test from template (per Step 5).Adding leap-day coverage to a Python BillingService.create_charge_for_month:
inventory (Step 1) categorises it as billing, whose catalog rows call for
month-end-across-leap-year, DST-window, and multi-tenant-timezone tests. Python
maps to freezegun (fake-clock-testing references/python.md, Step 3), so the emitted
tests/time/test_billing_service.py (Step 5) freezes 2024-02-29 asserting
days_in_period == 29 and 2025-02-28 asserting 28. Running the file
(Step 6) confirms both pass, and the coverage doc (Step 7) then records
BillingService's billing category as covered - the leap-year February boundary
is now exercised on every run.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Test only the happy path | Time bugs are edge cases | DST + leap-day mandatory |
| Live system time in tests | Annual / quarterly flakes | Always fake-clock |
| One mega-test for all time edge cases | Failures opaque | Per-category, per-touchpoint |
| Skip storage round-trip | Schema drift / serialiser bug hides | RFC 3339 round-trip everywhere |
| Test in UTC only | Misses local-zone DST / display bugs | Per-zone testing |
| Hardcoded dates that age | Re-write needed annually | Use relative dates or fake clock |
| No coverage doc | Gaps invisible | Step 7 |
| Ignore display-layer | Real users see wrong dates | Even if manual, document the manual coverage |
dst-transition-reference (DST bug classes; leap seconds in its
references/leap-seconds.md).fake-clock-testing (freezegun, Jest/Sinon fake timers, timecop,
JVM Clock injection, .NET TimeProvider, libfaketime).cron-job-test-author (qa-async-jobs).