initial commit

This commit is contained in:
Ali Camarata 2023-12-01 22:10:54 +07:00
commit 612aa63a78
16 changed files with 4802 additions and 0 deletions

32
.gitignore vendored Normal file
View file

@ -0,0 +1,32 @@
# Dependency directories
node_modules/
# Next.js build output
.next/
out/
# Build output of TypeScript
dist/
# Environment files
.env.local
.env.development.local
.env.test.local
.env.production.local
# IDE specific files
.vscode/
.idea/
*.swp
*.swo
# System Files
.DS_Store
Thumbs.db
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

74
README.md Normal file
View file

@ -0,0 +1,74 @@
# Luxon-Hijri
Luxon-Hijri is a comprehensive Hijri date conversion and formatting library based on the Umm al-Qura calendar system, leveraging the power of Luxon for robust date manipulations. Please note this is a first draft but should work well. It was created quickly for a need I had within my own app but should be ready for contributions and more. I will add localization and more if requested or if someone contributes.
## Features
- Convert between Hijri and Gregorian dates.
- Format Hijri dates with customizable patterns.
- Locale support for different languages.
- Efficient and optimized for performance.
- Comprehensive unit testing for reliability.
## Installation
```bash
npm install luxon-hijri
```
## Quick Start
Here's how you can quickly convert a Gregorian date to a Hijri date:
```javascript
import { toHijri } from 'luxon-hijri';
const hijriDate = toHijri(new Date());
console.log(hijriDate);
```
## Usage
### Converting Dates
Convert Gregorian dates to Hijri:
```javascript
import { toHijri } from 'luxon-hijri';
const hijriDate = toHijri(new Date(2023, 3, 14)); // April 14, 2023
console.log(hijriDate);
```
Convert Hijri dates to Gregorian:
```javascript
import { toGregorian } from 'luxon-hijri';
const gregorianDate = toGregorian(1444, 9, 1); // 1st of Ramadan, 1444 H
console.log(gregorianDate);
```
### Formatting Dates
Format Hijri dates using predefined patterns:
```javascript
import { formatHijriDate } from 'luxon-hijri';
const formattedDate = formatHijriDate({ hy: 1444, hm: 9, hd: 1 }, 'iYYYY-iMM-iDD');
console.log(formattedDate); // 1444-09-01
```
## Documentation
For detailed documentation, examples, and API reference, visit [Documentation Link].
## Contributing
We welcome contributions! Please read our [Contributing Guide](CONTRIBUTING.md) for details on how to submit pull requests, report issues, and suggest enhancements.
## License
This project is licensed under the ISC License - see the [LICENSE.md](LICENSE.md) file for details.
## Code of Conduct
Participation in this project is governed by a [Code of Conduct](CODE_OF_CONDUCT.md). We expect everyone to adhere to it to maintain a respectful and welcoming environment.

4171
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

37
package.json Normal file
View file

@ -0,0 +1,37 @@
{
"name": "luxon-hijri",
"version": "1.0.0",
"description": "A Hijri date converter based on the Umm al-Qura calendar system, using Luxon for date manipulations.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"test": "jest"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ussunnah/luxon-hijri.git"
},
"keywords": [
"hijri",
"calendar",
"converter",
"luxon",
"umm-al-qura"
],
"author": "USF",
"license": "ISC",
"devDependencies": {
"@types/luxon": "^3.3.4",
"jest": "^27.0.0",
"typescript": "^4.0.0"
},
"dependencies": {
"@umalqura/core": "^0.0.7",
"luxon": "^2.5.2"
},
"bugs": {
"url": "https://github.com/ussunnah/luxon-hijri/issues"
},
"homepage": "https://github.com/ussunnah/luxon-hijri#readme"
}

61
src/formatHijriDate.ts Normal file
View file

