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]
|
||||
|
||||
### 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
|
||||
|
||||
### 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).
|
||||
|
||||
## 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
|
||||
|
||||
- [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 {
|
||||
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 {
|
||||
|
|
@ -262,9 +266,11 @@ const plugin: PluginFunc = (_option, dayjsClass, dayjsFactory) => {
|
|||
if (!greg) {
|
||||
throw new Error(`Invalid or out-of-range Hijri date: ${hy}/${hm}/${hd}`);
|
||||
}
|
||||
// Construct from ISO date string to avoid timezone offset issues.
|
||||
// dayjsFactory(Date) interprets the Date in local time; a UTC-midnight Date
|
||||
// in western timezones would resolve to the previous local day.
|
||||
// Construct from an ISO date string (YYYY-MM-DD) so the result is the
|
||||
// Gregorian calendar day that corresponds to the Hijri date, at local
|
||||
// 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 mo = String(greg.getUTCMonth() + 1).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);
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
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