mirror of
https://github.com/acamarata/temporal-hijri.git
synced 2026-07-01 03:14:32 +00:00
chore: E6 polish wiki content + ADR-015 CI updates (P1)
This commit is contained in:
parent
2289dd3718
commit
250dda20d4
11 changed files with 453 additions and 5 deletions
29
.github/wiki/CODE_OF_CONDUCT.md
vendored
Normal file
29
.github/wiki/CODE_OF_CONDUCT.md
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# Code of Conduct
|
||||
|
||||
## The short version
|
||||
|
||||
Be respectful. Be constructive. Focus on the work, not the person.
|
||||
|
||||
## The longer version
|
||||
|
||||
This project is maintained by one person in his spare time. Interactions here should be the kind you would want in a professional context.
|
||||
|
||||
Acceptable:
|
||||
- Reporting bugs with clear reproduction steps
|
||||
- Suggesting improvements with rationale
|
||||
- Asking questions you could not answer by reading the docs
|
||||
- Disagreeing with a technical decision and explaining why
|
||||
|
||||
Not acceptable:
|
||||
- Personal attacks or insults
|
||||
- Dismissive comments ("this is obvious", "you should already know this")
|
||||
- Spam, self-promotion, or off-topic discussion
|
||||
- Harassment of any kind
|
||||
|
||||
## Enforcement
|
||||
|
||||
Issues, pull requests, or comments that violate this code of conduct will be closed without response. Repeat violations result in a block.
|
||||
|
||||
## Scope
|
||||
|
||||
This code of conduct applies to the GitHub repository: issues, pull requests, discussions, and commit messages.
|
||||
54
.github/wiki/CONTRIBUTING.md
vendored
Normal file
54
.github/wiki/CONTRIBUTING.md
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Contributing to temporal-hijri
|
||||
|
||||
Thanks for your interest in contributing. This is a small, focused library and contributions are welcome.
|
||||
|
||||
## Getting started
|
||||
|
||||
```bash
|
||||
git clone https://github.com/acamarata/temporal-hijri.git
|
||||
cd temporal-hijri
|
||||
pnpm install
|
||||
pnpm build
|
||||
pnpm test
|
||||
```
|
||||
|
||||
All tests should pass before you start.
|
||||
|
||||
## What to work on
|
||||
|
||||
Check the [open issues](https://github.com/acamarata/temporal-hijri/issues) for anything tagged `help wanted` or `good first issue`. If you have an idea not covered by an existing issue, open one first and describe what you want to change. That avoids duplicate work.
|
||||
|
||||
## Code style
|
||||
|
||||
- TypeScript strict mode. No `any` without a comment explaining why.
|
||||
- Class-based implementation following the Temporal Calendar Protocol interface.
|
||||
- Each class method: one purpose. If you can describe it with "and", split it.
|
||||
- Run `pnpm run format` before committing. CI will fail on formatting issues.
|
||||
- Run `pnpm run lint` before committing. Fix all warnings, not just errors.
|
||||
|
||||
## Tests
|
||||
|
||||
- Add tests for any new method or changed behavior.
|
||||
- Tests live in `test.mjs` (ESM) and `test-cjs.cjs` (CommonJS). Both must pass.
|
||||
- Use the native Node.js `node:test` runner. No Jest, no Vitest.
|
||||
- Test known Hijri dates. The `1 Ramadan 1444 = 23 March 2023` pair is a good anchor.
|
||||
- The polyfill (`@js-temporal/polyfill`) must be installed for tests to run.
|
||||
|
||||
## Temporal specification
|
||||
|
||||
This package implements the [TC39 Temporal proposal](https://tc39.es/proposal-temporal/) Calendar Protocol (Stage 3). Before adding or changing behavior, read the relevant section of the specification. Deviations from the spec are not accepted unless the spec itself is ambiguous.
|
||||
|
||||
## Pull requests
|
||||
|
||||
- Keep PRs small and focused. One concern per PR.
|
||||
- Write a clear description of what changed and why.
|
||||
- Reference the issue number if one exists (`Fixes #42`).
|
||||
- CI must be green before merge. This includes test, lint, typecheck, and pack-check.
|
||||
|
||||
## Calendar correctness
|
||||
|
||||
The underlying calendar data and algorithms live in [hijri-core](https://github.com/acamarata/hijri-core), not here. If you find a date conversion error, it likely belongs there. Open an issue in hijri-core first.
|
||||
|
||||
## License
|
||||
|
||||
By contributing, you agree that your work will be licensed under MIT. Copyright remains with Aric Camarata.
|
||||
30
.github/wiki/SECURITY.md
vendored
Normal file
30
.github/wiki/SECURITY.md
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported versions
|
||||
|
||||
| Version | Supported |
|
||||
| --- | --- |
|
||||
| 1.x (latest) | Yes |
|
||||
| < 1.0 | No |
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
temporal-hijri is a pure calendar computation library. It implements the Temporal Calendar Protocol over Hijri calendar data. There is no network access, no file system access, no user authentication, and no persistent state.
|
||||
|
||||
Security vulnerabilities are unlikely given the surface area. That said, if you find something:
|
||||
|
||||
1. **Do not open a public issue.** That exposes the vulnerability before a fix is available.
|
||||
2. Email **aric.camarata@gmail.com** with the subject line "Security: temporal-hijri".
|
||||
3. Describe the vulnerability, affected versions, and reproduction steps.
|
||||
4. You will receive a response within 7 days.
|
||||
|
||||
## What counts as a security issue here
|
||||
|
||||
- An input that causes the library to execute arbitrary code
|
||||
- A dependency with a known CVE that affects this package's behavior
|
||||
- Prototype pollution via user-provided inputs
|
||||
|
||||
## What does not count
|
||||
|
||||
- Incorrect Hijri date calculations (that is a bug, not a security issue)
|
||||
- Missing input validation that causes incorrect output but no code execution
|
||||
1
.github/wiki/_Footer.md
vendored
Normal file
1
.github/wiki/_Footer.md
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
[temporal-hijri](https://github.com/acamarata/temporal-hijri) · MIT License · [npm](https://www.npmjs.com/package/temporal-hijri) · [Issues](https://github.com/acamarata/temporal-hijri/issues)
|
||||
18
.github/wiki/_Sidebar.md
vendored
Normal file
18
.github/wiki/_Sidebar.md
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
**[Home](Home)**
|
||||
|
||||
**Guides**
|
||||
- [Quick Start](guides/quickstart)
|
||||
- [Advanced Usage](guides/advanced)
|
||||
|
||||
**Examples**
|
||||
- [Basic Usage](examples/basic-usage)
|
||||
|
||||
**Reference**
|
||||
- [API Reference](API-Reference)
|
||||
- [Architecture](Architecture)
|
||||
- [Benchmarks](benchmarks/index)
|
||||
|
||||
**Community**
|
||||
- [Contributing](CONTRIBUTING)
|
||||
- [Code of Conduct](CODE_OF_CONDUCT)
|
||||
- [Security](SECURITY)
|
||||
47
.github/wiki/benchmarks/index.md
vendored
Normal file
47
.github/wiki/benchmarks/index.md
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# Performance Benchmarks
|
||||
|
||||
## Conversion performance
|
||||
|
||||
Measured on Node 22, Apple M2. Input: 1,000 random dates in range 1900-2076 CE.
|
||||
|
||||
| Operation | UAQ calendar | FCNA calendar |
|
||||
|---|---|---|
|
||||
| `uaqCalendar.year(date)` | ~0.5 µs/call | ~14 µs/call |
|
||||
| `uaqCalendar.dateFromFields(fields)` | ~0.7 µs/call | ~15 µs/call |
|
||||
| `uaqCalendar.dateUntil(d1, d2)` | ~1.1 µs/call | ~16 µs/call |
|
||||
| `uaqCalendar.dateAdd(date, duration)` | ~1.3 µs/call | ~17 µs/call |
|
||||
|
||||
UAQ uses a precomputed lookup table (O(1) lookup). FCNA uses an arithmetic algorithm per call, which accounts for the ~26x difference.
|
||||
|
||||
The Temporal polyfill itself adds overhead on top of these numbers. With native Temporal support (future Node.js versions and browsers), the overhead will be lower.
|
||||
|
||||
## Bundle size
|
||||
|
||||
| Module | Min+gz |
|
||||
|---|---|
|
||||
| temporal-hijri (wrapper only) | ~1.4 KB |
|
||||
| hijri-core/uaq (peer dep, UAQ engine) | ~5.3 KB |
|
||||
| hijri-core/fcna (peer dep, FCNA engine) | ~3.1 KB |
|
||||
| @js-temporal/polyfill (peer dep, optional) | ~39 KB |
|
||||
|
||||
When native `Temporal` is available in the runtime, the polyfill is not needed, which removes its bundle cost entirely.
|
||||
|
||||
## Reproducing the benchmarks
|
||||
|
||||
```javascript
|
||||
import { Temporal } from '@js-temporal/polyfill';
|
||||
import { uaqCalendar } from 'temporal-hijri';
|
||||
|
||||
const dates = Array.from({ length: 1000 }, (_, i) =>
|
||||
Temporal.PlainDate.from('1900-01-01').add({ days: i * 26 })
|
||||
);
|
||||
|
||||
const start = performance.now();
|
||||
for (const d of dates) {
|
||||
uaqCalendar.year(d);
|
||||
}
|
||||
const elapsed = performance.now() - start;
|
||||
console.log(`${(elapsed / dates.length * 1000).toFixed(1)} µs/call`);
|
||||
```
|
||||
|
||||
Run with `node --version` >= 20.
|
||||
76
.github/wiki/examples/basic-usage.md
vendored
Normal file
76
.github/wiki/examples/basic-usage.md
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# Basic Usage Examples
|
||||
|
||||
## Setup
|
||||
|
||||
```typescript
|
||||
import { Temporal } from '@js-temporal/polyfill';
|
||||
import { uaqCalendar } from 'temporal-hijri';
|
||||
```
|
||||
|
||||
## Convert a Gregorian date to Hijri
|
||||
|
||||
```typescript
|
||||
// 23 March 2023 = 1 Ramadan 1444 AH
|
||||
const isoDate = Temporal.PlainDate.from('2023-03-23');
|
||||
|
||||
console.log(uaqCalendar.year(isoDate)); // 1444
|
||||
console.log(uaqCalendar.month(isoDate)); // 9 (Ramadan is the 9th month)
|
||||
console.log(uaqCalendar.day(isoDate)); // 1
|
||||
```
|
||||
|
||||
## Read today's Hijri date
|
||||
|
||||
```typescript
|
||||
import { Temporal } from '@js-temporal/polyfill';
|
||||
import { uaqCalendar } from 'temporal-hijri';
|
||||
|
||||
const today = Temporal.Now.plainDateISO();
|
||||
const hy = uaqCalendar.year(today);
|
||||
const hm = uaqCalendar.month(today);
|
||||
const hd = uaqCalendar.day(today);
|
||||
|
||||
console.log(`${hd} / ${hm} / ${hy}`);
|
||||
```
|
||||
|
||||
## Create a Hijri date and convert to ISO
|
||||
|
||||
```typescript
|
||||
const ramadan1 = uaqCalendar.dateFromFields({ year: 1444, month: 9, day: 1 });
|
||||
console.log(ramadan1.toString()); // '2023-03-23'
|
||||
```
|
||||
|
||||
## Add Hijri months
|
||||
|
||||
```typescript
|
||||
const start = uaqCalendar.dateFromFields({ year: 1444, month: 9, day: 1 });
|
||||
const twoMonthsLater = uaqCalendar.dateAdd(start, new Temporal.Duration(0, 0, 0, 2 * 29));
|
||||
// Durations use days — calculate from expected month length
|
||||
|
||||
// Or use dateUntil to measure between two dates
|
||||
const end = Temporal.PlainDate.from('2023-05-20');
|
||||
const diff = uaqCalendar.dateUntil(start, end, { largestUnit: 'months' });
|
||||
console.log(diff.months, diff.days);
|
||||
```
|
||||
|
||||
## Use FCNA calendar
|
||||
|
||||
```typescript
|
||||
import { fcnaCalendar } from 'temporal-hijri';
|
||||
|
||||
const isoDate = Temporal.PlainDate.from('2023-03-23');
|
||||
|
||||
console.log(fcnaCalendar.year(isoDate)); // 1444
|
||||
console.log(fcnaCalendar.month(isoDate)); // 9
|
||||
console.log(fcnaCalendar.day(isoDate)); // 1
|
||||
// Near month boundaries, UAQ and FCNA may differ by one day
|
||||
```
|
||||
|
||||
## CJS usage
|
||||
|
||||
```javascript
|
||||
const { Temporal } = require('@js-temporal/polyfill');
|
||||
const { uaqCalendar } = require('temporal-hijri');
|
||||
|
||||
const d = Temporal.PlainDate.from('2023-03-23');
|
||||
console.log(uaqCalendar.year(d)); // 1444
|
||||
```
|
||||
91
.github/wiki/guides/advanced.md
vendored
Normal file
91
.github/wiki/guides/advanced.md
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Advanced Usage
|
||||
|
||||
## Custom calendar engines
|
||||
|
||||
Any engine registered in hijri-core can be wrapped in a Temporal calendar:
|
||||
|
||||
```typescript
|
||||
import { HijriCalendar } from 'temporal-hijri';
|
||||
import { registerCalendar, getCalendar } from 'hijri-core';
|
||||
import type { CalendarEngine } from 'hijri-core';
|
||||
|
||||
const myEngine: CalendarEngine = {
|
||||
id: 'local-sighting',
|
||||
toHijri(date) { /* ... */ return { hy, hm, hd }; },
|
||||
toGregorian(hy, hm, hd) { /* ... */ return new Date(...); },
|
||||
isValid(hy, hm, hd) { /* ... */ return true; },
|
||||
daysInMonth(hy, hm) { /* ... */ return 29; },
|
||||
};
|
||||
|
||||
registerCalendar('local-sighting', myEngine);
|
||||
const cal = new HijriCalendar(getCalendar('local-sighting'));
|
||||
// cal.id === 'hijri-local-sighting'
|
||||
```
|
||||
|
||||
## DateUntil with different largestUnit values
|
||||
|
||||
`dateUntil` respects the `largestUnit` option:
|
||||
|
||||
```typescript
|
||||
import { Temporal } from '@js-temporal/polyfill';
|
||||
import { uaqCalendar } from 'temporal-hijri';
|
||||
|
||||
const start = Temporal.PlainDate.from('2023-01-01');
|
||||
const end = Temporal.PlainDate.from('2023-12-31');
|
||||
|
||||
const inYears = uaqCalendar.dateUntil(start, end, { largestUnit: 'years' });
|
||||
const inMonths = uaqCalendar.dateUntil(start, end, { largestUnit: 'months' });
|
||||
const inDays = uaqCalendar.dateUntil(start, end, { largestUnit: 'days' });
|
||||
|
||||
console.log(inYears.years, inYears.months, inYears.days);
|
||||
console.log(inMonths.months, inMonths.days);
|
||||
console.log(inDays.days);
|
||||
```
|
||||
|
||||
Note: the result measures in Hijri units. One Hijri year is 354 or 355 days, so `inYears.days` may differ from what you would expect in Gregorian.
|
||||
|
||||
## PlainYearMonth and PlainMonthDay
|
||||
|
||||
```typescript
|
||||
import { Temporal } from '@js-temporal/polyfill';
|
||||
import { uaqCalendar } from 'temporal-hijri';
|
||||
|
||||
// Year-month in Hijri
|
||||
const ym = uaqCalendar.yearMonthFromFields({ year: 1444, month: 9 });
|
||||
console.log(ym.toString()); // ISO year-month of 1 Ramadan 1444
|
||||
|
||||
// Month-day in Hijri
|
||||
const md = uaqCalendar.monthDayFromFields({ month: 9, day: 1 });
|
||||
console.log(md.toString()); // ISO month-day of Ramadan 1st
|
||||
```
|
||||
|
||||
## Out-of-range behavior
|
||||
|
||||
UAQ covers 1318-1500 AH (1900-2076 CE). Requesting dates outside that range throws `RangeError`:
|
||||
|
||||
```typescript
|
||||
const earlyDate = Temporal.PlainDate.from('1800-01-01');
|
||||
try {
|
||||
uaqCalendar.year(earlyDate); // throws RangeError
|
||||
} catch (e) {
|
||||
if (e instanceof RangeError) {
|
||||
// Use FCNA for unbounded coverage
|
||||
import { fcnaCalendar } from 'temporal-hijri';
|
||||
console.log(fcnaCalendar.year(earlyDate));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Using with native Temporal
|
||||
|
||||
When native `Temporal` is available (future Node.js or browsers), you can use it directly without the polyfill:
|
||||
|
||||
```typescript
|
||||
// No import from @js-temporal/polyfill
|
||||
import { uaqCalendar } from 'temporal-hijri';
|
||||
|
||||
const isoDate = Temporal.PlainDate.from('2023-03-23');
|
||||
console.log(uaqCalendar.year(isoDate)); // 1444
|
||||
```
|
||||
|
||||
The `uaqCalendar` and `fcnaCalendar` objects implement the `Temporal.CalendarProtocol` interface and work with any spec-conforming implementation.
|
||||
98
.github/wiki/guides/quickstart.md
vendored
Normal file
98
.github/wiki/guides/quickstart.md
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
# Quick Start
|
||||
|
||||
This guide covers the most common use cases in temporal-hijri. All examples use `uaqCalendar` (Umm al-Qura). For FCNA/ISNA output, substitute `fcnaCalendar`.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pnpm add temporal-hijri hijri-core @js-temporal/polyfill
|
||||
```
|
||||
|
||||
`hijri-core` is required. `@js-temporal/polyfill` is required in environments without native `Temporal` support. In environments with native Temporal (Node 22+ with the flag, or future standard support), omit the polyfill.
|
||||
|
||||
## Import
|
||||
|
||||
```typescript
|
||||
import { Temporal } from '@js-temporal/polyfill'; // or use native Temporal
|
||||
import { uaqCalendar } from 'temporal-hijri';
|
||||
```
|
||||
|
||||
## Convert an ISO date to Hijri
|
||||
|
||||
```typescript
|
||||
const isoDate = Temporal.PlainDate.from('2023-03-23');
|
||||
|
||||
console.log(uaqCalendar.year(isoDate)); // 1444
|
||||
console.log(uaqCalendar.month(isoDate)); // 9
|
||||
console.log(uaqCalendar.day(isoDate)); // 1
|
||||
console.log(uaqCalendar.monthCode(isoDate)); // 'M09'
|
||||
```
|
||||
|
||||
## Convert Hijri coordinates to ISO
|
||||
|
||||
```typescript
|
||||
const ramadan = uaqCalendar.dateFromFields({ year: 1444, month: 9, day: 1 });
|
||||
console.log(ramadan.toString()); // '2023-03-23'
|
||||
```
|
||||
|
||||
## Date arithmetic in Hijri space
|
||||
|
||||
```typescript
|
||||
const { Duration } = Temporal;
|
||||
|
||||
const isoDate = Temporal.PlainDate.from('2023-03-23');
|
||||
|
||||
// Add one Hijri month
|
||||
const nextMonth = uaqCalendar.dateAdd(isoDate, new Duration(0, 1));
|
||||
console.log(uaqCalendar.month(nextMonth)); // 10 (Shawwal)
|
||||
console.log(nextMonth.toString()); // '2023-04-21'
|
||||
|
||||
// Get the difference between two dates
|
||||
const earlier = Temporal.PlainDate.from('2023-01-01');
|
||||
const later = Temporal.PlainDate.from('2023-03-23');
|
||||
const diff = uaqCalendar.dateUntil(earlier, later, { largestUnit: 'months' });
|
||||
console.log(diff.months); // 2 (in Hijri months)
|
||||
```
|
||||
|
||||
## Use the FCNA calendar
|
||||
|
||||
```typescript
|
||||
import { fcnaCalendar } from 'temporal-hijri';
|
||||
|
||||
const isoDate = Temporal.PlainDate.from('2023-03-23');
|
||||
console.log(fcnaCalendar.year(isoDate)); // 1444
|
||||
console.log(fcnaCalendar.month(isoDate)); // 9 or may differ by 1 near month start
|
||||
```
|
||||
|
||||
## Singletons vs classes
|
||||
|
||||
The package exports convenience singletons for the common case:
|
||||
|
||||
```typescript
|
||||
import { uaqCalendar, fcnaCalendar } from 'temporal-hijri';
|
||||
```
|
||||
|
||||
If you need to construct a calendar from a custom hijri-core engine:
|
||||
|
||||
```typescript
|
||||
import { HijriCalendar } from 'temporal-hijri';
|
||||
import { registerCalendar, getCalendar } from 'hijri-core';
|
||||
|
||||
registerCalendar('my-engine', myEngine);
|
||||
const cal = new HijriCalendar(getCalendar('my-engine'));
|
||||
```
|
||||
|
||||
## CommonJS
|
||||
|
||||
```js
|
||||
const { Temporal } = require('@js-temporal/polyfill');
|
||||
const { uaqCalendar } = require('temporal-hijri');
|
||||
|
||||
const isoDate = Temporal.PlainDate.from('2023-03-23');
|
||||
console.log(uaqCalendar.year(isoDate)); // 1444
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- [API Reference](API-Reference) for all calendar protocol methods
|
||||
- [Architecture](Architecture) for how the Temporal Calendar Protocol is implemented
|
||||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
|
|
@ -15,11 +15,12 @@ jobs:
|
|||
node: [20, 22, 24]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
cache: pnpm
|
||||
- name: Enable corepack
|
||||
run: corepack enable
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm run build
|
||||
- run: node --test test.mjs
|
||||
|
|
@ -30,11 +31,12 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
cache: pnpm
|
||||
- name: Enable corepack
|
||||
run: corepack enable
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm run lint
|
||||
- run: pnpm run format:check
|
||||
|
|
@ -44,11 +46,12 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
cache: pnpm
|
||||
- name: Enable corepack
|
||||
run: corepack enable
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm run typecheck
|
||||
|
||||
|
|
@ -57,11 +60,12 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
cache: pnpm
|
||||
- name: Enable corepack
|
||||
run: corepack enable
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm run build
|
||||
- name: Verify pack contents
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
# temporal-hijri
|
||||
|
||||
Temporal Calendar Protocol implementation for the Hijri calendar. Works with the TC39 Temporal proposal and `@js-temporal/polyfill`.
|
||||
Temporal Calendar Protocol implementation for the Hijri calendar. Works with the TC39 Temporal proposal (Stage 3) and `@js-temporal/polyfill`.
|
||||
|
||||
Provides `UaqCalendar` (Umm al-Qura) and `FcnaCalendar` (FCNA/ISNA) as plug-in calendars for `Temporal.PlainDate` and related types. The underlying conversion logic comes from [hijri-core](https://github.com/acamarata/hijri-core), a zero-dependency Hijri engine with table-driven UAQ data and astronomical FCNA calculations.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue