mirror of
https://github.com/acamarata/dayjs-hijri-plus.git
synced 2026-07-02 11:40:40 +00:00
chore: E6 polish wiki content + ADR-015 CI updates (P1)
This commit is contained in:
parent
4c7ab92727
commit
ff3b681238
12 changed files with 533 additions and 22 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.
|
||||||
49
.github/wiki/CONTRIBUTING.md
vendored
Normal file
49
.github/wiki/CONTRIBUTING.md
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Contributing to dayjs-hijri-plus
|
||||||
|
|
||||||
|
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/dayjs-hijri-plus.git
|
||||||
|
cd dayjs-hijri-plus
|
||||||
|
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/dayjs-hijri-plus/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.
|
||||||
|
- Functional, stateless exports. No classes. No side effects.
|
||||||
|
- Each function: 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 function 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.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
dayjs-hijri-plus is a pure calendar computation library. It accepts plain JavaScript `Date` objects and Day.js instances as input and returns plain objects or strings. 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: dayjs-hijri-plus".
|
||||||
|
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 @@
|
||||||
|
[dayjs-hijri-plus](https://github.com/acamarata/dayjs-hijri-plus) · MIT License · [npm](https://www.npmjs.com/package/dayjs-hijri-plus) · [Issues](https://github.com/acamarata/dayjs-hijri-plus/issues)
|
||||||
19
.github/wiki/_Sidebar.md
vendored
Normal file
19
.github/wiki/_Sidebar.md
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
**[Home](Home)**
|
||||||
|
|
||||||
|
**Guides**
|
||||||
|
- [Quick Start](guides/quickstart)
|
||||||
|
- [Advanced Usage](guides/advanced)
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
- [Basic Usage](examples/basic-usage)
|
||||||
|
- [Formatting](examples/formatting)
|
||||||
|
|
||||||
|
**Reference**
|
||||||
|
- [API Reference](API-Reference)
|
||||||
|
- [Architecture](Architecture)
|
||||||
|
- [Benchmarks](benchmarks/index)
|
||||||
|
|
||||||
|
**Community**
|
||||||
|
- [Contributing](CONTRIBUTING)
|
||||||
|
- [Code of Conduct](CODE_OF_CONDUCT)
|
||||||
|
- [Security](SECURITY)
|
||||||
51
.github/wiki/benchmarks/index.md
vendored
Normal file
51
.github/wiki/benchmarks/index.md
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# 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 |
|
||||||
|
|---|---|---|
|
||||||
|
| `d.toHijri()` | ~0.5 µs/call | ~14 µs/call |
|
||||||
|
| `d.iYear()` | ~0.5 µs/call | ~14 µs/call |
|
||||||
|
| `dayjs.fromHijri()` | ~0.6 µs/call | ~15 µs/call |
|
||||||
|
| `d.format('iD iMMMM iYYYY')` | ~1.2 µs/call | ~15 µs/call |
|
||||||
|
|
||||||
|
UAQ uses a precomputed lookup table (O(1) lookup). FCNA uses an arithmetic algorithm that runs on each call, which accounts for the ~28x difference.
|
||||||
|
|
||||||
|
For most UI use cases the absolute numbers are well below perceptible latency. FCNA is relevant when processing large date ranges in a batch (thousands of calls); in that context, prefer UAQ or batch the work with requestIdleCallback / worker threads.
|
||||||
|
|
||||||
|
## Bundle size
|
||||||
|
|
||||||
|
The plugin adds minimal weight on top of Day.js.
|
||||||
|
|
||||||
|
| Module | Min+gz |
|
||||||
|
|---|---|
|
||||||
|
| dayjs-hijri-plus (wrapper only) | ~1.5 KB |
|
||||||
|
| hijri-core/uaq (peer dep, UAQ engine) | ~5.3 KB |
|
||||||
|
| hijri-core/fcna (peer dep, FCNA engine) | ~3.1 KB |
|
||||||
|
| dayjs (peer dep, separate) | ~6.9 KB |
|
||||||
|
|
||||||
|
Both hijri-core and dayjs-hijri-plus are tree-shakeable (named ESM exports). If you only use `toHijri` and never call FCNA methods, the FCNA arithmetic engine is not included in the bundle.
|
||||||
|
|
||||||
|
## Reproducing the benchmarks
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import hijri from 'dayjs-hijri-plus';
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
|
||||||
|
const dates = Array.from({ length: 1000 }, (_, i) =>
|
||||||
|
dayjs('1900-01-01').add(i * 26, 'day')
|
||||||
|
);
|
||||||
|
|
||||||
|
const start = performance.now();
|
||||||
|
for (const d of dates) {
|
||||||
|
d.toHijri();
|
||||||
|
}
|
||||||
|
const elapsed = performance.now() - start;
|
||||||
|
console.log(`${(elapsed / dates.length * 1000).toFixed(1)} µs/call`);
|
||||||
|
```
|
||||||
|
|
||||||
|
Run with `node --version` >= 20. Results vary by machine and Node version.
|
||||||
84
.github/wiki/examples/basic-usage.md
vendored
Normal file
84
.github/wiki/examples/basic-usage.md
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
# Basic Usage Examples
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import hijri from 'dayjs-hijri-plus';
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Convert today's date to Hijri
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const today = dayjs();
|
||||||
|
const h = today.toHijri();
|
||||||
|
// { hy: 1444, hm: 9, hd: 1 } (example — actual output depends on the current date)
|
||||||
|
|
||||||
|
console.log(`${h.hd} / ${h.hm} / ${h.hy}`);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Convert a known Gregorian date
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 23 March 2023 = 1 Ramadan 1444 AH
|
||||||
|
const d = dayjs('2023-03-23');
|
||||||
|
const h = d.toHijri();
|
||||||
|
|
||||||
|
console.log(h.hy); // 1444
|
||||||
|
console.log(h.hm); // 9 (Ramadan is the 9th month)
|
||||||
|
console.log(h.hd); // 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Convert from Hijri to Gregorian
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const gregorian = dayjs.fromHijri(1444, 9, 1);
|
||||||
|
console.log(gregorian.format('YYYY-MM-DD')); // '2023-03-23'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hijri accessor methods
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const d = dayjs('2023-03-23');
|
||||||
|
|
||||||
|
console.log(d.iYear()); // 1444
|
||||||
|
console.log(d.iMonth()); // 9
|
||||||
|
console.log(d.iDate()); // 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Format with Hijri tokens
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const d = dayjs('2023-03-23');
|
||||||
|
|
||||||
|
d.format('iD iMMMM iYYYY'); // '1 Ramadan 1444'
|
||||||
|
d.format('iDD/iMM/iYYYY'); // '01/09/1444'
|
||||||
|
d.format('YYYY-MM-DD'); // '2023-03-23' (Gregorian tokens still work)
|
||||||
|
d.format('YYYY (iYYYY/iM/iD)'); // '2023 (1444/9/1)'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use FCNA calendar
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const d = dayjs('2023-03-23');
|
||||||
|
const fcna = d.toHijri({ calendar: 'fcna' });
|
||||||
|
|
||||||
|
console.log(fcna.hy); // 1444
|
||||||
|
console.log(fcna.hm); // 9
|
||||||
|
console.log(fcna.hd); // 1
|
||||||
|
// Near month boundaries, UAQ and FCNA may differ by one day
|
||||||
|
```
|
||||||
|
|
||||||
|
## CJS usage
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const dayjs = require('dayjs');
|
||||||
|
const hijri = require('dayjs-hijri-plus');
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
|
||||||
|
const d = dayjs('2023-03-23');
|
||||||
|
console.log(d.iYear()); // 1444
|
||||||
|
```
|
||||||
97
.github/wiki/examples/formatting.md
vendored
Normal file
97
.github/wiki/examples/formatting.md
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
# Formatting Examples
|
||||||
|
|
||||||
|
## Hijri format token reference
|
||||||
|
|
||||||
|
| Token | Output | Example |
|
||||||
|
|---|---|---|
|
||||||
|
| `iYYYY` | Full Hijri year | `1444` |
|
||||||
|
| `iYY` | 2-digit Hijri year | `44` |
|
||||||
|
| `iMMMM` | Full month name | `Ramadan` |
|
||||||
|
| `iMMM` | Abbreviated month name | `Ram` |
|
||||||
|
| `iMM` | 2-digit month number | `09` |
|
||||||
|
| `iM` | Month number | `9` |
|
||||||
|
| `iDD` | 2-digit day | `01` |
|
||||||
|
| `iD` | Day number | `1` |
|
||||||
|
|
||||||
|
Tokens not prefixed with `i` are passed through to Day.js as Gregorian tokens.
|
||||||
|
|
||||||
|
## Common format patterns
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import hijri from 'dayjs-hijri-plus';
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
|
||||||
|
const d = dayjs('2023-03-23');
|
||||||
|
|
||||||
|
// Day Month Year (long)
|
||||||
|
d.format('iD iMMMM iYYYY');
|
||||||
|
// '1 Ramadan 1444'
|
||||||
|
|
||||||
|
// Numeric date
|
||||||
|
d.format('iDD/iMM/iYYYY');
|
||||||
|
// '01/09/1444'
|
||||||
|
|
||||||
|
// Short month name
|
||||||
|
d.format('iD iMMM iYYYY');
|
||||||
|
// '1 Ram 1444'
|
||||||
|
|
||||||
|
// Combined Gregorian and Hijri
|
||||||
|
d.format('YYYY-MM-DD (iD iMMMM iYYYY)');
|
||||||
|
// '2023-03-23 (1 Ramadan 1444)'
|
||||||
|
|
||||||
|
// ISO-style Hijri
|
||||||
|
d.format('iYYYY-iMM-iDD');
|
||||||
|
// '1444-09-01'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hijri month names
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const months = [
|
||||||
|
'Muharram', 'Safar', "Rabi' al-Awwal", "Rabi' al-Thani",
|
||||||
|
"Jumada al-Awwal", "Jumada al-Thani", 'Rajab', "Sha'ban",
|
||||||
|
'Ramadan', 'Shawwal', "Dhu al-Qa'dah", "Dhu al-Hijjah"
|
||||||
|
];
|
||||||
|
|
||||||
|
// iMMMM returns the standard transliteration for each month
|
||||||
|
for (let m = 1; m <= 12; m++) {
|
||||||
|
const d = dayjs.fromHijri(1444, m, 1);
|
||||||
|
console.log(d.format('iM iMMMM'));
|
||||||
|
}
|
||||||
|
// 1 Muharram
|
||||||
|
// 2 Safar
|
||||||
|
// ...
|
||||||
|
// 9 Ramadan
|
||||||
|
// ...
|
||||||
|
// 12 Dhu al-Hijjah
|
||||||
|
```
|
||||||
|
|
||||||
|
## React component example
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import hijri from 'dayjs-hijri-plus';
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
|
||||||
|
interface HijriDateProps {
|
||||||
|
date: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
function HijriDate({ date }: HijriDateProps) {
|
||||||
|
const d = dayjs(date);
|
||||||
|
const gregorian = d.format('YYYY-MM-DD');
|
||||||
|
const hijriFormatted = d.format('iD iMMMM iYYYY');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<time dateTime={gregorian}>
|
||||||
|
{hijriFormatted}
|
||||||
|
</time>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage: <HijriDate date={new Date('2023-03-23')} />
|
||||||
|
// Renders: <time datetime="2023-03-23">1 Ramadan 1444</time>
|
||||||
|
```
|
||||||
76
.github/wiki/guides/advanced.md
vendored
Normal file
76
.github/wiki/guides/advanced.md
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Advanced Usage
|
||||||
|
|
||||||
|
## Switching calendars per call
|
||||||
|
|
||||||
|
Each method accepts an optional options argument. You can mix UAQ and FCNA in the same codebase:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import hijri from 'dayjs-hijri-plus';
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
|
||||||
|
const d = dayjs('2023-03-23');
|
||||||
|
|
||||||
|
const uaqYear = d.iYear(); // UAQ (default)
|
||||||
|
const fcnaYear = d.iYear({ calendar: 'fcna' }); // FCNA
|
||||||
|
```
|
||||||
|
|
||||||
|
Near month boundaries, UAQ and FCNA may differ by one day. The calendar argument is per-call, not session-wide.
|
||||||
|
|
||||||
|
## Null safety
|
||||||
|
|
||||||
|
`d.toHijri()` (if the package exposes it) returns `null` for dates outside UAQ range (approximately 1900-2076 CE). Guard before using:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const hijri = d.toHijri();
|
||||||
|
if (hijri !== null) {
|
||||||
|
console.log(hijri.hy, hijri.hm, hijri.hd);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Combining with Day.js plugins
|
||||||
|
|
||||||
|
dayjs-hijri-plus works alongside other Day.js plugins. The order of `extend()` calls matters when two plugins patch the same method:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import utc from 'dayjs/plugin/utc';
|
||||||
|
import timezone from 'dayjs/plugin/timezone';
|
||||||
|
import hijri from 'dayjs-hijri-plus';
|
||||||
|
|
||||||
|
dayjs.extend(utc);
|
||||||
|
dayjs.extend(timezone);
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
|
||||||
|
// UTC-aware conversion
|
||||||
|
const d = dayjs.utc('2023-03-23');
|
||||||
|
console.log(d.iYear()); // 1444
|
||||||
|
```
|
||||||
|
|
||||||
|
## Formatting alongside Gregorian tokens
|
||||||
|
|
||||||
|
Hijri tokens (`iYYYY`, `iMM`, `iDD`, `iMMMM`, etc.) coexist with Day.js Gregorian tokens. Use them in the same format string:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
d.format('YYYY-MM-DD (iD iMMMM iYYYY)');
|
||||||
|
// '2023-03-23 (1 Ramadan 1444)'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tree-shaking
|
||||||
|
|
||||||
|
The package ships both ESM and CJS builds. In ESM bundlers (Vite, esbuild, Rollup), unused code is eliminated. The plugin itself is ~2 KB min+gz on top of Day.js.
|
||||||
|
|
||||||
|
## TypeScript augmentation
|
||||||
|
|
||||||
|
The plugin augments the Day.js type definitions automatically. You do not need to import any separate types file:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import hijri from 'dayjs-hijri-plus';
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
|
||||||
|
const d = dayjs('2023-03-23');
|
||||||
|
const year: number = d.iYear(); // fully typed
|
||||||
|
```
|
||||||
82
.github/wiki/guides/quickstart.md
vendored
Normal file
82
.github/wiki/guides/quickstart.md
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
# Quick Start
|
||||||
|
|
||||||
|
This guide covers the most common use cases in dayjs-hijri-plus. All examples use the default Umm al-Qura (UAQ) calendar.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm add dayjs dayjs-hijri-plus hijri-core
|
||||||
|
```
|
||||||
|
|
||||||
|
`dayjs` and `hijri-core` are required peer dependencies. Install both alongside this package.
|
||||||
|
|
||||||
|
## Load the plugin
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import hijri from 'dayjs-hijri-plus';
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
```
|
||||||
|
|
||||||
|
After extending, all `dayjs()` instances gain Hijri methods.
|
||||||
|
|
||||||
|
## Convert a Gregorian date to Hijri
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import hijri from 'dayjs-hijri-plus';
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
|
||||||
|
const d = dayjs('2023-03-23'); // 1 Ramadan 1444
|
||||||
|
console.log(d.iYear()); // 1444
|
||||||
|
console.log(d.iMonth()); // 9
|
||||||
|
console.log(d.iDate()); // 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Format with Hijri tokens
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
d.format('iYYYY/iMM/iDD'); // '1444/09/01'
|
||||||
|
d.format('iD iMMMM iYYYY'); // '1 Ramadan 1444'
|
||||||
|
```
|
||||||
|
|
||||||
|
Hijri format tokens are prefixed with `i` to avoid conflicts with Day.js Gregorian tokens.
|
||||||
|
|
||||||
|
## Convert a Hijri date to a Day.js object
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import hijri from 'dayjs-hijri-plus';
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
|
||||||
|
const d = dayjs.fromHijri(1444, 9, 1);
|
||||||
|
console.log(d.format('YYYY-MM-DD')); // '2023-03-23'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use the FCNA calendar
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const d = dayjs('2023-03-23');
|
||||||
|
console.log(d.iYear({ calendar: 'fcna' })); // 1444
|
||||||
|
console.log(d.iMonth({ calendar: 'fcna' })); // 9 or differs by a day near month start
|
||||||
|
```
|
||||||
|
|
||||||
|
## CommonJS
|
||||||
|
|
||||||
|
```js
|
||||||
|
const dayjs = require('dayjs');
|
||||||
|
const hijri = require('dayjs-hijri-plus');
|
||||||
|
|
||||||
|
dayjs.extend(hijri);
|
||||||
|
|
||||||
|
const d = dayjs('2023-03-23');
|
||||||
|
console.log(d.iYear(), d.iMonth(), d.iDate()); // 1444 9 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next steps
|
||||||
|
|
||||||
|
- [API Reference](API-Reference) for the full method list
|
||||||
|
- [Architecture](Architecture) for how the plugin integrates with Day.js
|
||||||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
|
|
@ -15,11 +15,12 @@ jobs:
|
||||||
node: [20, 22, 24]
|
node: [20, 22, 24]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
- name: Enable corepack
|
||||||
|
run: corepack enable
|
||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
- run: pnpm run build
|
- run: pnpm run build
|
||||||
- run: node --test test.mjs
|
- run: node --test test.mjs
|
||||||
|
|
@ -30,11 +31,12 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
- name: Enable corepack
|
||||||
|
run: corepack enable
|
||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
- run: pnpm run lint
|
- run: pnpm run lint
|
||||||
- run: pnpm run format:check
|
- run: pnpm run format:check
|
||||||
|
|
@ -44,11 +46,12 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
- name: Enable corepack
|
||||||
|
run: corepack enable
|
||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
- run: pnpm run typecheck
|
- run: pnpm run typecheck
|
||||||
|
|
||||||
|
|
@ -57,11 +60,12 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
- name: Enable corepack
|
||||||
|
run: corepack enable
|
||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
- run: pnpm run build
|
- run: pnpm run build
|
||||||
- name: Verify pack contents
|
- name: Verify pack contents
|
||||||
|
|
|
||||||
25
.github/workflows/wiki-sync.yml
vendored
25
.github/workflows/wiki-sync.yml
vendored
|
|
@ -11,26 +11,15 @@ permissions:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
sync:
|
sync:
|
||||||
name: Sync .github/wiki/ to GitHub Wiki
|
name: Sync wiki to GitHub Wiki
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Push wiki pages
|
- name: Sync .github/wiki/ to GitHub Wiki
|
||||||
uses: actions/checkout@v4
|
uses: Andrew-Chen-Wang/github-wiki-action@v4
|
||||||
with:
|
with:
|
||||||
repository: ${{ github.repository }}.wiki
|
path: .github/wiki/
|
||||||
path: wiki-repo
|
env:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
GITHUB_ACTOR: ${{ github.actor }}
|
||||||
- name: Copy wiki files
|
|
||||||
run: cp .github/wiki/*.md wiki-repo/
|
|
||||||
|
|
||||||
- name: Commit and push
|
|
||||||
working-directory: wiki-repo
|
|
||||||
run: |
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git add -A
|
|
||||||
git diff --cached --quiet || git commit -m "Sync wiki from .github/wiki/ [skip ci]"
|
|
||||||
git push
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue