{"id":39195770,"url":"https://github.com/kristjanesperanto/temporal-kit","last_synced_at":"2026-03-07T14:06:07.567Z","repository":{"id":326901297,"uuid":"1051346779","full_name":"KristjanESPERANTO/temporal-kit","owner":"KristjanESPERANTO","description":"A modern, functional utility library for the Temporal API - experiment with Temporal today.","archived":false,"fork":false,"pushed_at":"2026-03-01T10:58:21.000Z","size":765,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-01T12:43:25.582Z","etag":null,"topics":["date","ecmascript","javascript","temporal","typescript","utility-library"],"latest_commit_sha":null,"homepage":"https://kristjanesperanto.github.io/temporal-kit/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KristjanESPERANTO.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-05T20:40:42.000Z","updated_at":"2026-03-01T10:57:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/KristjanESPERANTO/temporal-kit","commit_stats":null,"previous_names":["kristjanesperanto/temporal-kit"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/KristjanESPERANTO/temporal-kit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KristjanESPERANTO%2Ftemporal-kit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KristjanESPERANTO%2Ftemporal-kit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KristjanESPERANTO%2Ftemporal-kit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KristjanESPERANTO%2Ftemporal-kit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KristjanESPERANTO","download_url":"https://codeload.github.com/KristjanESPERANTO/temporal-kit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KristjanESPERANTO%2Ftemporal-kit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29969700,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T12:56:10.327Z","status":"ssl_error","status_checked_at":"2026-03-01T12:55:24.744Z","response_time":124,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["date","ecmascript","javascript","temporal","typescript","utility-library"],"created_at":"2026-01-17T22:48:18.522Z","updated_at":"2026-03-01T13:01:07.524Z","avatar_url":"https://github.com/KristjanESPERANTO.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Temporal Kit\n\n\u003e **Modern, functional utilities for the Temporal API.**\n\u003e *Experiment with the future of JavaScript dates today.*\n\n[![Status](https://img.shields.io/badge/Status-Ready%20for%20Early%20Adopters-success)](https://github.com/KristjanESPERANTO/temporal-kit)\n[![npm version](https://img.shields.io/npm/v/temporal-kit)](https://www.npmjs.com/package/temporal-kit)\n[![Bundle Size](https://img.shields.io/bundlephobia/minzip/temporal-kit)](https://bundlephobia.com/package/temporal-kit)\n[![License](https://img.shields.io/npm/l/temporal-kit)](https://github.com/KristjanESPERANTO/temporal-kit/blob/main/LICENSE.md)\n\n**Temporal Kit** is a lightweight, tree-shakable library that fills the gap between the raw `Temporal` API and the ergonomic needs of daily development. It provides the missing helper functions—like `startOf`, `isBetween`, or `formatRelative`—in a pure, functional, and type-safe way.\n\n🌐 **[Try the Live Playground →](https://kristjanesperanto.github.io/temporal-kit/)**\n\n## Quick Start\n\n### Installation\n\n```bash\nnpm install temporal-kit\n```\n\n### Basic Usage\n\n```typescript\nimport { isPlainDate, add, startOf } from 'temporal-kit';\n// Or with polyfill for legacy environments:\nimport { isPlainDate } from 'temporal-kit/polyfilled';\n```\n\n### Browser Usage (without bundlers)\n\nFor environments that don't use bundlers (e.g., MagicMirror modules):\n\n```html\n\u003cscript src=\"node_modules/temporal-kit/dist/temporal-kit.browser.polyfilled.global.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  const today = TemporalKit.today();\n  const formatted = TemporalKit.formatPlainDate(today, 'en-US');\n  console.log(formatted); // \"January 9, 2026\"\n\u003c/script\u003e\n```\n\nOr via CDN:\n```html\n\u003cscript src=\"https://unpkg.com/temporal-kit/dist/temporal-kit.browser.polyfilled.global.js\"\u003e\u003c/script\u003e\n```\n\n\u003e **💡 See it in action:** Check out the [`examples`](examples/README.md) for runnable code samples covering type guards, polyfill usage, TypeScript integration, and more.\n\n## Common Recipes\n\n```typescript\nimport { formatRelative, startOf, endOf, add, nextDay, isBetween } from 'temporal-kit';\nimport { Temporal } from 'temporal-polyfill';\n\nconst now = Temporal.Now.zonedDateTimeISO();\n\n// 1. Relative Time\nformatRelative(now.subtract({ minutes: 5 })); // \"5 minutes ago\"\n\n// 2. Find next Friday\nconst nextFriday = nextDay(now, 5); // 5 = Friday\n\n// 3. Check if date is in range\nisBetween(now, startOf(now, 'year'), endOf(now, 'year')); // true\n\n// 4. Business Days\nimport { addBusinessDays, isWeekend } from 'temporal-kit';\nconst monday = addBusinessDays(friday, 1); // Skips weekend\n```\n\n## Documentation\n\n- **[API Reference](./docs/API.md)** - Complete function reference with examples\n- **[Usage Examples](./docs/USAGE_EXAMPLES.md)** - Practical examples for common use cases\n- **[Best Practices](./docs/BEST_PRACTICES.md)** - Comprehensive guide for using temporal-kit effectively\n\n## Supply-Chain Trust\n\nTo improve release integrity and enterprise adoption, `temporal-kit` uses a CI-based publish model with npm provenance.\n\nSee [SECURITY.md](./SECURITY.md) for security policy and trust controls.\nFor maintainer release operations (versioning, stable/`latest` and pre-release/`next` flow), see [CONTRIBUTING.md](./CONTRIBUTING.md).\n\n## 1. Why Temporal Kit?\n\n**Temporal** is arriving as the modern standard for date/time handling in JavaScript, with precise primitives (`Instant`, `ZonedDateTime`, `PlainDate/Time`). By design, Temporal focuses on correctness and intentionally leaves out many convenience helpers—things like `startOf`/`endOf`, humanized formatting, or common comparison utilities. This is deliberate: Temporal provides the foundation, but everyday ergonomics are better handled by libraries.\n\n**Temporal Kit** fills this gap with a focused, Temporal-first toolkit that provides:\n\n1.  **Common Ergonomic Helpers:** The everyday utilities teams need (`startOf`, `endOf`, `add`, `subtract`, `isBefore`, `isAfter`)\n2.  **Intl-First Formatting:** Locale-aware formatting without massive locale files\n3.  **Functional-First Design:** Pure functions, tree-shakable, composable—no hidden state\n4.  **Universal Compatibility:** Runs anywhere JavaScript runs (Browsers, Node.js, Edge) with native Temporal or polyfill\n5.  **Explicit over Magic:** No global config, no implicit conversions, no surprises\n\n**The Goal:** Stop reinventing the same small, error-prone utilities across projects. Instead, share a well-tested, modern implementation that covers 95% of everyday needs while staying lightweight and stable.\n\n## 2. Core Philosophy\n\n### A. Narrow Scope, High Quality\nRather than replicating every feature from older libraries, Temporal Kit focuses on:\n- **The 95% Use Case:** Common helpers that most projects need\n- **Well-Tested Primitives:** Battle-tested implementations to avoid subtle bugs\n- **Lightweight Core:** Keep it fast and stable by staying focused\n\nThe remaining 5%—specialized needs like complex recurring patterns, custom calendar systems, or advanced timezone logic—are better served by dedicated libraries that can focus deeply on those specific domains. For example, [rrule-temporal](https://github.com/ggaabe/rrule-temporal) handles recurring date calculations with iCalendar RRULE support.\n\n### B. \"Temporal First\" \u0026 ISO Compliance\n- We work directly with `Temporal` objects (`ZonedDateTime`, `PlainDate`, etc.)\n- **Clean Break:** No legacy `Date` quirks. Months are 1-indexed. No timezone surprises.\n- **Intl-First:** Formatting uses `Intl.DateTimeFormat` by default—correct localization without massive locale files.\n\n### C. Functional-First API\n\nA pure functional API optimized for composition, tree-shaking, and modern JavaScript patterns.\n\n```typescript\nimport { add, startOf, pipe } from 'temporal-kit'\n\n// Direct composition\nconst result = add(startOf(date, 'day'), { hours: 1 })\n\n// With pipe utility\nconst result = pipe(\n  date,\n  d =\u003e startOf(d, 'day'),\n  d =\u003e add(d, { hours: 1 })\n)\n```\n\n**Benefits:**\n- Perfect tree-shaking - only bundle what you use\n- Composable and testable\n- Modern functional patterns\n- Future-ready for JS pipeline operator (`|\u003e`)\n\n\u003e **Why no method chaining?**\n\u003e Fluent APIs (like `moment().add().startOf()`) are convenient but break tree-shaking because the wrapper object must bundle *all* available methods. By sticking to pure functions, `temporal-kit` remains small and aligns with the future of JavaScript (Pipeline Operator).\n\n### D. Polyfill Strategy (Explicit Opt-in)\nWe adopt a robust strategy for compatibility:\n- **`temporal-kit`**: Lean. Expects `Temporal` to exist. Throws helpful error if missing.\n- **`temporal-kit/polyfilled`**: Imports `temporal-polyfill` automatically for legacy environments (requires `temporal-polyfill` peer dependency).\n\n## 3. Architecture\n\n### Directory Structure\n```\nsrc/\n├── types/          # Core type definitions (DateLike, TimeLike unions)\n├── guards/         # Type guards (isPlainDate, isZonedDateTime, etc.)\n├── compare/        # Comparison functions (isBefore, isAfter, min, max)\n├── convert/        # Creation \u0026 conversion (now, fromISO, explicit conversions)\n├── format/         # Intl-based formatting (format, formatTime, formatDateTime, formatRelative)\n├── math/           # Arithmetic (add, subtract, startOf, endOf)\n├── utils/          # Utilities (pipe, compose)\n├── index.ts        # Main entry (expects native Temporal)\n└── polyfilled.ts   # Auto-loads polyfill for legacy environments\n```\n\n### Implementation Details\n- **Zero Runtime Dependencies:** We build directly on native `Temporal` APIs. Polyfill is optional.\n- **Type-Safe:** Full TypeScript support with strict mode and cutting-edge compiler options.\n- **Dual Entry Points:**\n  - `temporal-kit` - Expects native Temporal\n  - `temporal-kit/polyfilled` - Auto-loads polyfill\n- **Perfect Tree-Shaking:** `sideEffects: false` ensures optimal bundle sizes.\n- **Modern Tooling:**\n  - **Biome** - Fast linting/formatting with performance rules\n  - **Vitest** - Type-checked tests with 100% coverage threshold\n  - **tsup** - ESNext bundling with optimized tree-shaking\n  - **TypeScript 5.x** - Latest compiler features enabled\n- **Testing Strategy:** 100% code coverage including:\n  - Type guards and runtime checks\n  - Comparison and conversion functions\n  - Calendar arithmetic and boundary operations\n  - Intl-based formatting with locale support\n  - Functional composition utilities\n  - Error handling and edge cases\n\n## 4. Features \u0026 Capabilities\n\n- **Comparison:** `isBefore`, `isAfter`, `isSame`, `isBetween`, `min`, `max`, `clamp`\n- **Arithmetic:** `add`, `subtract`, `startOf`, `endOf`\n- **Formatting:** `format`, `formatTime`, `formatDateTime`, `formatRelative` (Intl-based)\n- **Conversion:** `now`, `fromISO`\n- **Ranges:** `rangesOverlap`, `eachDayOfInterval`, `stepInterval`\n- **Collections:** `sortAsc`, `sortDesc`, `closestTo`\n- **Validation:** `isValidDateString`, `isValidTimezone`, `getTimezoneName`\n- **Functional Utils:** `pipe`, `compose`\n\n## 5. Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](./CONTRIBUTING.md) for details on:\n- Development setup\n- Quality checks (Linting, Typechecking, Testing)\n- Release process\n- Project standards\n\n- **ESNext target** - No legacy transpilation, minimal output\n\n## 6. Comparison\n\n| Feature | [Moment.js](https://momentjs.com/) | [date-fns](https://date-fns.org/) | [Luxon](https://moment.github.io/luxon/) | [Native Temporal](https://tc39.es/proposal-temporal/docs/) | **Temporal Kit** |\n| :--- | :--- | :--- | :--- | :--- | :--- |\n| **Base Object** | Mutable Wrapper ⚠️ | Legacy `Date` ⚠️ | Custom Class | `Temporal` | **`Temporal`** |\n| **Paradigm** | OO / Mutable ⚠️ | Functional | OO / Immutable | OO / Verbose | **Functional** |\n| **Timezones** | Separate Helpers | Separate Helpers | Built-in | Native | **Native** |\n| **Tree-Shaking**| ❌ No | ✅ Yes | ❌ No | N/A | **✅ Yes** |\n| **Polyfill Needed?**| No | No | No | No (Native) | **Optional** |\n| **Best For...** | Legacy / Avoid 🛑 | Legacy Projects | Heavy Date Apps | Low-level Logic | **Modern Apps** |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkristjanesperanto%2Ftemporal-kit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkristjanesperanto%2Ftemporal-kit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkristjanesperanto%2Ftemporal-kit/lists"}