--- description: All date-related data must use DateTime; never add parallel date files or helpers — extend the VO instead alwaysApply: true --- # DateTime Value Object ## Mandatory ALL data related to dates or date-times in the domain and application layers MUST use `DateTime` from `src/common/value-objects/date-time/`. - Construct from HTTP ISO via `DateTime.create(raw)` - Reconstruct from DB via `DateTime.fromUnixMs(ms)` - Compare with `equals()`, persist with `value` / `toJSON()` (unix **milliseconds**, UTC instant) - Render with `format()` / `toString()` using `DEFAULT_TIMEZONE` (default `GMT+7`) — timezone is for display and naive ISO interpretation only There is one date abstraction in this codebase: `DateTime`. Use it for every timestamp, occurrence, schedule instant, created/updated field, and any other date-related value in domain/application code. ## Forbidden Do NOT: - Store or pass date-times as plain `string` / `number` / built-in `Date` in domain models, services, or repositories (beyond the DTO/HTTP or DB number boundary) - Create **any** new file or function for date parsing, validation, formatting, timezone conversion, or comparison - Add pipes, decorators, utils, helpers, or modules that bypass the VO - Use date libraries (`date-fns`, `luxon`, `moment`, `dayjs`, Temporal polyfills, etc.) ```typescript // BAD — new helper / parallel logic function parseDate(raw: string): number { /* ... */ } function formatDate(ms: number): string { /* ... */ } user.occurredAt = Date.parse(dto.occurredAt) // GOOD — DateTime only const occurredAt = DateTime.create(dto.occurredAt) user.occurredAt = occurredAt // DateTime in domain await repo.save({ occurredAt: occurredAt.value }) // unix ms only at persistence edge ``` ## When the VO is not enough If a requirement cannot be met with the current VO (e.g. new input formats, formatting options, comparisons, timezone forms): 1. **Update** `src/common/value-objects/date-time/` (implementation + colocated tests) to match the requirement 2. Do **not** create a new file, function, type, helper, or module for dates ## Boundaries - HTTP DTOs may accept ISO `string`; map to `DateTime.create()` at the service boundary - Database columns may store unix milliseconds (`bigint` / integer); map to/from `DateTime` in the repository - Naive ISO strings (no `Z` / offset) are interpreted in `DEFAULT_TIMEZONE` - `InvalidDateTimeError` is the only date validation error; do not echo raw input in messages - Canonical storage is always UTC; never persist the display timezone as the instant