Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 12x 12x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 5x 5x 5x 5x 5x 5x 5x 5x 7x 7x 2x 7x 7x 1x 1x 1x 7x 7x 1x 7x 7x 1x 7x 7x 1x 1x 1x 7x 7x 7x 7x 7x 1x 7x 7x 5x 5x 5x 1x 1x 1x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 1x 2x 2x 2x 3x 1x 1x 1x 1x 1x | import moment from 'moment';
import type { Moment as MomentInstance } from 'moment';
import { toHijri, toGregorian, hmLong, hmMedium, hwLong, hwShort, hwNumeric } from 'hijri-core';
import type { HijriDate, ConversionOptions } from './types';
declare module 'moment' {
interface MomentStatic {
/**
* Construct a moment from a Hijri date.
* Throws if the date is invalid or outside the supported range.
* Call installHijri(moment) before use.
*/
fromHijri(hy: number, hm: number, hd: number, options?: ConversionOptions): MomentInstance;
}
interface Moment {
/**
* Convert this moment to a Hijri date.
* Returns null if the date falls outside the supported calendar range.
*/
toHijri(options?: ConversionOptions): HijriDate | null;
/** Return the Hijri year, or null if out of range. */
hijriYear(options?: ConversionOptions): number | null;
/** Return the Hijri month (1-12), or null if out of range. */
hijriMonth(options?: ConversionOptions): number | null;
/** Return the Hijri day, or null if out of range. */
hijriDay(options?: ConversionOptions): number | null;
/** Return true if this moment falls within the supported Hijri range. */
isValidHijri(options?: ConversionOptions): boolean;
/**
* Format this moment using Hijri-aware format tokens.
*
* Hijri tokens: iYYYY iYY iMMMM iMMM iMM iM iDD iD iEEEE iEEE iE ioooo iooo
* All other tokens are passed through to moment's own format().
*
* Returns an empty string if the date is outside the Hijri range.
*/
formatHijri(formatStr: string, options?: ConversionOptions): string;
}
}
// Regex matching all Hijri format tokens. Ordered longest-first so iYYYY is
// matched before iYY, iMMMM before iMMM, iDD before iD, iEEEE before iEEE.
const HIJRI_TOKEN_RE = /iYYYY|iYY|iMMMM|iMMM|iMM|iM|iDD|iD|iEEEE|iEEE|iE|ioooo|iooo/g;
/**
* Escape a literal string so moment.format() treats it as literal text.
* Wraps the value in square brackets, escaping any ] characters within.
*/
function escapeLiteral(value: string): string {
return '[' + value.replace(/]/g, '][]') + ']';
}
/**
* Install the Hijri plugin into the provided moment instance.
*
* @example
* import moment from 'moment';
* import installHijri from 'moment-hijri-plus';
* installHijri(moment);
*/
function install(momentInstance: typeof moment): void {
momentInstance.fn.toHijri = function (opts?: ConversionOptions): HijriDate | null {
return toHijri(this.toDate(), opts);
};
momentInstance.fn.hijriYear = function (opts?: ConversionOptions): number | null {
return this.toHijri(opts)?.hy ?? null;
};
momentInstance.fn.hijriMonth = function (opts?: ConversionOptions): number | null {
return this.toHijri(opts)?.hm ?? null;
};
momentInstance.fn.hijriDay = function (opts?: ConversionOptions): number | null {
return this.toHijri(opts)?.hd ?? null;
};
momentInstance.fn.isValidHijri = function (opts?: ConversionOptions): boolean {
return this.toHijri(opts) !== null;
};
momentInstance.fn.formatHijri = function (formatStr: string, opts?: ConversionOptions): string {
const hijri = this.toHijri(opts);
if (!hijri) return '';
const dow = this.day();
// Replace Hijri tokens with escaped literals, then pass the residual string
// to moment.format() so all standard tokens (YYYY, MMM, etc.) resolve correctly.
// Escaping is required because values like "Ramadan" would otherwise be
// interpreted by moment as format tokens (R, a, m, etc.).
const residual = formatStr.replace(HIJRI_TOKEN_RE, (token: string): string => {
switch (token) {
case 'iYYYY':
return escapeLiteral(String(hijri.hy).padStart(4, '0'));
case 'iYY':
return escapeLiteral(String(hijri.hy % 100).padStart(2, '0'));
case 'iMMMM':
// Non-null: hijri.hm is 1-12; hm-1 is always 0-11, within hmLong bounds.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return escapeLiteral(hmLong[hijri.hm - 1]!);
case 'iMMM':
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return escapeLiteral(hmMedium[hijri.hm - 1]!);
case 'iMM':
return escapeLiteral(String(hijri.hm).padStart(2, '0'));
case 'iM':
return escapeLiteral(String(hijri.hm));
case 'iDD':
return escapeLiteral(String(hijri.hd).padStart(2, '0'));
case 'iD':
return escapeLiteral(String(hijri.hd));
case 'iEEEE':
// Non-null: dow is always 0-6 (day of week), within hwLong bounds.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return escapeLiteral(hwLong[dow]!);
case 'iEEE':
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return escapeLiteral(hwShort[dow]!);
case 'iE':
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return escapeLiteral(String(hwNumeric[dow]!));
// Era tokens: both iooo and ioooo map to the common abbreviation.
case 'iooo':
case 'ioooo':
return escapeLiteral('AH');
default:
return token;
}
});
return this.format(residual);
};
// Attach fromHijri as a property on the constructor. We use bracket notation and a type
// assertion because MomentStatic augmentation produces a DTS visibility error with some
// TypeScript configurations; attaching at runtime is equivalent and safe.
(momentInstance as unknown as Record<string, unknown>)['fromHijri'] = function (
hy: number,
hm: number,
hd: number,
opts?: ConversionOptions,
): moment.Moment {
let greg: Date | null;
try {
greg = toGregorian(hy, hm, hd, opts);
} catch {
throw new Error(`Invalid or out-of-range Hijri date: ${hy}/${hm}/${hd}`);
}
if (!greg) {
throw new Error(`Invalid or out-of-range Hijri date: ${hy}/${hm}/${hd}`);
}
// Construct from explicit year/month/day to avoid UTC-to-local timezone
// shift when the Date object represents midnight UTC.
return momentInstance([greg.getUTCFullYear(), greg.getUTCMonth(), greg.getUTCDate()]);
};
}
export default install;
export type { HijriDate, ConversionOptions, CalendarEngine } from 'hijri-core';
export { registerCalendar, getCalendar, listCalendars } from 'hijri-core';
|