@ -0,0 +1,61 @@
// formatHijriDate.ts
import { DateTime } from 'luxon';
import { hmLong, hmMedium, hmShort } from './hMonths';
import { hwLong, hwShort, hwNumeric } from './hWeekdays';
/**
* Formats a Hijri date according to the given format string
* @param {Date} hijriDate - The Hijri date to format
* @param {string} format - The format string
* @returns {string} - The formatted date string
*/
export function formatHijriDate(hijriDate: { hy: number; hm: number; hd: number }, format: string): string {
// Replace each pattern in the format string with the corresponding value
return format.replace(/\biYYYY\b|\biYY\b|\biMM\b|\biM\b|\biMMM\b|\biMMMM\b|\biDD\b|\biD\b|\biE\b|\biEEE\b|\biEEEE\b|\b[HHhmsaiozZ]+\b/g, (match) => {
switch (match) {
case 'iYYYY':
return String(hijriDate.hy).padStart(4, '0');
case 'iYY':
return String(hijriDate.hy % 100).padStart(2, '0');
case 'iMM':
return String(hijriDate.hm).padStart(2, '0');
case 'iM':
return String(hijriDate.hm);
case 'iMMM':
return hmMedium[hijriDate.hm - 1];
case 'iMMMM':
return hmLong[hijriDate.hm - 1];
case 'iDD':
return String(hijriDate.hd).padStart(2, '0');
case 'iD':
return String(hijriDate.hd);
case 'iE':
return String(hwNumeric[DateTime.fromObject({ year: hijriDate.hy, month: hijriDate.hm, day: hijriDate.hd }).weekday - 1]);
case 'iEEE':
return hwShort[DateTime.fromObject({ year: hijriDate.hy, month: hijriDate.hm, day: hijriDate.hd }).weekday - 1];
case 'iEEEE':
return hwLong[DateTime.fromObject({ year: hijriDate.hy, month: hijriDate.hm, day: hijriDate.hd }).weekday - 1];
// The following patterns are the same for both Gregorian and Hijri
case 'HH':
case 'H':
case 'hh':
case 'h':
case 'mm':
case 'm':
case 'ss':
case 's':
case 'a':
case 'iooo':
case 'ioooo':
case 'z':
case 'zz':
case 'Z':
// Use Luxon's DateTime formatting for these patterns
const gregorianDate = DateTime.fromObject({ year: hijriDate.hy, month: hijriDate.hm, day: hijriDate.hd });
return gregorianDate.toFormat(match);
default:
return match;
}
});
}

48
src/formatPatterns.ts Normal file
View file

@ -0,0 +1,48 @@
// formatPatterns.ts
// Define a mapping of Hijri format tokens to their meanings
export const formatPatterns = {
// Hijri Year
iYYYY: 'Hijri year (4 digits)',
iYY: 'Hijri year (2 digits)',
// Hijri Month
iMM: 'Hijri month (2 digits, zero-padded)',
iM: 'Hijri month (1 or 2 digits without zero-padding)',
iMMM: 'Hijri month (abbreviated name)',
iMMMM: 'Hijri month (full name)',
// Hijri Day
iDD: 'Hijri day of the month (2 digits, zero-padded)',
iD: 'Hijri day of the month (1 or 2 digits without zero-padding)',
// Hijri Weekday
iE: 'Hijri weekday (1 digit)',
iEEE: 'Hijri weekday (abbreviated name)',
iEEEE: 'Hijri weekday (full name)',
// Hour, Minute, Second
// These can remain the same as in Gregorian as they dont change in Hijri
HH: 'Hour (2 digits, zero-padded, 24-hour clock)',
H: 'Hour (1 or 2 digits without zero-padding, 24-hour clock)',
hh: 'Hour (2 digits, zero-padded, 12-hour clock)',
h: 'Hour (1 or 2 digits without zero-padding, 12-hour clock)',
mm: 'Minute (2 digits, zero-padded)',
m: 'Minute (1 or 2 digits without zero-padding)',
ss: 'Second (2 digits, zero-padded)',
s: 'Second (1 or 2 digits without zero-padding)',
// AM/PM
a: 'AM/PM marker',
// Other
iooo: 'Hijri era (abbreviated)',
ioooo: 'Hijri era (full)',
// Timezone
z: 'Timezone (abbreviated)',
zz: 'Timezone (full)',
Z: 'Timezone offset from UTC',
};
// Export the patterns for use in the rest of the package
export default formatPatterns;

195
src/hDates.ts Normal file
View file

