mirror of
https://github.com/acamarata/dayjs-hijri-plus.git
synced 2026-06-30 18:54:26 +00:00
fix: convert the displayed calendar date in toHijri for hijri-core's UTC-day contract
toHijri() now passes Date.UTC(year, month, date) to hijri-core instead of the raw instant from this.toDate(). Fixes wrong-Hijri-day results around UTC-midnight on hosts east or west of UTC. Lock-step with hijri-core fix/utc-day-boundary.
This commit is contained in:
parent
f8ab0772b9
commit
f9ad1e52ed
5 changed files with 47 additions and 4 deletions
|
|
@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `.toHijri()` now converts the calendar date the dayjs instance displays (via `Date.UTC(year, month, date)`) instead of passing the raw instant to hijri-core. Fixes wrong-Hijri-day results around UTC-midnight instants on hosts east or west of UTC. Lock-step with the unreleased hijri-core `fix/utc-day-boundary` fix.
|
||||||
|
|
||||||
## [1.0.2] - 2026-05-30
|
## [1.0.2] - 2026-05-30
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,12 @@ dayjs.fromHijri(1444, 10, 1).format('YYYY-MM-DD'); // '2023-04-21'
|
||||||
|
|
||||||
Full API reference, examples, and architecture notes are on the [GitHub Wiki](https://github.com/acamarata/dayjs-hijri-plus/wiki).
|
Full API reference, examples, and architecture notes are on the [GitHub Wiki](https://github.com/acamarata/dayjs-hijri-plus/wiki).
|
||||||
|
|
||||||
|
## Day boundaries and time zones
|
||||||
|
|
||||||
|
`.toHijri()` converts the calendar date the dayjs instance displays — the same date you would read off the screen — regardless of the host's system timezone or whether the dayjs `utc` plugin is active. A call like `dayjs('2025-03-01').toHijri()` always maps the 1st of March 2025, not whatever local instant that string resolves to in UTC.
|
||||||
|
|
||||||
|
Religious start-of-day at sunset is out of scope. Sunset-aware day boundaries require external prayer-time data and are not handled here.
|
||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
- [hijri-core](https://github.com/acamarata/hijri-core): the zero-dependency Hijri calendar engine this plugin wraps
|
- [hijri-core](https://github.com/acamarata/hijri-core): the zero-dependency Hijri calendar engine this plugin wraps
|
||||||
|
|
|
||||||
14
src/index.ts
14
src/index.ts
|
|
@ -167,7 +167,11 @@ const plugin: PluginFunc = (_option, dayjsClass, dayjsFactory) => {
|
||||||
// ------------------------------------------------------------------ //
|
// ------------------------------------------------------------------ //
|
||||||
|
|
||||||
dayjsClass.prototype.toHijri = function (opts?: ConversionOptions): HijriDate | null {
|
dayjsClass.prototype.toHijri = function (opts?: ConversionOptions): HijriDate | null {
|
||||||
return toHijri(this.toDate(), opts);
|
// Build a UTC-noon Date from the calendar date this instance displays so
|
||||||
|
// that hijri-core's UTC-day contract reads the correct day regardless of
|
||||||
|
// the host timezone or whether the dayjs utc plugin is active.
|
||||||
|
// dayjs .month() is 0-based, matching Date.UTC's month parameter.
|
||||||
|
return toHijri(new Date(Date.UTC(this.year(), this.month(), this.date())), opts);
|
||||||
};
|
};
|
||||||
|
|
||||||
dayjsClass.prototype.isValidHijri = function (opts?: ConversionOptions): boolean {
|
dayjsClass.prototype.isValidHijri = function (opts?: ConversionOptions): boolean {
|
||||||
|
|
@ -262,9 +266,11 @@ const plugin: PluginFunc = (_option, dayjsClass, dayjsFactory) => {
|
||||||
if (!greg) {
|
if (!greg) {
|
||||||
throw new Error(`Invalid or out-of-range Hijri date: ${hy}/${hm}/${hd}`);
|
throw new Error(`Invalid or out-of-range Hijri date: ${hy}/${hm}/${hd}`);
|
||||||
}
|
}
|
||||||
// Construct from ISO date string to avoid timezone offset issues.
|
// Construct from an ISO date string (YYYY-MM-DD) so the result is the
|
||||||
// dayjsFactory(Date) interprets the Date in local time; a UTC-midnight Date
|
// Gregorian calendar day that corresponds to the Hijri date, at local
|
||||||
// in western timezones would resolve to the previous local day.
|
// midnight in whatever timezone the consumer uses. Passing a raw Date
|
||||||
|
// object to dayjsFactory() would interpret it as a UTC instant and could
|
||||||
|
// land on the previous local day for hosts west of UTC.
|
||||||
const y = greg.getUTCFullYear();
|
const y = greg.getUTCFullYear();
|
||||||
const mo = String(greg.getUTCMonth() + 1).padStart(2, "0");
|
const mo = String(greg.getUTCMonth() + 1).padStart(2, "0");
|
||||||
const dy = String(greg.getUTCDate()).padStart(2, "0");
|
const dy = String(greg.getUTCDate()).padStart(2, "0");
|
||||||
|
|
|
||||||
13
test-cjs.cjs
13
test-cjs.cjs
|
|
@ -59,3 +59,16 @@ describe('CJS: isValidHijri', () => {
|
||||||
assert.equal(dayjs(D_RAMADAN_1444).isValidHijri(), true);
|
assert.equal(dayjs(D_RAMADAN_1444).isValidHijri(), true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('CJS: UTC-day boundary (regression)', () => {
|
||||||
|
it('dayjs("2025-03-01").toHijri() -> 1 Ramadan 1446', () => {
|
||||||
|
const h = dayjs('2025-03-01').toHijri();
|
||||||
|
assert.deepEqual(h, { hy: 1446, hm: 9, hd: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('round-trip: fromHijri(1446,9,1) then toHijri() -> {1446,9,1}', () => {
|
||||||
|
const d = dayjs.fromHijri(1446, 9, 1);
|
||||||
|
const h = d.toHijri();
|
||||||
|
assert.deepEqual(h, { hy: 1446, hm: 9, hd: 1 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
15
test.mjs
15
test.mjs
|
|
@ -102,3 +102,18 @@ describe('isValidHijri', () => {
|
||||||
assert.equal(valid, true);
|
assert.equal(valid, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('UTC-day boundary (regression)', () => {
|
||||||
|
// dayjs("YYYY-MM-DD") parses as local midnight — timezone-invariant anchor
|
||||||
|
// for toHijri now that the adapter reads the displayed calendar date.
|
||||||
|
it('dayjs("2025-03-01").toHijri() -> 1 Ramadan 1446', () => {
|
||||||
|
const h = dayjs('2025-03-01').toHijri();
|
||||||
|
assert.deepEqual(h, { hy: 1446, hm: 9, hd: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('round-trip: fromHijri(1446,9,1) then toHijri() -> {1446,9,1}', () => {
|
||||||
|
const d = dayjs.fromHijri(1446, 9, 1);
|
||||||
|
const h = d.toHijri();
|
||||||
|
assert.deepEqual(h, { hy: 1446, hm: 9, hd: 1 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue