mihrab-methods 1.3.2__tar.gz
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.
- mihrab_methods-1.3.2/PKG-INFO +77 -0
- mihrab_methods-1.3.2/README.md +60 -0
- mihrab_methods-1.3.2/mihrab_methods/__init__.py +7 -0
- mihrab_methods-1.3.2/mihrab_methods/api.py +162 -0
- mihrab_methods-1.3.2/mihrab_methods/data/certification.json +154 -0
- mihrab_methods-1.3.2/mihrab_methods/data/corrections/algeria.json +784 -0
- mihrab_methods-1.3.2/mihrab_methods/data/corrections/diyanet.json +18899 -0
- mihrab_methods-1.3.2/mihrab_methods/data/corrections/indonesia.json +606 -0
- mihrab_methods-1.3.2/mihrab_methods/data/corrections/morocco.json +280 -0
- mihrab_methods-1.3.2/mihrab_methods/data/corrections/sweden.json +516 -0
- mihrab_methods-1.3.2/mihrab_methods/data/corrections/turkiyetakvimi.json +1886 -0
- mihrab_methods-1.3.2/mihrab_methods/methods.py +638 -0
- mihrab_methods-1.3.2/mihrab_methods/sun.py +234 -0
- mihrab_methods-1.3.2/mihrab_methods.egg-info/PKG-INFO +77 -0
- mihrab_methods-1.3.2/mihrab_methods.egg-info/SOURCES.txt +18 -0
- mihrab_methods-1.3.2/mihrab_methods.egg-info/dependency_links.txt +1 -0
- mihrab_methods-1.3.2/mihrab_methods.egg-info/requires.txt +3 -0
- mihrab_methods-1.3.2/mihrab_methods.egg-info/top_level.txt +1 -0
- mihrab_methods-1.3.2/pyproject.toml +31 -0
- mihrab_methods-1.3.2/setup.cfg +4 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mihrab-methods
|
|
3
|
+
Version: 1.3.2
|
|
4
|
+
Summary: The prayer-time authorities' own calculation methods, each reproducing its published timetable to the minute: a port of the mihrab-methods library.
|
|
5
|
+
Author: Hassan El Ghamri
|
|
6
|
+
License: MPL-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/MihrabHQ/mihrab-methods
|
|
8
|
+
Project-URL: Documentation, https://github.com/MihrabHQ/mihrab-methods/tree/main/ports/python
|
|
9
|
+
Project-URL: Changelog, https://github.com/MihrabHQ/mihrab-methods/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: prayer-times,salah,adhan,islam,diyanet,mihrab
|
|
11
|
+
Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Religion
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: tzdata; platform_system == "Windows"
|
|
17
|
+
|
|
18
|
+
# mihrab-methods in Python
|
|
19
|
+
|
|
20
|
+
The methods of [mihrab-methods](../../README.md) — Sweden, Diyanet,
|
|
21
|
+
Morocco, Algeria, Indonesia and Türkiye Takvimi — in plain Python, with no dependencies
|
|
22
|
+
beyond the standard library (Python 3.9 or later, for `zoneinfo`).
|
|
23
|
+
|
|
24
|
+
The TypeScript library is the reference. This port follows it line for
|
|
25
|
+
line, is held to `test/vectors.json`, and names the method revisions it
|
|
26
|
+
reproduces in `mihrab_methods.REVISIONS`. A correction list belongs to one
|
|
27
|
+
revision: when a method's revision is raised in the library, this port is
|
|
28
|
+
behind until it is raised here too.
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
pip install mihrab-methods
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The package carries the correction lists of its release; a version has the
|
|
35
|
+
same number as the npm package it was built with.
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from mihrab_methods import load_corrections, times_for
|
|
39
|
+
|
|
40
|
+
lists = load_corrections() # the package's own; or a directory laid out as data/corrections
|
|
41
|
+
stockholm = {'authority': 'sweden', 'lat': 59.33, 'lon': 18.034, 'tz': 'Europe/Stockholm'}
|
|
42
|
+
day = times_for(stockholm, '2026-11-12', lists['sweden'])
|
|
43
|
+
print(day['printed']) # the six times as 'HH:MM' on the clock the table prints
|
|
44
|
+
print(day['instants']) # the same six times as timezone-aware datetimes
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
A place is a dict shaped like the library's `Place`: `authority`, `lat`,
|
|
48
|
+
`lon`, `tz`, and the fields a list gives some of its places (`ishaDeg`,
|
|
49
|
+
`clock`, `prayerPoints`, `dipDeg`, `dipMaghribDeg`, `highland`,
|
|
50
|
+
`twilightDip`, `afternoon`, `temkin`). The places themselves are in `data/places/`;
|
|
51
|
+
use the coordinates exactly as the list has them, since the correction
|
|
52
|
+
lists are looked up by them.
|
|
53
|
+
|
|
54
|
+
Without a correction list `times_for` gives the bare method: within a
|
|
55
|
+
minute of the full answer on the days a list has an entry for, the same on
|
|
56
|
+
every other day.
|
|
57
|
+
|
|
58
|
+
## Check
|
|
59
|
+
|
|
60
|
+
From the repository root:
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
python3 ports/python/test_vectors.py
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The zone offsets come from the machine's time-zone database, as they do in
|
|
67
|
+
the library; two machines with different editions of it can differ on a
|
|
68
|
+
zone whose rules changed between them.
|
|
69
|
+
|
|
70
|
+
## What is where
|
|
71
|
+
|
|
72
|
+
| File | What |
|
|
73
|
+
| --- | --- |
|
|
74
|
+
| `mihrab_methods/sun.py` | The three positions of the sun the methods use |
|
|
75
|
+
| `mihrab_methods/methods.py` | The methods: the Congress method (Sweden, Diyanet), Morocco, Algeria, Indonesia, Türkiye Takvimi |
|
|
76
|
+
| `mihrab_methods/api.py` | Place and date in, the day out: clock, correction list, printing |
|
|
77
|
+
| `test_vectors.py` | Holds the port to `test/vectors.json` |
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# mihrab-methods in Python
|
|
2
|
+
|
|
3
|
+
The methods of [mihrab-methods](../../README.md) — Sweden, Diyanet,
|
|
4
|
+
Morocco, Algeria, Indonesia and Türkiye Takvimi — in plain Python, with no dependencies
|
|
5
|
+
beyond the standard library (Python 3.9 or later, for `zoneinfo`).
|
|
6
|
+
|
|
7
|
+
The TypeScript library is the reference. This port follows it line for
|
|
8
|
+
line, is held to `test/vectors.json`, and names the method revisions it
|
|
9
|
+
reproduces in `mihrab_methods.REVISIONS`. A correction list belongs to one
|
|
10
|
+
revision: when a method's revision is raised in the library, this port is
|
|
11
|
+
behind until it is raised here too.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
pip install mihrab-methods
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The package carries the correction lists of its release; a version has the
|
|
18
|
+
same number as the npm package it was built with.
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from mihrab_methods import load_corrections, times_for
|
|
22
|
+
|
|
23
|
+
lists = load_corrections() # the package's own; or a directory laid out as data/corrections
|
|
24
|
+
stockholm = {'authority': 'sweden', 'lat': 59.33, 'lon': 18.034, 'tz': 'Europe/Stockholm'}
|
|
25
|
+
day = times_for(stockholm, '2026-11-12', lists['sweden'])
|
|
26
|
+
print(day['printed']) # the six times as 'HH:MM' on the clock the table prints
|
|
27
|
+
print(day['instants']) # the same six times as timezone-aware datetimes
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
A place is a dict shaped like the library's `Place`: `authority`, `lat`,
|
|
31
|
+
`lon`, `tz`, and the fields a list gives some of its places (`ishaDeg`,
|
|
32
|
+
`clock`, `prayerPoints`, `dipDeg`, `dipMaghribDeg`, `highland`,
|
|
33
|
+
`twilightDip`, `afternoon`, `temkin`). The places themselves are in `data/places/`;
|
|
34
|
+
use the coordinates exactly as the list has them, since the correction
|
|
35
|
+
lists are looked up by them.
|
|
36
|
+
|
|
37
|
+
Without a correction list `times_for` gives the bare method: within a
|
|
38
|
+
minute of the full answer on the days a list has an entry for, the same on
|
|
39
|
+
every other day.
|
|
40
|
+
|
|
41
|
+
## Check
|
|
42
|
+
|
|
43
|
+
From the repository root:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
python3 ports/python/test_vectors.py
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The zone offsets come from the machine's time-zone database, as they do in
|
|
50
|
+
the library; two machines with different editions of it can differ on a
|
|
51
|
+
zone whose rules changed between them.
|
|
52
|
+
|
|
53
|
+
## What is where
|
|
54
|
+
|
|
55
|
+
| File | What |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| `mihrab_methods/sun.py` | The three positions of the sun the methods use |
|
|
58
|
+
| `mihrab_methods/methods.py` | The methods: the Congress method (Sweden, Diyanet), Morocco, Algeria, Indonesia, Türkiye Takvimi |
|
|
59
|
+
| `mihrab_methods/api.py` | Place and date in, the day out: clock, correction list, printing |
|
|
60
|
+
| `test_vectors.py` | Holds the port to `test/vectors.json` |
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""mihrab-methods in Python: the prayer-time methods of five authorities,
|
|
2
|
+
ported from the TypeScript library and held to its test vectors."""
|
|
3
|
+
from .api import (PRAYERS, REVISIONS, CorrectionList, clock_offset_at, load_corrections, minutes_for, place_clock_at,
|
|
4
|
+
point_key, printed, times_for)
|
|
5
|
+
|
|
6
|
+
__all__ = ['PRAYERS', 'REVISIONS', 'CorrectionList', 'clock_offset_at', 'load_corrections', 'minutes_for',
|
|
7
|
+
'place_clock_at', 'point_key', 'printed', 'times_for']
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""A place and a date in, the day's six times out: the authority's method,
|
|
2
|
+
then its correction list — what `timesFor` does in the TypeScript library.
|
|
3
|
+
|
|
4
|
+
A place is a dict shaped like the library's `Place` (see docs/api.md):
|
|
5
|
+
`authority`, `lat`, `lon`, `tz`, and where the list has them `ishaDeg`,
|
|
6
|
+
`clock`, `prayerPoints`, `dipDeg`, `dipMaghribDeg`, `highland`,
|
|
7
|
+
`twilightDip`, `afternoon`, `temkin`.
|
|
8
|
+
"""
|
|
9
|
+
import datetime
|
|
10
|
+
import json
|
|
11
|
+
import math
|
|
12
|
+
import os
|
|
13
|
+
from decimal import ROUND_HALF_UP, Decimal
|
|
14
|
+
from zoneinfo import ZoneInfo
|
|
15
|
+
|
|
16
|
+
from . import methods
|
|
17
|
+
|
|
18
|
+
PRAYERS = ('fajr', 'sunrise', 'dhuhr', 'asr', 'maghrib', 'isha')
|
|
19
|
+
#: The method revisions this port reproduces. A correction list belongs to one revision.
|
|
20
|
+
REVISIONS = {'sweden': 1, 'diyanet': 1, 'morocco': 2, 'algeria': 1, 'indonesia': 2, 'turkiyetakvimi': 1}
|
|
21
|
+
|
|
22
|
+
_UTC = datetime.timezone.utc
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _to_fixed(x):
|
|
26
|
+
"""A coordinate to three decimals, as JavaScript's toFixed(3) writes it:
|
|
27
|
+
the binary value's exact decimal expansion, ties away from zero."""
|
|
28
|
+
return str(Decimal(float(x) + 0.0).quantize(Decimal('0.001'), rounding=ROUND_HALF_UP)) # + 0.0: -0 is written 0.000
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def point_key(lat, lon):
|
|
32
|
+
return '%s,%s' % (_to_fixed(lat), _to_fixed(lon))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CorrectionList:
|
|
36
|
+
"""data/corrections/<authority>.json, indexed: point -> date -> {prayer: minutes}."""
|
|
37
|
+
|
|
38
|
+
def __init__(self, source):
|
|
39
|
+
self.source = source
|
|
40
|
+
self._index = {}
|
|
41
|
+
for point, entries in source.get('points', {}).items():
|
|
42
|
+
by_date = self._index.setdefault(point, {})
|
|
43
|
+
for e in entries:
|
|
44
|
+
date, key, step = e.split(' ')
|
|
45
|
+
by_date.setdefault(date, {})[key] = int(step)
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def load(cls, path):
|
|
49
|
+
with open(path, encoding='utf-8') as f:
|
|
50
|
+
return cls(json.load(f))
|
|
51
|
+
|
|
52
|
+
def correction(self, lat, lon, date):
|
|
53
|
+
return self._index.get(point_key(lat, lon), {}).get(date)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def clock_offset_at(tz, year, month0, day):
|
|
57
|
+
"""Minutes east of UTC that a zone keeps at noon UTC of a date."""
|
|
58
|
+
at = datetime.datetime(year, month0 + 1, 1, 12, tzinfo=_UTC) + datetime.timedelta(days=day - 1)
|
|
59
|
+
return round(at.astimezone(ZoneInfo(tz)).utcoffset().total_seconds() / 60)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def place_clock_at(place, year, month0, day):
|
|
63
|
+
"""The clock a place's table prints a date in: its own where it has one, else its zone's."""
|
|
64
|
+
clock = place.get('clock')
|
|
65
|
+
if clock:
|
|
66
|
+
date = '%04d-%02d-%02d' % (year, month0 + 1, day)
|
|
67
|
+
off = clock[0][1]
|
|
68
|
+
for start, o in clock:
|
|
69
|
+
if start <= date:
|
|
70
|
+
off = o
|
|
71
|
+
return off
|
|
72
|
+
return clock_offset_at(place['tz'], year, month0, day)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _congress(place, year, month0, day, asr_shadow):
|
|
76
|
+
clock = place_clock_at(place, year, month0, day)
|
|
77
|
+
isha_deg = place.get('ishaDeg', methods.CONGRESS_ISHA_DEG)
|
|
78
|
+
pts_by_year = place.get('prayerPoints')
|
|
79
|
+
if pts_by_year:
|
|
80
|
+
years = sorted(int(y) for y in pts_by_year)
|
|
81
|
+
best = years[0]
|
|
82
|
+
for y in years:
|
|
83
|
+
if abs(y - year) < abs(best - year):
|
|
84
|
+
best = y
|
|
85
|
+
pts = pts_by_year[str(best)]
|
|
86
|
+
raw = {k: methods.congress_minutes(pts[i][0], pts[i][1], year, month0, day, asr_shadow, isha_deg, clock)[k]
|
|
87
|
+
for i, k in enumerate(PRAYERS)}
|
|
88
|
+
else:
|
|
89
|
+
raw = methods.congress_minutes(place['lat'], place['lon'], year, month0, day, asr_shadow, isha_deg, clock)
|
|
90
|
+
# the library carries an instant in whole milliseconds, then rounds it to the minute
|
|
91
|
+
return {k: math.floor(math.trunc(v * 60000) / 60000 + 0.5) for k, v in raw.items()}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def minutes_for(place, date, corrections=None, asr_shadow=1):
|
|
95
|
+
"""Minutes past 00:00 UT of `date` ('YYYY-MM-DD') for the six times, or None where the method gives none."""
|
|
96
|
+
year, month, day = (int(p) for p in date.split('-'))
|
|
97
|
+
month0 = month - 1
|
|
98
|
+
a = place['authority']
|
|
99
|
+
if a in ('sweden', 'diyanet'):
|
|
100
|
+
t = _congress(place, year, month0, day, asr_shadow)
|
|
101
|
+
elif a == 'morocco':
|
|
102
|
+
t = methods.morocco_minutes(place['lat'], place['lon'], year, month0, day, place.get('dipDeg'), asr_shadow,
|
|
103
|
+
place.get('dipMaghribDeg'))
|
|
104
|
+
elif a == 'algeria':
|
|
105
|
+
t = methods.algeria_minutes(place['lat'], place['lon'], year, month0, day, asr_shadow)
|
|
106
|
+
elif a == 'indonesia':
|
|
107
|
+
t = methods.kemenag_minutes(place['lat'], place['lon'], year, month0, day, bool(place.get('highland')),
|
|
108
|
+
bool(place.get('twilightDip')), asr_shadow, place.get('afternoon'))
|
|
109
|
+
elif a == 'turkiyetakvimi':
|
|
110
|
+
t = methods.takvim_minutes(place['lat'], place['lon'], year, month0, day, place.get('temkin'), asr_shadow)
|
|
111
|
+
else:
|
|
112
|
+
raise ValueError('unknown authority: %r' % (a,))
|
|
113
|
+
if t is None:
|
|
114
|
+
return None
|
|
115
|
+
c = corrections.correction(place['lat'], place['lon'], date) if corrections else None
|
|
116
|
+
if c:
|
|
117
|
+
for k, step in c.items():
|
|
118
|
+
if not (k == 'asr' and asr_shadow != 1): # the lists are of the standard Asr only
|
|
119
|
+
t[k] += step
|
|
120
|
+
return t
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def printed(minutes, offset_minutes):
|
|
124
|
+
"""'HH:MM' of a time on a clock, as a table prints it."""
|
|
125
|
+
m = (minutes + offset_minutes) % 1440
|
|
126
|
+
return '%02d:%02d' % (m // 60, m % 60)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def times_for(place, date, corrections=None, asr_shadow=1):
|
|
130
|
+
"""The day as a table prints it: {'clock': minutes east of UTC, 'printed': {...}, 'instants': {...}} or None.
|
|
131
|
+
|
|
132
|
+
`corrections` is the authority's CorrectionList; without it the times are the bare method's,
|
|
133
|
+
which is the published table to within the list's few minutes, not on every one.
|
|
134
|
+
"""
|
|
135
|
+
t = minutes_for(place, date, corrections, asr_shadow)
|
|
136
|
+
if t is None:
|
|
137
|
+
return None
|
|
138
|
+
year, month, day = (int(p) for p in date.split('-'))
|
|
139
|
+
off = place_clock_at(place, year, month - 1, day)
|
|
140
|
+
start = datetime.datetime(year, month, day, tzinfo=_UTC)
|
|
141
|
+
return {
|
|
142
|
+
'clock': off,
|
|
143
|
+
'printed': {k: printed(t[k], off) for k in PRAYERS},
|
|
144
|
+
'instants': {k: start + datetime.timedelta(minutes=t[k]) for k in PRAYERS},
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
#: The lists the installed package carries (those of its release); absent in a source checkout.
|
|
149
|
+
BUNDLED_CORRECTIONS = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'corrections')
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def load_corrections(directory=None):
|
|
153
|
+
"""Every list in a directory laid out as the repository's data/corrections;
|
|
154
|
+
with no directory, the lists the installed package carries."""
|
|
155
|
+
if directory is None:
|
|
156
|
+
directory = BUNDLED_CORRECTIONS
|
|
157
|
+
out = {}
|
|
158
|
+
for a in REVISIONS:
|
|
159
|
+
p = os.path.join(directory, a + '.json')
|
|
160
|
+
if os.path.exists(p):
|
|
161
|
+
out[a] = CorrectionList.load(p)
|
|
162
|
+
return out
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sweden": {
|
|
3
|
+
"certified": true,
|
|
4
|
+
"checkedAt": "2026-11-09",
|
|
5
|
+
"places": 108,
|
|
6
|
+
"checks": [
|
|
7
|
+
{
|
|
8
|
+
"tables": "Sweden — Islamiska Förbundet’s tables",
|
|
9
|
+
"places": 107,
|
|
10
|
+
"times": 63114,
|
|
11
|
+
"off": 0,
|
|
12
|
+
"offWithoutCorrections": 20,
|
|
13
|
+
"from": "2026-10-11",
|
|
14
|
+
"to": "2027-12-14",
|
|
15
|
+
"setAside": {
|
|
16
|
+
"misplaced": [],
|
|
17
|
+
"sourceFaults": 35491,
|
|
18
|
+
"copiedRows": 696
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"tables": "Sweden — Diyanet’s own tables",
|
|
23
|
+
"places": 159,
|
|
24
|
+
"times": 1393794,
|
|
25
|
+
"off": 0,
|
|
26
|
+
"offWithoutCorrections": 259,
|
|
27
|
+
"from": "2024-01-01",
|
|
28
|
+
"to": "2027-12-31"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"corrections": {
|
|
32
|
+
"from": "2024-01-01",
|
|
33
|
+
"to": "2027-12-31",
|
|
34
|
+
"entries": 270,
|
|
35
|
+
"sha256": "173d7145b5ec917882f8ac9890dd1fa5f3143bd714eb540482861bf8a6bac660"
|
|
36
|
+
},
|
|
37
|
+
"revision": 1
|
|
38
|
+
},
|
|
39
|
+
"diyanet": {
|
|
40
|
+
"certified": true,
|
|
41
|
+
"checkedAt": "2026-11-11",
|
|
42
|
+
"places": 8318,
|
|
43
|
+
"checks": [
|
|
44
|
+
{
|
|
45
|
+
"tables": "Diyanet — its tables worldwide",
|
|
46
|
+
"places": 8318,
|
|
47
|
+
"times": 71630078,
|
|
48
|
+
"off": 0,
|
|
49
|
+
"offWithoutCorrections": 9368,
|
|
50
|
+
"from": "2024-01-01",
|
|
51
|
+
"to": "2027-12-31"
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"corrections": {
|
|
55
|
+
"from": "2024-01-01",
|
|
56
|
+
"to": "2027-12-31",
|
|
57
|
+
"entries": 9357,
|
|
58
|
+
"sha256": "a8c6a7305611f8dcedc04a64efb8dd150d9a588c2b3ac3391bfb776d70a2ec83"
|
|
59
|
+
},
|
|
60
|
+
"revision": 1
|
|
61
|
+
},
|
|
62
|
+
"morocco": {
|
|
63
|
+
"certified": true,
|
|
64
|
+
"checkedAt": "2026-11-11",
|
|
65
|
+
"places": 164,
|
|
66
|
+
"checks": [
|
|
67
|
+
{
|
|
68
|
+
"tables": "Morocco — Habous",
|
|
69
|
+
"places": 164,
|
|
70
|
+
"times": 94350,
|
|
71
|
+
"off": 0,
|
|
72
|
+
"offWithoutCorrections": 114,
|
|
73
|
+
"from": "2026-08-27",
|
|
74
|
+
"to": "2026-11-30"
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"corrections": {
|
|
78
|
+
"from": "2026-08-27",
|
|
79
|
+
"to": "2026-11-30",
|
|
80
|
+
"entries": 114,
|
|
81
|
+
"sha256": "2ae7161a7164f7ccebf1aa9f81628a810ce8fdd337e0645907e6c58d0be6aae9"
|
|
82
|
+
},
|
|
83
|
+
"revision": 2
|
|
84
|
+
},
|
|
85
|
+
"algeria": {
|
|
86
|
+
"certified": true,
|
|
87
|
+
"checkedAt": "2026-11-09",
|
|
88
|
+
"places": 68,
|
|
89
|
+
"checks": [
|
|
90
|
+
{
|
|
91
|
+
"tables": "Algeria — Ministry of Religious Affairs",
|
|
92
|
+
"places": 68,
|
|
93
|
+
"times": 101184,
|
|
94
|
+
"off": 0,
|
|
95
|
+
"offWithoutCorrections": 642,
|
|
96
|
+
"from": "2026-10-01",
|
|
97
|
+
"to": "2027-06-05"
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"corrections": {
|
|
101
|
+
"from": "2026-10-01",
|
|
102
|
+
"to": "2027-06-05",
|
|
103
|
+
"entries": 642,
|
|
104
|
+
"sha256": "f8d227cdd88aabe5bcd1775ec0324abfdae07a8a3986fdd19816337c2d4ab3ca"
|
|
105
|
+
},
|
|
106
|
+
"revision": 1
|
|
107
|
+
},
|
|
108
|
+
"indonesia": {
|
|
109
|
+
"certified": true,
|
|
110
|
+
"checkedAt": "2026-11-11",
|
|
111
|
+
"places": 517,
|
|
112
|
+
"checks": [
|
|
113
|
+
{
|
|
114
|
+
"tables": "Indonesia — Kemenag",
|
|
115
|
+
"places": 517,
|
|
116
|
+
"times": 362934,
|
|
117
|
+
"off": 0,
|
|
118
|
+
"offWithoutCorrections": 234,
|
|
119
|
+
"from": "2026-10-07",
|
|
120
|
+
"to": "2027-01-31"
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"corrections": {
|
|
124
|
+
"from": "2026-10-07",
|
|
125
|
+
"to": "2027-01-31",
|
|
126
|
+
"entries": 234,
|
|
127
|
+
"sha256": "a3f1c30576ddddbfda6cadabe442e1bcf3fb476b018b269d7d4783edd4e39d03"
|
|
128
|
+
},
|
|
129
|
+
"revision": 2
|
|
130
|
+
},
|
|
131
|
+
"turkiyetakvimi": {
|
|
132
|
+
"certified": true,
|
|
133
|
+
"checkedAt": "2026-11-11",
|
|
134
|
+
"places": 821,
|
|
135
|
+
"checks": [
|
|
136
|
+
{
|
|
137
|
+
"tables": "Türkiye Takvimi — its cities’ years",
|
|
138
|
+
"places": 821,
|
|
139
|
+
"times": 1812768,
|
|
140
|
+
"off": 0,
|
|
141
|
+
"offWithoutCorrections": 860,
|
|
142
|
+
"from": "2025-12-31",
|
|
143
|
+
"to": "2027-01-02"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"corrections": {
|
|
147
|
+
"from": "2025-12-31",
|
|
148
|
+
"to": "2027-01-02",
|
|
149
|
+
"entries": 860,
|
|
150
|
+
"sha256": "edf5bd37ccd06dbcb87300a6c943353adb624a545ff6ea416a8f89715713d7bd"
|
|
151
|
+
},
|
|
152
|
+
"revision": 1
|
|
153
|
+
}
|
|
154
|
+
}
|