@ -0,0 +1,195 @@
// hDates.ts
// Hijri Dates Reference Table
export interface hDates {
hy: number; // Hijri Year
dpm: number; // Days Per Month
gy: number; // Gregorian Year
gm: number; // Gregorian Month
gd: number; // Gregorian Day
}
export const hDatesTable: hDates[] = [
{ hy: 1318, dpm: 0x02EA, gy: 1900, gm: 4, gd: 30 },
{ hy: 1319, dpm: 0x06E9, gy: 1901, gm: 4, gd: 19 },
{ hy: 1320, dpm: 0x0ED2, gy: 1902, gm: 4, gd: 9 },
{ hy: 1321, dpm: 0x0EA4, gy: 1903, gm: 3, gd: 30 },
{ hy: 1322, dpm: 0x0D4A, gy: 1904, gm: 3, gd: 18 },
{ hy: 1323, dpm: 0x0A96, gy: 1905, gm: 3, gd: 7 },
{ hy: 1324, dpm: 0x0536, gy: 1906, gm: 2, gd: 24 },
{ hy: 1325, dpm: 0x0AB5, gy: 1907, gm: 2, gd: 13 },
{ hy: 1326, dpm: 0x0DAA, gy: 1908, gm: 2, gd: 3 },
{ hy: 1327, dpm: 0x0BA4, gy: 1909, gm: 1, gd: 23 },
{ hy: 1328, dpm: 0x0B49, gy: 1910, gm: 1, gd: 12 },
{ hy: 1329, dpm: 0x0A93, gy: 1911, gm: 1, gd: 1 },
{ hy: 1330, dpm: 0x052B, gy: 1911, gm: 12, gd: 21 },
{ hy: 1331, dpm: 0x0A57, gy: 1912, gm: 12, gd: 9 },
{ hy: 1332, dpm: 0x04B6, gy: 1913, gm: 11, gd: 29 },
{ hy: 1333, dpm: 0x0AB5, gy: 1914, gm: 11, gd: 18 },
{ hy: 1334, dpm: 0x05AA, gy: 1915, gm: 11, gd: 8 },
{ hy: 1335, dpm: 0x0D55, gy: 1916, gm: 10, gd: 27 },
{ hy: 1336, dpm: 0x0D2A, gy: 1917, gm: 10, gd: 17 },
{ hy: 1337, dpm: 0x0A56, gy: 1918, gm: 10, gd: 6 },
{ hy: 1338, dpm: 0x04AE, gy: 1919, gm: 9, gd: 25 },
{ hy: 1339, dpm: 0x095D, gy: 1920, gm: 9, gd: 13 },
{ hy: 1340, dpm: 0x02EC, gy: 1921, gm: 9, gd: 3 },
{ hy: 1341, dpm: 0x06D5, gy: 1922, gm: 8, gd: 23 },
{ hy: 1342, dpm: 0x06AA, gy: 1923, gm: 8, gd: 13 },
{ hy: 1343, dpm: 0x0555, gy: 1924, gm: 8, gd: 1 },
{ hy: 1344, dpm: 0x04AB, gy: 1925, gm: 7, gd: 21 },
{ hy: 1345, dpm: 0x095B, gy: 1926, gm: 7, gd: 10 },
{ hy: 1346, dpm: 0x02BA, gy: 1927, gm: 6, gd: 30 },
{ hy: 1347, dpm: 0x0575, gy: 1928, gm: 6, gd: 18 },
{ hy: 1348, dpm: 0x0BB2, gy: 1929, gm: 6, gd: 8 },
{ hy: 1349, dpm: 0x0764, gy: 1930, gm: 5, gd: 29 },
{ hy: 1350, dpm: 0x0749, gy: 1931, gm: 5, gd: 18 },
{ hy: 1351, dpm: 0x0655, gy: 1932, gm: 5, gd: 6 },
{ hy: 1352, dpm: 0x02AB, gy: 1933, gm: 4, gd: 25 },
{ hy: 1353, dpm: 0x055B, gy: 1934, gm: 4, gd: 14 },
{ hy: 1354, dpm: 0x0ADA, gy: 1935, gm: 4, gd: 4 },
{ hy: 1355, dpm: 0x06D4, gy: 1936, gm: 3, gd: 24 },
{ hy: 1356, dpm: 0x0EC9, gy: 1937, gm: 3, gd: 13 },
{ hy: 1357, dpm: 0x0D92, gy: 1938, gm: 3, gd: 3 },
{ hy: 1358, dpm: 0x0D25, gy: 1939, gm: 2, gd: 20 },
{ hy: 1359, dpm: 0x0A4D, gy: 1940, gm: 2, gd: 9 },
{ hy: 1360, dpm: 0x02AD, gy: 1941, gm: 1, gd: 28 },
{ hy: 1361, dpm: 0x056D, gy: 1942, gm: 1, gd: 17 },
{ hy: 1362, dpm: 0x0B6A, gy: 1943, gm: 1, gd: 7 },
{ hy: 1363, dpm: 0x0B52, gy: 1943, gm: 12, gd: 28 },
{ hy: 1364, dpm: 0x0AA5, gy: 1944, gm: 12, gd: 16 },
{ hy: 1365, dpm: 0x0A4B, gy: 1945, gm: 12, gd: 5 },
{ hy: 1366, dpm: 0x0497, gy: 1946, gm: 11, gd: 24 },
{ hy: 1367, dpm: 0x0937, gy: 1947, gm: 11, gd: 13 },
{ hy: 1368, dpm: 0x02B6, gy: 1948, gm: 11, gd: 2 },
{ hy: 1369, dpm: 0x0575, gy: 1949, gm: 10, gd: 22 },
{ hy: 1370, dpm: 0x0D6A, gy: 1950, gm: 10, gd: 12 },
{ hy: 1371, dpm: 0x0D52, gy: 1951, gm: 10, gd: 2 },
{ hy: 1372, dpm: 0x0A96, gy: 1952, gm: 9, gd: 20 },
{ hy: 1373, dpm: 0x092D, gy: 1953, gm: 9, gd: 9 },
{ hy: 1374, dpm: 0x025D, gy: 1954, gm: 8, gd: 29 },
{ hy: 1375, dpm: 0x04DD, gy: 1955, gm: 8, gd: 18 },
{ hy: 1376, dpm: 0x0ADA, gy: 1956, gm: 8, gd: 7 },
{ hy: 1377, dpm: 0x05D4, gy: 1957, gm: 7, gd: 28 },
{ hy: 1378, dpm: 0x0DA9, gy: 1958, gm: 7, gd: 17 },
{ hy: 1379, dpm: 0x0D52, gy: 1959, gm: 7, gd: 7 },
{ hy: 1380, dpm: 0x0AAA, gy: 1960, gm: 6, gd: 25 },
{ hy: 1381, dpm: 0x04D6, gy: 1961, gm: 6, gd: 14 },
{ hy: 1382, dpm: 0x09B6, gy: 1962, gm: 6, gd: 3 },
{ hy: 1383, dpm: 0x0374, gy: 1963, gm: 5, gd: 24 },
{ hy: 1384, dpm: 0x0769, gy: 1964, gm: 5, gd: 12 },
{ hy: 1385, dpm: 0x0752, gy: 1965, gm: 5, gd: 2 },
{ hy: 1386, dpm: 0x06A5, gy: 1966, gm: 4, gd: 21 },
{ hy: 1387, dpm: 0x054B, gy: 1967, gm: 4, gd: 10 },
{ hy: 1388, dpm: 0x0AAB, gy: 1968, gm: 3, gd: 29 },
{ hy: 1389, dpm: 0x055A, gy: 1969, gm: 3, gd: 19 },
{ hy: 1390, dpm: 0x0AD5, gy: 1970, gm: 3, gd: 8 },
{ hy: 1391, dpm: 0x0DD2, gy: 1971, gm: 2, gd: 26 },
{ hy: 1392, dpm: 0x0DA4, gy: 1972, gm: 2, gd: 16 },
{ hy: 1393, dpm: 0x0D49, gy: 1973, gm: 2, gd: 4 },
{ hy: 1394, dpm: 0x0A95, gy: 1974, gm: 1, gd: 24 },
{ hy: 1395, dpm: 0x052D, gy: 1975, gm: 1, gd: 13 },
{ hy: 1396, dpm: 0x0A5D, gy: 1976, gm: 1, gd: 2 },
{ hy: 1397, dpm: 0x055A, gy: 1976, gm: 12, gd: 22 },
{ hy: 1398, dpm: 0x0AD5, gy: 1977, gm: 12, gd: 11 },
{ hy: 1399, dpm: 0x06AA, gy: 1978, gm: 12, gd: 1 },
{ hy: 1400, dpm: 0x0695, gy: 1979, gm: 11, gd: 20 },
{ hy: 1401, dpm: 0x052B, gy: 1980, gm: 11, gd: 8 },
{ hy: 1402, dpm: 0x0A57, gy: 1981, gm: 10, gd: 28 },
{ hy: 1403, dpm: 0x04AE, gy: 1982, gm: 10, gd: 18 },
{ hy: 1404, dpm: 0x0976, gy: 1983, gm: 10, gd: 7 },
{ hy: 1405, dpm: 0x056C, gy: 1984, gm: 9, gd: 26 },
{ hy: 1406, dpm: 0x0B55, gy: 1985, gm: 9, gd: 15 },
{ hy: 1407, dpm: 0x0AAA, gy: 1986, gm: 9, gd: 5 },
{ hy: 1408, dpm: 0x0A55, gy: 1987, gm: 8, gd: 25 },
{ hy: 1409, dpm: 0x04AD, gy: 1988, gm: 8, gd: 13 },
{ hy: 1410, dpm: 0x095D, gy: 1989, gm: 8, gd: 2 },
{ hy: 1411, dpm: 0x02DA, gy: 1990, gm: 7, gd: 23 },
{ hy: 1412, dpm: 0x05D9, gy: 1991, gm: 7, gd: 12 },
{ hy: 1413, dpm: 0x0DB2, gy: 1992, gm: 7, gd: 1 },
{ hy: 1414, dpm: 0x0BA4, gy: 1993, gm: 6, gd: 21 },
{ hy: 1415, dpm: 0x0B4A, gy: 1994, gm: 6, gd: 10 },
{ hy: 1416, dpm: 0x0A55, gy: 1995, gm: 5, gd: 30 },
{ hy: 1417, dpm: 0x02B5, gy: 1996, gm: 5, gd: 18 },
{ hy: 1418, dpm: 0x0575, gy: 1997, gm: 5, gd: 7 },
{ hy: 1419, dpm: 0x0B6A, gy: 1998, gm: 4, gd: 27 },
{ hy: 1420, dpm: 0x0BD2, gy: 1999, gm: 4, gd: 17 },
{ hy: 1421, dpm: 0x0BC4, gy: 2000, gm: 4, gd: 6 },
{ hy: 1422, dpm: 0x0B89, gy: 2001, gm: 3, gd: 26 },
{ hy: 1423, dpm: 0x0A95, gy: 2002, gm: 3, gd: 15 },
{ hy: 1424, dpm: 0x052D, gy: 2003, gm: 3, gd: 4 },
{ hy: 1425, dpm: 0x05AD, gy: 2004, gm: 2, gd: 21 },
{ hy: 1426, dpm: 0x0B6A, gy: 2005, gm: 2, gd: 10 },
{ hy: 1427, dpm: 0x06D4, gy: 2006, gm: 1, gd: 31 },
{ hy: 1428, dpm: 0x0DC9, gy: 2007, gm: 1, gd: 20 },
{ hy: 1429, dpm: 0x0D92, gy: 2008, gm: 1, gd: 10 },
{ hy: 1430, dpm: 0x0AA6, gy: 2008, gm: 12, gd: 29 },
{ hy: 1431, dpm: 0x0956, gy: 2009, gm: 12, gd: 18 },
{ hy: 1432, dpm: 0x02AE, gy: 2010, gm: 12, gd: 7 },
{ hy: 1433, dpm: 0x056D, gy: 2011, gm: 11, gd: 26 },
{ hy: 1434, dpm: 0x036A, gy: 2012, gm: 11, gd: 15 },
{ hy: 1435, dpm: 0x0B55, gy: 2013, gm: 11, gd: 4 },
{ hy: 1436, dpm: 0x0AAA, gy: 2014, gm: 10, gd: 25 },
{ hy: 1437, dpm: 0x094D, gy: 2015, gm: 10, gd: 14 },
{ hy: 1438, dpm: 0x049D, gy: 2016, gm: 10, gd: 2 },
{ hy: 1439, dpm: 0x095D, gy: 2017, gm: 9, gd: 21 },
{ hy: 1440, dpm: 0x02BA, gy: 2018, gm: 9, gd: 11 },
{ hy: 1441, dpm: 0x05B5, gy: 2019, gm: 8, gd: 31 },
{ hy: 1442, dpm: 0x05AA, gy: 2020, gm: 8, gd: 20 },
{ hy: 1443, dpm: 0x0D55, gy: 2021, gm: 8, gd: 9 },
{ hy: 1444, dpm: 0x0A9A, gy: 2022, gm: 7, gd: 30 },
{ hy: 1445, dpm: 0x092E, gy: 2023, gm: 7, gd: 19 },
{ hy: 1446, dpm: 0x026E, gy: 2024, gm: 7, gd: 7 },
{ hy: 1447, dpm: 0x055D, gy: 2025, gm: 6, gd: 26 },
{ hy: 1448, dpm: 0x0ADA, gy: 2026, gm: 6, gd: 16 },
{ hy: 1449, dpm: 0x06D4, gy: 2027, gm: 6, gd: 6 },
{ hy: 1450, dpm: 0x06A5, gy: 2028, gm: 5, gd: 25 },
{ hy: 1451, dpm: 0x054B, gy: 2029, gm: 5, gd: 14 },
{ hy: 1452, dpm: 0x0A97, gy: 2030, gm: 5, gd: 3 },
{ hy: 1453, dpm: 0x054E, gy: 2031, gm: 4, gd: 23 },
{ hy: 1454, dpm: 0x0AAE, gy: 2032, gm: 4, gd: 11 },
{ hy: 1455, dpm: 0x05AC, gy: 2033, gm: 4, gd: 1 },
{ hy: 1456, dpm: 0x0BA9, gy: 2034, gm: 3, gd: 21 },
{ hy: 1457, dpm: 0x0D92, gy: 2035, gm: 3, gd: 11 },
{ hy: 1458, dpm: 0x0B25, gy: 2036, gm: 2, gd: 28 },
{ hy: 1459, dpm: 0x064B, gy: 2037, gm: 2, gd: 16 },
{ hy: 1460, dpm: 0x0CAB, gy: 2038, gm: 2, gd: 5 },
{ hy: 1461, dpm: 0x055A, gy: 2039, gm: 1, gd: 26 },
{ hy: 1462, dpm: 0x0B55, gy: 2040, gm: 1, gd: 15 },
{ hy: 1463, dpm: 0x06D2, gy: 2041, gm: 1, gd: 4 },
{ hy: 1464, dpm: 0x0EA5, gy: 2041, gm: 12, gd: 24 },
{ hy: 1465, dpm: 0x0E4A, gy: 2042, gm: 12, gd: 14 },
{ hy: 1466, dpm: 0x0A95, gy: 2043, gm: 12, gd: 3 },
{ hy: 1467, dpm: 0x052D, gy: 2044, gm: 11, gd: 21 },
{ hy: 1468, dpm: 0x0AAD, gy: 2045, gm: 11, gd: 10 },
{ hy: 1469, dpm: 0x036C, gy: 2046, gm: 10, gd: 31 },
{ hy: 1470, dpm: 0x0759, gy: 2047, gm: 10, gd: 20 },
{ hy: 1471, dpm: 0x06D2, gy: 2048, gm: 10, gd: 9 },
{ hy: 1472, dpm: 0x0695, gy: 2049, gm: 9, gd: 28 },
{ hy: 1473, dpm: 0x052D, gy: 2050, gm: 9, gd: 17 },
{ hy: 1474, dpm: 0x0A5B, gy: 2051, gm: 9, gd: 6 },
{ hy: 1475, dpm: 0x04BA, gy: 2052, gm: 8, gd: 26 },
{ hy: 1476, dpm: 0x09BA, gy: 2053, gm: 8, gd: 15 },
{ hy: 1477, dpm: 0x03B4, gy: 2054, gm: 8, gd: 5 },
{ hy: 1478, dpm: 0x0B69, gy: 2055, gm: 7, gd: 25 },
{ hy: 1479, dpm: 0x0B52, gy: 2056, gm: 7, gd: 14 },
{ hy: 1480, dpm: 0x0AA6, gy: 2057, gm: 7, gd: 3 },
{ hy: 1481, dpm: 0x04B6, gy: 2058, gm: 6, gd: 22 },
{ hy: 1482, dpm: 0x096D, gy: 2059, gm: 6, gd: 11 },
{ hy: 1483, dpm: 0x02EC, gy: 2060, gm: 5, gd: 31 },
{ hy: 1484, dpm: 0x06D9, gy: 2061, gm: 5, gd: 20 },
{ hy: 1485, dpm: 0x0EB2, gy: 2062, gm: 5, gd: 10 },
{ hy: 1486, dpm: 0x0D54, gy: 2063, gm: 4, gd: 30 },
{ hy: 1487, dpm: 0x0D2A, gy: 2064, gm: 4, gd: 18 },
{ hy: 1488, dpm: 0x0A56, gy: 2065, gm: 4, gd: 7 },
{ hy: 1489, dpm: 0x04AE, gy: 2066, gm: 3, gd: 27 },
{ hy: 1490, dpm: 0x096D, gy: 2067, gm: 3, gd: 16 },
{ hy: 1491, dpm: 0x0D6A, gy: 2068, gm: 3, gd: 5 },
{ hy: 1492, dpm: 0x0B54, gy: 2069, gm: 2, gd: 23 },
{ hy: 1493, dpm: 0x0B29, gy: 2070, gm: 2, gd: 12 },
{ hy: 1494, dpm: 0x0A93, gy: 2071, gm: 2, gd: 1 },
{ hy: 1495, dpm: 0x052B, gy: 2072, gm: 1, gd: 21 },
{ hy: 1496, dpm: 0x0A57, gy: 2073, gm: 1, gd: 9 },
{ hy: 1497, dpm: 0x0536, gy: 2073, gm: 12, gd: 30 },
{ hy: 1498, dpm: 0x0AB5, gy: 2074, gm: 12, gd: 19 },
{ hy: 1499, dpm: 0x06AA, gy: 2075, gm: 12, gd: 9 },
{ hy: 1500, dpm: 0x0E93, gy: 2076, gm: 11, gd: 27 },
{ hy: 1501, dpm: 0, gy: 2077, gm: 11, gd: 17 }];

