# hijri-utils

A lightweight, zero-dependency JavaScript utility library for Hijri (Islamic calendar) date conversions and operations.

- Convert between Gregorian and Hijri dates
- Get the current Hijri date
- Format Hijri dates as readable strings (English & Arabic)
- Compare Hijri dates
- Check leap years and month lengths
- Works fully offline — uses the tabular/arithmetic algorithm (no API calls)
- Supports both CommonJS (`require`) and ESM (`import`)

## Installation

```bash
npm install hijri-utils
```

## Quick Start

```js
// ESM
import { toHijri, formatHijri } from 'hijri-utils';

// CommonJS
const { toHijri, formatHijri } = require('hijri-utils');

const hijri = toHijri(new Date());
console.log(formatHijri(hijri)); // "14 Shawwal 1447"
```

## API Reference

### `toHijri(date)` / `toHijri(year, month, day)`

Convert a Gregorian date to a Hijri date.

**Parameters:**

| Param | Type | Description |
|-------|------|-------------|
| `date` | `Date` | A JavaScript Date object |
| `year` | `number` | Gregorian year (alternative form) |
| `month` | `number` | Gregorian month, 1-12 (alternative form) |
| `day` | `number` | Gregorian day (alternative form) |

**Returns:** `{ year: number, month: number, day: number }`

```js
toHijri(new Date(2025, 0, 1));    // { year: 1446, month: 7, day: 1 }
toHijri(2025, 1, 1);              // { year: 1446, month: 7, day: 1 }
```

---

### `toGregorian(year, month, day)`

Convert a Hijri date to a Gregorian `Date` object.

**Parameters:**

| Param | Type | Description |
|-------|------|-------------|
| `year` | `number` | Hijri year |
| `month` | `number` | Hijri month (1-12) |
| `day` | `number` | Hijri day |

**Returns:** `Date`

```js
toGregorian(1446, 7, 1);
// Date: 2025-01-01T00:00:00.000
```

---

### `getCurrentHijri()`

Get today's Hijri date.

**Returns:** `{ year: number, month: number, day: number }`

```js
getCurrentHijri();
// { year: 1447, month: 10, day: 14 }  (example)
```

---

### `formatHijri(hijriDate, options?)`

Format a Hijri date as a human-readable string.

**Parameters:**

| Param | Type | Description |
|-------|------|-------------|
| `hijriDate` | `{ year, month, day }` | A Hijri date object |
| `options.locale` | `'en'` \| `'ar'` | Language for month name (default: `'en'`) |

**Returns:** `string`

```js
formatHijri({ year: 1446, month: 9, day: 15 });
// "15 Ramadan 1446"

formatHijri({ year: 1446, month: 9, day: 15 }, { locale: 'ar' });
// "15 رمضان 1446"
```

---

### `compareHijri(a, b)`

Compare two Hijri dates. Works as an `Array.sort` comparator.

**Parameters:**

| Param | Type | Description |
|-------|------|-------------|
| `a` | `{ year, month, day }` | First Hijri date |
| `b` | `{ year, month, day }` | Second Hijri date |

**Returns:** `-1` if a < b, `0` if equal, `1` if a > b

```js
const a = { year: 1445, month: 12, day: 10 };
const b = { year: 1446, month: 1, day: 1 };

compareHijri(a, b); // -1 (a is before b)

// Sort an array of Hijri dates
const dates = [b, a];
dates.sort(compareHijri);
// [a, b]
```

---

### `isHijriLeapYear(year)`

Check if a Hijri year is a leap year in the 30-year tabular cycle.

Leap years are years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29 within each cycle.

**Parameters:**

| Param | Type | Description |
|-------|------|-------------|
| `year` | `number` | Hijri year |

**Returns:** `boolean`

```js
isHijriLeapYear(1436); // true
isHijriLeapYear(1446); // false
```

---

### `hijriMonthDays(year, month)`

Get the number of days in a given Hijri month.

**Parameters:**

| Param | Type | Description |
|-------|------|-------------|
| `year` | `number` | Hijri year |
| `month` | `number` | Hijri month (1-12) |

**Returns:** `number` (29 or 30)

```js
hijriMonthDays(1446, 1);   // 30 (Muharram — odd month)
hijriMonthDays(1446, 2);   // 29 (Safar — even month)
hijriMonthDays(1436, 12);  // 30 (Dhul Hijjah in a leap year)
```

---

### `HIJRI_MONTHS_EN` / `HIJRI_MONTHS_AR`

Arrays of the 12 Hijri month names in English and Arabic.

```js
HIJRI_MONTHS_EN[0];  // "Muharram"
HIJRI_MONTHS_EN[8];  // "Ramadan"
HIJRI_MONTHS_AR[8];  // "رمضان"
```

## Algorithm

This library uses the **tabular Islamic calendar** (arithmetic/civil algorithm) for conversions. It is based on a fixed 30-year cycle and does not depend on moon sighting or astronomical observation. Results may differ by ±1–2 days from the observational Hijri calendar used in some countries.

All conversions go through an intermediate Julian Day Number (JDN):

```
Gregorian → JDN → Hijri
Hijri → JDN → Gregorian
```

## Requirements

- Node.js >= 18.0.0
- Zero runtime dependencies

## Running Tests

```bash
npm test
```

Tests use Node's built-in test runner (`node:test`).

## License

[MIT](LICENSE)
