mihrab-methods 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +373 -0
- package/README.md +319 -2
- package/certification.json +120 -0
- package/data/corrections/algeria.json +784 -0
- package/data/corrections/diyanet.json +18444 -0
- package/data/corrections/indonesia.json +210 -0
- package/data/corrections/morocco.json +993 -0
- package/data/corrections/sweden.json +516 -0
- package/dist/cjs/algeria.d.ts +4 -0
- package/dist/cjs/algeria.js +22 -0
- package/dist/cjs/authorities/algeria.d.ts +3 -0
- package/dist/cjs/authorities/algeria.js +57 -0
- package/dist/cjs/authorities/diyanet.d.ts +9 -0
- package/dist/cjs/authorities/diyanet.js +90 -0
- package/dist/cjs/authorities/indonesia.d.ts +4 -0
- package/dist/cjs/authorities/indonesia.js +82 -0
- package/dist/cjs/authorities/morocco.d.ts +5 -0
- package/dist/cjs/authorities/morocco.js +65 -0
- package/dist/cjs/authorities/slug.d.ts +2 -0
- package/dist/cjs/authorities/slug.js +17 -0
- package/dist/cjs/authorities/sweden.d.ts +3 -0
- package/dist/cjs/authorities/sweden.js +58 -0
- package/dist/cjs/core/api.d.ts +61 -0
- package/dist/cjs/core/api.js +176 -0
- package/dist/cjs/core/civilDate.d.ts +17 -0
- package/dist/cjs/core/civilDate.js +41 -0
- package/dist/cjs/core/clock.d.ts +15 -0
- package/dist/cjs/core/clock.js +46 -0
- package/dist/cjs/core/compute.d.ts +10 -0
- package/dist/cjs/core/compute.js +59 -0
- package/dist/cjs/core/correctionList.d.ts +25 -0
- package/dist/cjs/core/correctionList.js +62 -0
- package/dist/cjs/core/fetchLatest.d.ts +57 -0
- package/dist/cjs/core/fetchLatest.js +137 -0
- package/dist/cjs/core/index.d.ts +14 -0
- package/dist/cjs/core/index.js +45 -0
- package/dist/cjs/core/registry.d.ts +28 -0
- package/dist/cjs/core/registry.js +29 -0
- package/dist/cjs/core/types.d.ts +193 -0
- package/dist/cjs/core/types.js +22 -0
- package/dist/cjs/core.d.ts +2 -0
- package/dist/cjs/core.js +18 -0
- package/dist/cjs/data/generated/algeriaCertification.d.ts +3 -0
- package/dist/cjs/data/generated/algeriaCertification.js +4 -0
- package/dist/cjs/data/generated/algeriaCities.d.ts +8 -0
- package/dist/cjs/data/generated/algeriaCities.js +5 -0
- package/dist/cjs/data/generated/algeriaCorrections.d.ts +3 -0
- package/dist/cjs/data/generated/algeriaCorrections.js +4 -0
- package/dist/cjs/data/generated/algeriaMethodPoints.d.ts +2 -0
- package/dist/cjs/data/generated/algeriaMethodPoints.js +5 -0
- package/dist/cjs/data/generated/countryOutlines.d.ts +5 -0
- package/dist/cjs/data/generated/countryOutlines.js +5 -0
- package/dist/cjs/data/generated/diyanetCertification.d.ts +3 -0
- package/dist/cjs/data/generated/diyanetCertification.js +4 -0
- package/dist/cjs/data/generated/diyanetCorrections.d.ts +3 -0
- package/dist/cjs/data/generated/diyanetCorrections.js +4 -0
- package/dist/cjs/data/generated/diyanetCountries.d.ts +5 -0
- package/dist/cjs/data/generated/diyanetCountries.js +5 -0
- package/dist/cjs/data/generated/diyanetTurkeyPoints.d.ts +7 -0
- package/dist/cjs/data/generated/diyanetTurkeyPoints.js +5 -0
- package/dist/cjs/data/generated/diyanetWorldPoints.d.ts +10 -0
- package/dist/cjs/data/generated/diyanetWorldPoints.js +5 -0
- package/dist/cjs/data/generated/indonesiaCertification.d.ts +3 -0
- package/dist/cjs/data/generated/indonesiaCertification.js +4 -0
- package/dist/cjs/data/generated/indonesiaCorrections.d.ts +3 -0
- package/dist/cjs/data/generated/indonesiaCorrections.js +4 -0
- package/dist/cjs/data/generated/kemenagMethodPoints.d.ts +2 -0
- package/dist/cjs/data/generated/kemenagMethodPoints.js +5 -0
- package/dist/cjs/data/generated/kemenagPlaces.d.ts +8 -0
- package/dist/cjs/data/generated/kemenagPlaces.js +5 -0
- package/dist/cjs/data/generated/moroccoCertification.d.ts +3 -0
- package/dist/cjs/data/generated/moroccoCertification.js +4 -0
- package/dist/cjs/data/generated/moroccoCities.d.ts +8 -0
- package/dist/cjs/data/generated/moroccoCities.js +5 -0
- package/dist/cjs/data/generated/moroccoCorrections.d.ts +3 -0
- package/dist/cjs/data/generated/moroccoCorrections.js +4 -0
- package/dist/cjs/data/generated/moroccoMethodPoints.d.ts +2 -0
- package/dist/cjs/data/generated/moroccoMethodPoints.js +5 -0
- package/dist/cjs/data/generated/swedenCertification.d.ts +3 -0
- package/dist/cjs/data/generated/swedenCertification.js +4 -0
- package/dist/cjs/data/generated/swedenCorrections.d.ts +3 -0
- package/dist/cjs/data/generated/swedenCorrections.js +4 -0
- package/dist/cjs/data/generated/swedenPlaces.d.ts +5 -0
- package/dist/cjs/data/generated/swedenPlaces.js +5 -0
- package/dist/cjs/diyanet.d.ts +4 -0
- package/dist/cjs/diyanet.js +22 -0
- package/dist/cjs/index.d.ts +19 -0
- package/dist/cjs/index.js +37 -0
- package/dist/cjs/indonesia.d.ts +4 -0
- package/dist/cjs/indonesia.js +22 -0
- package/dist/cjs/locate.d.ts +21 -0
- package/dist/cjs/locate.js +204 -0
- package/dist/cjs/methods/algeria.d.ts +56 -0
- package/dist/cjs/methods/algeria.js +119 -0
- package/dist/cjs/methods/indonesia.d.ts +31 -0
- package/dist/cjs/methods/indonesia.js +94 -0
- package/dist/cjs/methods/morocco.d.ts +61 -0
- package/dist/cjs/methods/morocco.js +113 -0
- package/dist/cjs/methods/revisions.d.ts +15 -0
- package/dist/cjs/methods/revisions.js +18 -0
- package/dist/cjs/methods/scratch-congress.d.ts +87 -0
- package/dist/cjs/methods/scratch-congress.js +539 -0
- package/dist/cjs/methods/sweden.d.ts +88 -0
- package/dist/cjs/methods/sweden.js +568 -0
- package/dist/cjs/morocco.d.ts +4 -0
- package/dist/cjs/morocco.js +22 -0
- package/dist/cjs/sun/preciseSun.d.ts +19 -0
- package/dist/cjs/sun/preciseSun.js +185 -0
- package/dist/cjs/sweden.d.ts +4 -0
- package/dist/cjs/sweden.js +22 -0
- package/dist/esm/algeria.d.ts +4 -0
- package/dist/esm/algeria.js +4 -0
- package/dist/esm/authorities/algeria.d.ts +3 -0
- package/dist/esm/authorities/algeria.js +51 -0
- package/dist/esm/authorities/diyanet.d.ts +9 -0
- package/dist/esm/authorities/diyanet.js +83 -0
- package/dist/esm/authorities/indonesia.d.ts +4 -0
- package/dist/esm/authorities/indonesia.js +75 -0
- package/dist/esm/authorities/morocco.d.ts +5 -0
- package/dist/esm/authorities/morocco.js +59 -0
- package/dist/esm/authorities/slug.d.ts +2 -0
- package/dist/esm/authorities/slug.js +14 -0
- package/dist/esm/authorities/sweden.d.ts +3 -0
- package/dist/esm/authorities/sweden.js +52 -0
- package/dist/esm/core/api.d.ts +61 -0
- package/dist/esm/core/api.js +162 -0
- package/dist/esm/core/civilDate.d.ts +17 -0
- package/dist/esm/core/civilDate.js +36 -0
- package/dist/esm/core/clock.d.ts +15 -0
- package/dist/esm/core/clock.js +39 -0
- package/dist/esm/core/compute.d.ts +10 -0
- package/dist/esm/core/compute.js +56 -0
- package/dist/esm/core/correctionList.d.ts +25 -0
- package/dist/esm/core/correctionList.js +56 -0
- package/dist/esm/core/fetchLatest.d.ts +57 -0
- package/dist/esm/core/fetchLatest.js +98 -0
- package/dist/esm/core/index.d.ts +14 -0
- package/dist/esm/core/index.js +14 -0
- package/dist/esm/core/registry.d.ts +28 -0
- package/dist/esm/core/registry.js +23 -0
- package/dist/esm/core/types.d.ts +193 -0
- package/dist/esm/core/types.js +18 -0
- package/dist/esm/core.d.ts +2 -0
- package/dist/esm/core.js +2 -0
- package/dist/esm/data/generated/algeriaCertification.d.ts +3 -0
- package/dist/esm/data/generated/algeriaCertification.js +2 -0
- package/dist/esm/data/generated/algeriaCities.d.ts +8 -0
- package/dist/esm/data/generated/algeriaCities.js +3 -0
- package/dist/esm/data/generated/algeriaCorrections.d.ts +3 -0
- package/dist/esm/data/generated/algeriaCorrections.js +2 -0
- package/dist/esm/data/generated/algeriaMethodPoints.d.ts +2 -0
- package/dist/esm/data/generated/algeriaMethodPoints.js +3 -0
- package/dist/esm/data/generated/countryOutlines.d.ts +5 -0
- package/dist/esm/data/generated/countryOutlines.js +3 -0
- package/dist/esm/data/generated/diyanetCertification.d.ts +3 -0
- package/dist/esm/data/generated/diyanetCertification.js +2 -0
- package/dist/esm/data/generated/diyanetCorrections.d.ts +3 -0
- package/dist/esm/data/generated/diyanetCorrections.js +2 -0
- package/dist/esm/data/generated/diyanetCountries.d.ts +5 -0
- package/dist/esm/data/generated/diyanetCountries.js +3 -0
- package/dist/esm/data/generated/diyanetTurkeyPoints.d.ts +7 -0
- package/dist/esm/data/generated/diyanetTurkeyPoints.js +3 -0
- package/dist/esm/data/generated/diyanetWorldPoints.d.ts +10 -0
- package/dist/esm/data/generated/diyanetWorldPoints.js +3 -0
- package/dist/esm/data/generated/indonesiaCertification.d.ts +3 -0
- package/dist/esm/data/generated/indonesiaCertification.js +2 -0
- package/dist/esm/data/generated/indonesiaCorrections.d.ts +3 -0
- package/dist/esm/data/generated/indonesiaCorrections.js +2 -0
- package/dist/esm/data/generated/kemenagMethodPoints.d.ts +2 -0
- package/dist/esm/data/generated/kemenagMethodPoints.js +3 -0
- package/dist/esm/data/generated/kemenagPlaces.d.ts +8 -0
- package/dist/esm/data/generated/kemenagPlaces.js +3 -0
- package/dist/esm/data/generated/moroccoCertification.d.ts +3 -0
- package/dist/esm/data/generated/moroccoCertification.js +2 -0
- package/dist/esm/data/generated/moroccoCities.d.ts +8 -0
- package/dist/esm/data/generated/moroccoCities.js +3 -0
- package/dist/esm/data/generated/moroccoCorrections.d.ts +3 -0
- package/dist/esm/data/generated/moroccoCorrections.js +2 -0
- package/dist/esm/data/generated/moroccoMethodPoints.d.ts +2 -0
- package/dist/esm/data/generated/moroccoMethodPoints.js +3 -0
- package/dist/esm/data/generated/swedenCertification.d.ts +3 -0
- package/dist/esm/data/generated/swedenCertification.js +2 -0
- package/dist/esm/data/generated/swedenCorrections.d.ts +3 -0
- package/dist/esm/data/generated/swedenCorrections.js +2 -0
- package/dist/esm/data/generated/swedenPlaces.d.ts +5 -0
- package/dist/esm/data/generated/swedenPlaces.js +3 -0
- package/dist/esm/diyanet.d.ts +4 -0
- package/dist/esm/diyanet.js +4 -0
- package/dist/esm/index.d.ts +19 -0
- package/dist/esm/index.js +19 -0
- package/dist/esm/indonesia.d.ts +4 -0
- package/dist/esm/indonesia.js +4 -0
- package/dist/esm/locate.d.ts +21 -0
- package/dist/esm/locate.js +196 -0
- package/dist/esm/methods/algeria.d.ts +56 -0
- package/dist/esm/methods/algeria.js +114 -0
- package/dist/esm/methods/indonesia.d.ts +31 -0
- package/dist/esm/methods/indonesia.js +90 -0
- package/dist/esm/methods/morocco.d.ts +61 -0
- package/dist/esm/methods/morocco.js +107 -0
- package/dist/esm/methods/revisions.d.ts +15 -0
- package/dist/esm/methods/revisions.js +15 -0
- package/dist/esm/methods/scratch-congress.d.ts +87 -0
- package/dist/esm/methods/scratch-congress.js +534 -0
- package/dist/esm/methods/sweden.d.ts +88 -0
- package/dist/esm/methods/sweden.js +563 -0
- package/dist/esm/morocco.d.ts +4 -0
- package/dist/esm/morocco.js +4 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/sun/preciseSun.d.ts +19 -0
- package/dist/esm/sun/preciseSun.js +181 -0
- package/dist/esm/sweden.d.ts +4 -0
- package/dist/esm/sweden.js +4 -0
- package/docs/methods.md +190 -0
- package/package.json +178 -4
- package/schemas/certification.schema.json +59 -0
- package/schemas/corrections.schema.json +29 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.kemenagRawMinutes = kemenagRawMinutes;
|
|
4
|
+
exports.kemenagTimes = kemenagTimes;
|
|
5
|
+
/**
|
|
6
|
+
* Indonesia — the Ministry of Religious Affairs' (Kemenag) method, as its
|
|
7
|
+
* timetable is computed.
|
|
8
|
+
*
|
|
9
|
+
* Read off its table for all 517 regencies and cities (October–December
|
|
10
|
+
* 2026):
|
|
11
|
+
*
|
|
12
|
+
* • the precise apparent Sun (`preciseApparentSun`, as JPL's to a tenth
|
|
13
|
+
* of a second), taken at each prayer's own moment, iterated — Meeus's
|
|
14
|
+
* shorter series drifts by a second and left a minute in two hundred
|
|
15
|
+
* off;
|
|
16
|
+
* • Fajr 20°, Isha 18°; sunrise and Maghrib at −1°, and at −2° in the
|
|
17
|
+
* regencies the ministry classes as highland — in six highland
|
|
18
|
+
* regencies of Papua the degree is taken off Fajr and Isha too;
|
|
19
|
+
* • Asr when the shadow is its length plus the noon shadow, the noon
|
|
20
|
+
* shadow from the Sun's declination at 00:00 UT of the day (as an
|
|
21
|
+
* almanac's daily entry gives it), the hour angle from the Sun at Asr;
|
|
22
|
+
* • every time rounded up, after a margin of two minutes (three for
|
|
23
|
+
* Dhuhr, minus three for sunrise).
|
|
24
|
+
*
|
|
25
|
+
* At each regency's own point (fitted to the table; Karawang's afternoon
|
|
26
|
+
* at a second one) this gives the ministry's minute for 99.969 % of its
|
|
27
|
+
* times, and never a minute further; the rest are within about a second
|
|
28
|
+
* of a minute's edge, with no pattern a model could take
|
|
29
|
+
* (`data/corrections/indonesia.json` has them).
|
|
30
|
+
*/
|
|
31
|
+
const preciseSun_js_1 = require("../sun/preciseSun.js");
|
|
32
|
+
const RAD = Math.PI / 180;
|
|
33
|
+
const DAY_MS = 86_400_000;
|
|
34
|
+
const ITERATIONS = 3;
|
|
35
|
+
const MARGIN = { fajr: 2, sunrise: -3, dhuhr: 3, asr: 2, maghrib: 2, isha: 2 };
|
|
36
|
+
const ASR_ITERATIONS = 4;
|
|
37
|
+
/** Exact times with the margins, minutes past 00:00 UT of the civil date, before rounding. */
|
|
38
|
+
function kemenagRawMinutes(latitude, longitude, year, month, day, opts = {}) {
|
|
39
|
+
const d0 = (Date.UTC(year, month, day) - Date.UTC(2000, 0, 1)) / DAY_MS - 0.5;
|
|
40
|
+
const at = (t) => (0, preciseSun_js_1.preciseApparentSun)(d0 + t / 1440);
|
|
41
|
+
let noon = 720 - 4 * longitude;
|
|
42
|
+
for (let i = 0; i < ITERATIONS; i++)
|
|
43
|
+
noon = 720 - 4 * longitude - at(noon).eot;
|
|
44
|
+
const sp = Math.sin(latitude * RAD);
|
|
45
|
+
const cp = Math.cos(latitude * RAD);
|
|
46
|
+
const hourAngle = (alt, dec) => {
|
|
47
|
+
const c = (Math.sin(alt * RAD) - sp * Math.sin(dec)) / (cp * Math.cos(dec));
|
|
48
|
+
return Math.abs(c) <= 1 ? (4 * Math.acos(c)) / RAD : NaN;
|
|
49
|
+
};
|
|
50
|
+
const event = (alt, sign, start) => {
|
|
51
|
+
let t = start;
|
|
52
|
+
for (let i = 0; i < ITERATIONS; i++) {
|
|
53
|
+
const { dec, eot } = at(t);
|
|
54
|
+
t = 720 - 4 * longitude - eot + sign * hourAngle(alt, dec);
|
|
55
|
+
if (!Number.isFinite(t))
|
|
56
|
+
return NaN;
|
|
57
|
+
}
|
|
58
|
+
return t;
|
|
59
|
+
};
|
|
60
|
+
const twilight = opts.twilightDip ? 1 : 0;
|
|
61
|
+
const horizon = opts.highland ? -2 : -1;
|
|
62
|
+
// The noon shadow from the declination at 00:00 UT; the hour angle from the Sun at Asr, iterated.
|
|
63
|
+
const shadowDec = at(0).dec;
|
|
64
|
+
const asrAlt = Math.atan(1 / ((opts.asrShadow ?? 1) + Math.tan(Math.abs(latitude * RAD - shadowDec)))) / RAD;
|
|
65
|
+
let asr = noon + 200;
|
|
66
|
+
for (let i = 0; i < ASR_ITERATIONS; i++) {
|
|
67
|
+
const { dec, eot } = at(asr);
|
|
68
|
+
asr = 720 - 4 * longitude - eot + hourAngle(asrAlt, dec);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
fajr: event(-20 - twilight, -1, noon - 420) + MARGIN.fajr,
|
|
72
|
+
sunrise: event(horizon, -1, noon - 360) + MARGIN.sunrise,
|
|
73
|
+
dhuhr: noon + MARGIN.dhuhr,
|
|
74
|
+
asr: asr + MARGIN.asr,
|
|
75
|
+
maghrib: event(horizon, 1, noon + 360) + MARGIN.maghrib,
|
|
76
|
+
isha: event(-18 - twilight, 1, noon + 420) + MARGIN.isha,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** The ministry's times for a point and civil date (month 0-based), on the minute; null where one does not form. */
|
|
80
|
+
function kemenagTimes(latitude, longitude, year, month, day, opts = {}) {
|
|
81
|
+
const r = kemenagRawMinutes(latitude, longitude, year, month, day, opts);
|
|
82
|
+
if (opts.afternoon) {
|
|
83
|
+
const pm = kemenagRawMinutes(opts.afternoon[0], opts.afternoon[1], year, month, day, opts);
|
|
84
|
+
r.asr = pm.asr;
|
|
85
|
+
r.maghrib = pm.maghrib;
|
|
86
|
+
r.isha = pm.isha;
|
|
87
|
+
}
|
|
88
|
+
const all = [r.fajr, r.sunrise, r.dhuhr, r.asr, r.maghrib, r.isha];
|
|
89
|
+
if (!all.every(Number.isFinite))
|
|
90
|
+
return null;
|
|
91
|
+
const start = Date.UTC(year, month, day);
|
|
92
|
+
const at = (m) => new Date(start + Math.ceil(m - 1e-9) * 60_000);
|
|
93
|
+
return { fajr: at(r.fajr), sunrise: at(r.sunrise), dhuhr: at(r.dhuhr), asr: at(r.asr), maghrib: at(r.maghrib), isha: at(r.isha) };
|
|
94
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Morocco — the Ministry of Habous and Islamic Affairs's method, as its
|
|
3
|
+
* timetable is computed (issue #10).
|
|
4
|
+
*
|
|
5
|
+
* Read off 77 days of the ministry's tables for its 164 located cities:
|
|
6
|
+
*
|
|
7
|
+
* • a precise Sun — Meeus's apparent Sun with the full nutation and his
|
|
8
|
+
* chapter-28 equation of time; a JPL ephemeris fits no better, NOAA's
|
|
9
|
+
* and the Almanac's series far worse — taken at each prayer's own
|
|
10
|
+
* moment (iterated), declination and equation of time alike;
|
|
11
|
+
* • Fajr 19°, Isha 17°, Asr one shadow length (Shafi'i);
|
|
12
|
+
* • Dhuhr five minutes after the transit;
|
|
13
|
+
* • sunrise 2.85 minutes before, and Maghrib 3.7 after, the Sun's upper
|
|
14
|
+
* limb on the horizon — refraction 34′ and the Sun's semi-diameter for
|
|
15
|
+
* its distance that day — less the city's own horizon dip;
|
|
16
|
+
* • Fajr rounded down to the minute, the rest to the nearest.
|
|
17
|
+
*
|
|
18
|
+
* The dip is the ministry's own per city and per side — the horizon east
|
|
19
|
+
* at sunrise, west at Maghrib, which mountains or the sea make different —
|
|
20
|
+
* fitted from its tables with the city's point (`data/moroccoMethodPoints.json`,
|
|
21
|
+
* about 0.02° per √metre of height); elsewhere 0.02°·√height, 0.86 of it at
|
|
22
|
+
* Maghrib. On 77 days of the ministry's tables for its 164 located cities
|
|
23
|
+
* this is its printed minute for 99.12 % of times, and never further than
|
|
24
|
+
* one; `data/corrections/morocco.json` holds the rest.
|
|
25
|
+
*/
|
|
26
|
+
export type MoroccoInstants = {
|
|
27
|
+
fajr: Date;
|
|
28
|
+
sunrise: Date;
|
|
29
|
+
dhuhr: Date;
|
|
30
|
+
asr: Date;
|
|
31
|
+
maghrib: Date;
|
|
32
|
+
isha: Date;
|
|
33
|
+
};
|
|
34
|
+
/** Meeus's apparent Sun at `d` days from J2000.0: declination (rad), equation of time (minutes). */
|
|
35
|
+
export declare function meeusApparentSun(d: number): {
|
|
36
|
+
dec: number;
|
|
37
|
+
eot: number;
|
|
38
|
+
};
|
|
39
|
+
/** Minutes before the horizon crossing that the ministry prints sunrise, and after it Maghrib. */
|
|
40
|
+
export declare const MOROCCO_SUNRISE_MARGIN = -2.85;
|
|
41
|
+
export declare const MOROCCO_MAGHRIB_MARGIN = 3.7;
|
|
42
|
+
/** The share of the horizon dip Maghrib takes, against sunrise's whole, where a city's own is not known. */
|
|
43
|
+
export declare const MOROCCO_MAGHRIB_DIP_SHARE = 0.86;
|
|
44
|
+
/** Degrees of dip per √metre where the ministry's own value is not known. */
|
|
45
|
+
export declare const MOROCCO_DIP_PER_SQRT_M = 0.02;
|
|
46
|
+
/** Exact times, minutes past 00:00 UT of the civil date, margins applied, before rounding. NaN where one does not form. */
|
|
47
|
+
export declare function moroccoRawMinutes(latitude: number, longitude: number, year: number, month: number, day: number, dipDeg?: number, asrShadow?: number,
|
|
48
|
+
/** The horizon's dip westward, at Maghrib; MOROCCO_MAGHRIB_DIP_SHARE of `dipDeg` when not known. */
|
|
49
|
+
dipMaghribDeg?: number): {
|
|
50
|
+
fajr: number;
|
|
51
|
+
sunrise: number;
|
|
52
|
+
dhuhr: number;
|
|
53
|
+
asr: number;
|
|
54
|
+
maghrib: number;
|
|
55
|
+
isha: number;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The ministry's times for a point and civil date (month 0-based), on the
|
|
59
|
+
* minute. Null when a time does not form there.
|
|
60
|
+
*/
|
|
61
|
+
export declare function moroccoTimes(latitude: number, longitude: number, year: number, month: number, day: number, dipDeg?: number, asrShadow?: number, dipMaghribDeg?: number): MoroccoInstants | null;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Morocco — the Ministry of Habous and Islamic Affairs's method, as its
|
|
4
|
+
* timetable is computed (issue #10).
|
|
5
|
+
*
|
|
6
|
+
* Read off 77 days of the ministry's tables for its 164 located cities:
|
|
7
|
+
*
|
|
8
|
+
* • a precise Sun — Meeus's apparent Sun with the full nutation and his
|
|
9
|
+
* chapter-28 equation of time; a JPL ephemeris fits no better, NOAA's
|
|
10
|
+
* and the Almanac's series far worse — taken at each prayer's own
|
|
11
|
+
* moment (iterated), declination and equation of time alike;
|
|
12
|
+
* • Fajr 19°, Isha 17°, Asr one shadow length (Shafi'i);
|
|
13
|
+
* • Dhuhr five minutes after the transit;
|
|
14
|
+
* • sunrise 2.85 minutes before, and Maghrib 3.7 after, the Sun's upper
|
|
15
|
+
* limb on the horizon — refraction 34′ and the Sun's semi-diameter for
|
|
16
|
+
* its distance that day — less the city's own horizon dip;
|
|
17
|
+
* • Fajr rounded down to the minute, the rest to the nearest.
|
|
18
|
+
*
|
|
19
|
+
* The dip is the ministry's own per city and per side — the horizon east
|
|
20
|
+
* at sunrise, west at Maghrib, which mountains or the sea make different —
|
|
21
|
+
* fitted from its tables with the city's point (`data/moroccoMethodPoints.json`,
|
|
22
|
+
* about 0.02° per √metre of height); elsewhere 0.02°·√height, 0.86 of it at
|
|
23
|
+
* Maghrib. On 77 days of the ministry's tables for its 164 located cities
|
|
24
|
+
* this is its printed minute for 99.12 % of times, and never further than
|
|
25
|
+
* one; `data/corrections/morocco.json` holds the rest.
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.MOROCCO_DIP_PER_SQRT_M = exports.MOROCCO_MAGHRIB_DIP_SHARE = exports.MOROCCO_MAGHRIB_MARGIN = exports.MOROCCO_SUNRISE_MARGIN = void 0;
|
|
29
|
+
exports.meeusApparentSun = meeusApparentSun;
|
|
30
|
+
exports.moroccoRawMinutes = moroccoRawMinutes;
|
|
31
|
+
exports.moroccoTimes = moroccoTimes;
|
|
32
|
+
const RAD = Math.PI / 180;
|
|
33
|
+
const DAY_MS = 86_400_000;
|
|
34
|
+
/** Meeus's apparent Sun at `d` days from J2000.0: declination (rad), equation of time (minutes). */
|
|
35
|
+
function meeusApparentSun(d) {
|
|
36
|
+
const T = d / 36525;
|
|
37
|
+
const L0 = (((280.46646 + T * (36000.76983 + 0.0003032 * T)) % 360) + 360) % 360;
|
|
38
|
+
const M = (357.52911 + T * (35999.05029 - 0.0001537 * T)) * RAD;
|
|
39
|
+
const C = (1.914602 - T * (0.004817 + 0.000014 * T)) * Math.sin(M) +
|
|
40
|
+
(0.019993 - 0.000101 * T) * Math.sin(2 * M) +
|
|
41
|
+
0.000289 * Math.sin(3 * M);
|
|
42
|
+
const om = (125.04 - 1934.136 * T) * RAD;
|
|
43
|
+
const eps0 = 23 + (26 + (21.448 - T * (46.815 + T * (0.00059 - T * 0.001813))) / 60) / 60;
|
|
44
|
+
const Lm = (280.4665 + 36000.7698 * T) * RAD;
|
|
45
|
+
const Lmoon = (218.3165 + 481267.8813 * T) * RAD;
|
|
46
|
+
const dpsi = (-17.2 * Math.sin(om) - 1.32 * Math.sin(2 * Lm) - 0.23 * Math.sin(2 * Lmoon) + 0.21 * Math.sin(2 * om)) / 3600;
|
|
47
|
+
const deps = (9.2 * Math.cos(om) + 0.57 * Math.cos(2 * Lm) + 0.1 * Math.cos(2 * Lmoon) - 0.09 * Math.cos(2 * om)) / 3600;
|
|
48
|
+
const lambda = (L0 + C - 0.00569 + dpsi) * RAD;
|
|
49
|
+
const eps = (eps0 + deps) * RAD;
|
|
50
|
+
const ra = (((Math.atan2(Math.cos(eps) * Math.sin(lambda), Math.cos(lambda)) / RAD) % 360) + 360) % 360;
|
|
51
|
+
const dec = Math.asin(Math.sin(eps) * Math.sin(lambda));
|
|
52
|
+
const E = L0 - 0.0057183 - ra + dpsi * Math.cos(eps);
|
|
53
|
+
const eot = ((((E + 180) % 360) + 360) % 360 - 180) * 4;
|
|
54
|
+
return { dec, eot };
|
|
55
|
+
}
|
|
56
|
+
const ITERATIONS = 3;
|
|
57
|
+
/** Minutes before the horizon crossing that the ministry prints sunrise, and after it Maghrib. */
|
|
58
|
+
exports.MOROCCO_SUNRISE_MARGIN = -2.85;
|
|
59
|
+
exports.MOROCCO_MAGHRIB_MARGIN = 3.7;
|
|
60
|
+
/** The share of the horizon dip Maghrib takes, against sunrise's whole, where a city's own is not known. */
|
|
61
|
+
exports.MOROCCO_MAGHRIB_DIP_SHARE = 0.86;
|
|
62
|
+
/** Degrees of dip per √metre where the ministry's own value is not known. */
|
|
63
|
+
exports.MOROCCO_DIP_PER_SQRT_M = 0.02;
|
|
64
|
+
/** Exact times, minutes past 00:00 UT of the civil date, margins applied, before rounding. NaN where one does not form. */
|
|
65
|
+
function moroccoRawMinutes(latitude, longitude, year, month, day, dipDeg = 0, asrShadow = 1,
|
|
66
|
+
/** The horizon's dip westward, at Maghrib; MOROCCO_MAGHRIB_DIP_SHARE of `dipDeg` when not known. */
|
|
67
|
+
dipMaghribDeg = exports.MOROCCO_MAGHRIB_DIP_SHARE * dipDeg) {
|
|
68
|
+
const d0 = (Date.UTC(year, month, day) - Date.UTC(2000, 0, 1)) / DAY_MS - 0.5;
|
|
69
|
+
const at = (t) => meeusApparentSun(d0 + t / 1440);
|
|
70
|
+
let noon = 720 - 4 * longitude;
|
|
71
|
+
for (let i = 0; i < ITERATIONS; i++)
|
|
72
|
+
noon = 720 - 4 * longitude - at(noon).eot;
|
|
73
|
+
const sp = Math.sin(latitude * RAD);
|
|
74
|
+
const cp = Math.cos(latitude * RAD);
|
|
75
|
+
// the upper limb on the horizon: refraction 34′ and the semi-diameter for the Sun's distance that day
|
|
76
|
+
const T = (d0 + noon / 1440) / 36525;
|
|
77
|
+
const Ma = (357.52911 + 35999.05029 * T) * RAD;
|
|
78
|
+
const horizon = -(34 / 60 + 0.26667 / (1.00014 - 0.016708 * Math.cos(Ma) - 0.00014 * Math.cos(2 * Ma)));
|
|
79
|
+
const event = (altitudeOf, sign, start) => {
|
|
80
|
+
let t = start;
|
|
81
|
+
for (let i = 0; i < ITERATIONS; i++) {
|
|
82
|
+
const { dec, eot } = at(t);
|
|
83
|
+
const c = (Math.sin(altitudeOf(dec) * RAD) - sp * Math.sin(dec)) / (cp * Math.cos(dec));
|
|
84
|
+
if (!(Math.abs(c) <= 1))
|
|
85
|
+
return NaN;
|
|
86
|
+
t = 720 - 4 * longitude - eot + (sign * 4 * Math.acos(c)) / RAD;
|
|
87
|
+
}
|
|
88
|
+
return t;
|
|
89
|
+
};
|
|
90
|
+
const fixed = (a) => () => a;
|
|
91
|
+
const asrAltitude = (dec) => Math.atan(1 / (asrShadow + Math.tan(Math.abs(latitude - dec / RAD) * RAD))) / RAD;
|
|
92
|
+
return {
|
|
93
|
+
fajr: event(fixed(-19), -1, noon - 420) - 0.5,
|
|
94
|
+
sunrise: event(fixed(horizon - dipDeg), -1, noon - 360) + exports.MOROCCO_SUNRISE_MARGIN,
|
|
95
|
+
dhuhr: noon + 5,
|
|
96
|
+
asr: event(asrAltitude, 1, noon + 200),
|
|
97
|
+
maghrib: event(fixed(horizon - dipMaghribDeg), 1, noon + 360) + exports.MOROCCO_MAGHRIB_MARGIN,
|
|
98
|
+
isha: event(fixed(-17), 1, noon + 420),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The ministry's times for a point and civil date (month 0-based), on the
|
|
103
|
+
* minute. Null when a time does not form there.
|
|
104
|
+
*/
|
|
105
|
+
function moroccoTimes(latitude, longitude, year, month, day, dipDeg = 0, asrShadow = 1, dipMaghribDeg) {
|
|
106
|
+
const r = moroccoRawMinutes(latitude, longitude, year, month, day, dipDeg, asrShadow, dipMaghribDeg);
|
|
107
|
+
const all = [r.fajr, r.sunrise, r.dhuhr, r.asr, r.maghrib, r.isha];
|
|
108
|
+
if (!all.every(Number.isFinite))
|
|
109
|
+
return null;
|
|
110
|
+
const start = Date.UTC(year, month, day);
|
|
111
|
+
const at = (m) => new Date(start + Math.floor(m + 0.5) * 60_000);
|
|
112
|
+
return { fajr: at(r.fajr), sunrise: at(r.sunrise), dhuhr: at(r.dhuhr), asr: at(r.asr), maghrib: at(r.maghrib), isha: at(r.isha) };
|
|
113
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Each method's revision: raised whenever a change to a method, or to the
|
|
3
|
+
* points it computes its places at, changes what it prints. A correction
|
|
4
|
+
* list is written for one revision (certification.json names it), and an
|
|
5
|
+
* app applies a list only to the revision it computes — a list for another
|
|
6
|
+
* would move the wrong minutes. An app on an older revision tells its user
|
|
7
|
+
* to update instead.
|
|
8
|
+
*/
|
|
9
|
+
export declare const METHOD_REVISION: {
|
|
10
|
+
readonly sweden: 1;
|
|
11
|
+
readonly diyanet: 1;
|
|
12
|
+
readonly morocco: 1;
|
|
13
|
+
readonly algeria: 1;
|
|
14
|
+
readonly indonesia: 1;
|
|
15
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.METHOD_REVISION = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Each method's revision: raised whenever a change to a method, or to the
|
|
6
|
+
* points it computes its places at, changes what it prints. A correction
|
|
7
|
+
* list is written for one revision (certification.json names it), and an
|
|
8
|
+
* app applies a list only to the revision it computes — a list for another
|
|
9
|
+
* would move the wrong minutes. An app on an older revision tells its user
|
|
10
|
+
* to update instead.
|
|
11
|
+
*/
|
|
12
|
+
exports.METHOD_REVISION = {
|
|
13
|
+
sweden: 1,
|
|
14
|
+
diyanet: 1,
|
|
15
|
+
morocco: 1,
|
|
16
|
+
algeria: 1,
|
|
17
|
+
indonesia: 1,
|
|
18
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The International Prayer Times Congress method (Istanbul, 2021 — the
|
|
3
|
+
* Diyanet and the European Council for Fatwa and Research) as Diyanet's
|
|
4
|
+
* tables realise it. Islamiska Förbundet's Swedish tables are those
|
|
5
|
+
* tables, row for row, so this is Sweden's method (id 24).
|
|
6
|
+
*
|
|
7
|
+
* The published rules (awqatsalah.com, "Tespit Kriterleri"):
|
|
8
|
+
* - Dhuhr five minutes after transit; Asr one shadow (Dhuhr when the
|
|
9
|
+
* shadow never forms), four minutes late; sunrise seven early,
|
|
10
|
+
* Maghrib seven late ("temkin").
|
|
11
|
+
* - Neither the day nor the night is shorter than five hours.
|
|
12
|
+
* - True Fajr at 18°, true Isha at 16°. Where the 18° dawn no longer
|
|
13
|
+
* forms, the share of the night the sharia night's third took on the
|
|
14
|
+
* last day it did is carried: Isha that share of the night after
|
|
15
|
+
* Maghrib, Fajr the same share scaled by 18/16 before sunrise.
|
|
16
|
+
* - The move from true times to the carried ones is gradual, starting
|
|
17
|
+
* twenty minutes before (Isha) or after (Fajr) the takdir.
|
|
18
|
+
*
|
|
19
|
+
* What the tables turn out to do with them, read off Diyanet's own tables
|
|
20
|
+
* for all 160 Swedish places, 2024–2027 (99.98 % of times on the printed
|
|
21
|
+
* minute, the rest a fraction of a second from the rounding point):
|
|
22
|
+
* - The sun is taken once a day, at 0h UT less 45 s: Meeus's mean
|
|
23
|
+
* elements and equation of the centre, the TRUE (geometric) longitude,
|
|
24
|
+
* the apparent obliquity (mean plus nutation), the equation of time as
|
|
25
|
+
* the mean longitude less the right ascension, 0.106 s later; and
|
|
26
|
+
* two small waves by the mean longitude the formula leaves out: a few
|
|
27
|
+
* hundredths of a second on the transit, a tenth of an arc-second on
|
|
28
|
+
* the declination.
|
|
29
|
+
* - Coordinates are kept to three decimals of a degree.
|
|
30
|
+
* - Asr that never forms is printed at Dhuhr's time.
|
|
31
|
+
* - The night a share is taken of is the day's own: 24 h less the
|
|
32
|
+
* printed day, sunrise to Maghrib.
|
|
33
|
+
* - The five-hour floors hold each end separately, 150 minutes from the
|
|
34
|
+
* printed Dhuhr or from the midnight after it. Where midsummer's
|
|
35
|
+
* night is floored at both ends (to within a minute), that night
|
|
36
|
+
* anchors the season, and the floored times never step back: before
|
|
37
|
+
* midsummer no sunrise earlier than midsummer's and a floored Maghrib
|
|
38
|
+
* no earlier than the day before; after it no sunrise earlier nor
|
|
39
|
+
* Maghrib later than on any day since midsummer — and Fajr and Isha
|
|
40
|
+
* carried the same way.
|
|
41
|
+
* - The gradual transition is a straight line across the days next to
|
|
42
|
+
* the gap on which the true time lies within twenty minutes of the
|
|
43
|
+
* takdir at the gap's edge: twenty minutes away at the far end, the
|
|
44
|
+
* takdir at the edge.
|
|
45
|
+
*
|
|
46
|
+
* Beyond Sweden the same code gives Diyanet's tables worldwide, read off
|
|
47
|
+
* them for places on six continents:
|
|
48
|
+
* - Where the dawn forms all summer but midsummer's true Isha (at 16°)
|
|
49
|
+
* falls later than the share carried from that night, midsummer is the
|
|
50
|
+
* takdir's day — a gap of one day, with its ramps (from about 44.4°
|
|
51
|
+
* north: Austria, central France, northern Bosnia).
|
|
52
|
+
* - Isha is printed at 16° in some countries and 17° in others; the
|
|
53
|
+
* high-latitude rules are worked at 16° either way (`ishaDeg`).
|
|
54
|
+
*
|
|
55
|
+
* Times are minutes past 0h UT of the date, a frame the clock changes
|
|
56
|
+
* cannot bend; `congressTimes` turns them into instants.
|
|
57
|
+
*/
|
|
58
|
+
/**
|
|
59
|
+
* Isha's depression: the Congress's 16° (Diyanet's in much of Europe,
|
|
60
|
+
* Russia, Central Asia, China and North America), or Diyanet's own 17°
|
|
61
|
+
* (elsewhere). The high-latitude rules are the Congress's at 16° either way;
|
|
62
|
+
* the angle sets only the true Isha printed.
|
|
63
|
+
*/
|
|
64
|
+
export declare const CONGRESS_ISHA_DEG = 16;
|
|
65
|
+
export declare const DIYANET_ISHA_DEG = 17;
|
|
66
|
+
export type CongressInstants = {
|
|
67
|
+
fajr: Date;
|
|
68
|
+
sunrise: Date;
|
|
69
|
+
dhuhr: Date;
|
|
70
|
+
asr: Date;
|
|
71
|
+
maghrib: Date;
|
|
72
|
+
isha: Date;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* The Congress method's times for a calendar date (year, month 0–11, day),
|
|
76
|
+
* as instants, unrounded. `asrShadow` is 1 for the standard Asr, 2 for the
|
|
77
|
+
* Hanafi one; the tables print the standard. `ishaDeg` is Isha's depression:
|
|
78
|
+
* 16° (the Congress's, Diyanet's in Europe and North America) or 17°
|
|
79
|
+
* (Diyanet's everywhere else).
|
|
80
|
+
*/
|
|
81
|
+
export declare function congressTimes(latitude: number, longitude: number, year: number, month: number, day: number, asrShadow?: number, ishaDeg?: number): CongressInstants;
|
|
82
|
+
/** For tests and the verification tool: the year's structure as the method sees it. */
|
|
83
|
+
export declare function congressYearInfo(latitude: number, longitude: number, year: number): {
|
|
84
|
+
gap: [string, string] | null;
|
|
85
|
+
ratio: number | null;
|
|
86
|
+
midsummerFloors: boolean;
|
|
87
|
+
};
|