46
src/hMonths.ts Normal file
View file

@ -0,0 +1,46 @@
// hMonths.ts
// Hijri Month Names
export const hmLong = [
"Muharram", // 1st month
"Safar", // 2nd month
"Rabi'l Awwal", // 3rd month
"Rabi'l Thani", // 4th month
"Jumadal Awwal", // 5th month
"Jumadal Thani", // 6th month
"Rajab", // 7th month
"Sha'ban", // 8th month
"Ramadan", // 9th month
"Shawwal", // 10th month
"Dhul Qi'dah", // 11th month
"Dhul Hijjah" // 12th month
];
export const hmMedium = [
"Muharram",
"Safar",
"Rabi1",
"Rabi2",
"Jumada1",
"Jumada2",
"Rajab",
"Shaban",
"Ramadan",
"Shawwal",
"Dhul-Qidah",
"Dhul-Hijah"
];
export const hmShort = [
"Muh",
"Saf",
"Ra1",
"Ra2",
"Ju1",
"Ju2",
"Raj",
"Shb",
"Ram",
"Shw",
"DhQ",
"DhH"
];

25
src/hWeekdays.ts Normal file
View file

@ -0,0 +1,25 @@
// hWeekdays.ts
// Full names of Hijri weekdays
export const hwLong = [
"Yawm al-Ahad", // Sunday
"Yawm al-Ithnayn", // Monday
"Yawm ath-Thulatha'", // Tuesday
"Yawm al-Arba`a'", // Wednesday
"Yawm al-Khamis", // Thursday
"Yawm al-Jum`a", // Friday
"Yawm as-Sabt" // Saturday
];
// Abbreviated names of Hijri weekdays
export const hwShort = [
"Ahad", // Sunday
"Ithn", // Monday
"Thul", // Tuesday
"Arba", // Wednesday
"Kham", // Thursday
"Jum`a", // Friday
"Sabt" // Saturday
];
// Numeric representation of Hijri weekdays (1 for Sunday, 2 for Monday, etc.)
export const hwNumeric = [1, 2, 3, 4, 5, 6, 7];

