mirror of
https://github.com/acamarata/luxon-hijri.git
synced 2026-06-30 18:54:28 +00:00
initial commit
This commit is contained in:
commit
612aa63a78
16 changed files with 4802 additions and 0 deletions
32
.gitignore
vendored
Normal file
32
.gitignore
vendored
Normal 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
74
README.md
Normal 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
4171
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
37
package.json
Normal file
37
package.json
Normal 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
61
src/formatHijriDate.ts
Normal 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
48
src/formatPatterns.ts
Normal 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 don’t 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
195
src/hDates.ts
Normal 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
46
src/hMonths.ts
Normal 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
25
src/hWeekdays.ts
Normal 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
8
src/index.ts
Normal 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
4
src/locales/ar.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"months": ["محرم", "صفر", "..."],
|
||||
"weekdays": ["الأحد", "الاثنين", "..."]
|
||||
}
|
||||
4
src/locales/en.json
Normal file
4
src/locales/en.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"months": ["Muharram", "Safar", "..."],
|
||||
"weekdays": ["Sunday", "Monday", "..."]
|
||||
}
|
||||
28
src/toGregorian.ts
Normal file
28
src/toGregorian.ts
Normal 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
44
src/toHijri.ts
Normal 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
12
src/utils.ts
Normal 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
13
tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"noImplicitAny": true,
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"jsx": "react",
|
||||
"allowJs": true,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
Loading…
Reference in a new issue