8
src/index.ts Normal file
View file

@ -0,0 +1,8 @@
// index.ts
export { formatPatterns } from './formatPatterns';
export { hDatesTable, hDates } from './hDates';
export { hmLong, hmMedium, hmShort } from './hMonths';
export { toGregorian } from './toGregorian';
export { toHijri } from './toHijri';
export { formatHijriDate } from './formatHijriDate';
export { isValidHijriDate } from './utils';

4
src/locales/ar.json Normal file
View file

@ -0,0 +1,4 @@
{
"months": ["محرم", "صفر", "..."],
"weekdays": ["الأحد", "الاثنين", "..."]
}

4
src/locales/en.json Normal file
View file

@ -0,0 +1,4 @@
{
"months": ["Muharram", "Safar", "..."],
"weekdays": ["Sunday", "Monday", "..."]
}

28
src/toGregorian.ts Normal file
View file

@ -0,0 +1,28 @@
// toGregorian.ts
import { DateTime } from 'luxon';
import { hDatesTable, hDates } from './hDates';
import { isValidHijriDate } from './utils';
export function toGregorian(hy: number, hm: number, hd: number): Date | null {
// Validate the input Hijri date
if (!isValidHijriDate(hy, hm, hd)) {
throw new Error('Invalid Hijri date');
}
const hijriYearRecord = hDatesTable.find(record => record.hy === hy);
if (hijriYearRecord) {
let totalDaysTillMonthStart = 0;
for (let i = 0; i < hm - 1; i++) {
totalDaysTillMonthStart += (hijriYearRecord.dpm >> i) & 1 ? 30 : 29;
}
const totalDays = totalDaysTillMonthStart + hd - 1;
const startDate = DateTime.local(hijriYearRecord.gy, hijriYearRecord.gm, hijriYearRecord.gd);
const gregorianDate = startDate.plus({ days: totalDays });
return gregorianDate.toJSDate();
}
return null;
}

44
src/toHijri.ts Normal file
View file

@ -0,0 +1,44 @@
// toHijri.ts
import { DateTime } from 'luxon';
import { hDatesTable, hDates } from './hDates';
export function toHijri(gregorianDate: Date): { hy: number, hm: number, hd: number } | null {
if (!(gregorianDate instanceof Date) || isNaN(gregorianDate.getTime())) {
throw new Error('Invalid Gregorian date');
}
const inputDate = DateTime.fromJSDate(gregorianDate).startOf('day');
const closestDate = hDatesTable.reduce((prev: Date, curr: hDates) => {
const currDate = DateTime.local(curr.gy, curr.gm, curr.gd).startOf('day');
if (currDate <= inputDate && currDate > DateTime.fromJSDate(prev)) {
return currDate.toJSDate();
}
return prev;
}, new Date(0));
const correspondingHijriYear = hDatesTable.find((date: hDates) => {
const dt = DateTime.local(date.gy, date.gm, date.gd).startOf('day');
return dt.toJSDate().getTime() === closestDate.getTime();
});
if (correspondingHijriYear) {
const differenceInDays = inputDate.diff(DateTime.fromJSDate(closestDate).startOf('day'), 'days').days;
let hijriYear = correspondingHijriYear.hy;
let hijriMonth = 0;
let remainingDays = Math.round(differenceInDays);
for (let i = 0; i < 12; i++) {
const daysInThisMonth = (correspondingHijriYear.dpm >> i) & 1 ? 30 : 29;
if (remainingDays < daysInThisMonth) {
hijriMonth = i + 1;
break;
}
remainingDays -= daysInThisMonth;
}
return { hy: hijriYear, hm: hijriMonth, hd: remainingDays + 1 };
}
return null;
}

12
src/utils.ts Normal file
View file

@ -0,0 +1,12 @@
// utils.ts
import { hDatesTable } from './hDates';
export function isValidHijriDate(hy: number, hm: number, hd: number): boolean {
const yearRecord = hDatesTable.find(record => record.hy === hy);
if (!yearRecord) {
return false;
}
const daysInMonth = (yearRecord.dpm >> (hm - 1)) & 1 ? 30 : 29;
return hm >= 1 && hm <= 12 && hd >= 1 && hd <= daysInMonth;
}

13
tsconfig.json Normal file
View file

@ -0,0 +1,13 @@
{
"compilerOptions": {
"outDir": "./dist",
"noImplicitAny": true,
"module": "commonjs",
"target": "es6",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node",
"esModuleInterop": true
},
"include": ["src/**/*"]
}