Collection of islamic tools and utilities implemented in stb-style header only library
libmuslim
Collection of islamic tools and utilities implemented in stb-style header only library
README
libmuslim
An stb-style collection of single-header C libraries for Muslim applications.
Drop a header in, define its *_IMPLEMENTATION macro in one translation unit,
and you are done. C11 and C++17, no build system, no package manager.
| Header | Provides | Depends on |
|---|---|---|
prayertimes.h |
Prayer times, 21 calculation methods | <math.h> |
hijri.h |
Hijri calendar, crescent visibility models | <math.h> |
timezone.h |
IANA zone name → UTC offset, DST applied | OS timezone database |
prayertimes.h and hijri.h are independent and dependency-free.
timezone.h is optional and is the only header that touches the OS.
Quick start
#define PRAYERTIMES_IMPLEMENTATION
#include "prayertimes.h"
const MethodParams *params = method_params_get(CALC_KEMENAG);
struct PrayerTimes t = calculate_prayer_times(
2025, 11, 21, // date
-6.2851291, // latitude, negative = South
106.9814968, // longitude, positive = East
7.0, // UTC offset in hours
params);
char buf[16];
format_time_hm(t.fajr, buf, sizeof buf);
printf("Fajr: %s\n", buf); // Fajr: 04:05
gcc -std=c11 -Wall -Wextra -Wpedantic -O2 examples/prayertimes_example.c -lm -o example
prayertimes.h
Each method sets a Fajr angle, an Isha angle or fixed interval, a Maghrib offset, an Asr shadow factor (1 = Shafi'i, 2 = Hanafi), and an ihtiyat precautionary margin. Kemenag is the default.
| Key | Method | Region |
|---|---|---|
mwl |
Muslim World League | Europe, Far East |
makkah |
Umm al-Qura, Makkah | Arabian Peninsula |
isna |
ISNA | North America |
egypt |
Egyptian General Authority | Africa, Middle East |
karachi |
Univ. Islamic Sciences, Karachi | Pakistan, India, Bangladesh |
turkey |
Diyanet | Turkey |
singapore |
MUIS | Singapore |
jakim |
JAKIM | Malaysia |
kemenag |
KEMENAG (default) | Indonesia |
france |
UOIF | France |
russia |
Spiritual Administration | Russia |
dubai |
GAIAE | UAE |
qatar · kuwait · jordan · gulf |
Ministries of Awqaf | Gulf states |
tunisia · algeria · morocco |
Ministries of Religious Affairs | Maghreb |
portugal |
Comunidade Islâmica de Lisboa | Portugal |
moonsighting |
Moonsighting Committee | Worldwide |
const MethodParams *mwl = method_params_get(CALC_MWL);
CalcMethod m = method_from_string("isna"); // case-insensitive
Pass CALC_CUSTOM with your own angles for anything not listed.
To walk a date range without struct tm or mktime, and therefore without
local-time hazards, use the static inline day-number helpers:
for (long s = mt_days_from_civil(2026, 7, 1); s <= mt_days_from_civil(2026, 7, 31); s++) {
int y, m, d;
mt_civil_from_days(s, &y, &m, &d);
struct PrayerTimes t = calculate_prayer_times(y, m, d, lat, lon, tz, params);
}
Times are cross-checked against published timetables to within 1–2 minutes
depending on method. Those references are third-party calculators, not primary
authorities. See docs/KEMENAG_METHOD.md for the
worked mathematics.
hijri.h
The API is layered deliberately, and the layers mean different things:
HijriEveningParameters— explicit astronomical quantities for one evening at one location: sunset, moonset, conjunction, altitudes, both geocentric and topocentric elongation, Moon age, lag.HijriLocalPredicate— one threshold condition at one observer location.- Calendar functions — convert a Gregorian date to a Hijri date.
A local predicate is not a national or global authority decision. Real authorities combine calculation with geographic aggregation, actual sighting reports, and administrative rulings. Applications must add that themselves.
HijriLocation jakarta = {-6.2088, 106.8456, 8.0, "Jakarta"};
HijriDate date;
hijri_from_gregorian_with_local_predicate(
2026, 7, 27, &jakarta, HIJRI_PREDICATE_MABIMS_2021, &date);
hijri_umm_al_qura_from_gregorian(2026, 7, 27, &date); // Mecca-based, takes no location
Yallop and Odeh are graded visibility classifications, not calendar policies —
hijri_yallop_evaluate_evening() and hijri_odeh_evaluate_evening() return
best-time parameters, a score, and a zone. Turning a zone into a date is an
application policy you define.
Accuracy. The lunar position uses the full Meeus ch. 47 series. Measured against 24 JPL Horizons epochs spanning 1900–2100: 0.0051° in longitude, 0.0006° in latitude, 41.9 km in distance. Nutation and aberration are not applied, so these are geometric positions referred to the mean equinox of date. A calculated result is still not an observation, and nothing here decides religious validity.
timezone.h
prayertimes.htakes a fixed numeric UTC offset and has no notion of zones or DST — deliberately, since DST is a political rule rather than an astronomical one. For a DST-active date you must pass the adjusted offset yourself (1.0for London in summer,0.0in winter).
timezone.h will resolve it for you from the host OS timezone database:
#define MUSLIM_TIMEZONE_IMPLEMENTATION // exactly one translation unit
#include "timezone.h"
char zone[64];
get_system_timezone(zone, sizeof zone); // "Europe/London"
double tz = parse_timezone_offset(zone, time(NULL)); // DST applied
On a platform without a timezone database, keep supplying the offset yourself.
Building and tests
Everything compiles standalone. No build system.
for t in tests/test_prayertimes.c tests/test_hijri.c tests/test_moon_meeus.c tests/test_timezone.c; do
gcc -std=c11 -Wall -Wextra -Wpedantic -O2 "$t" -lm -o /tmp/t && /tmp/t || echo "FAIL $t"
done
tests/test_moon_meeus.c validates the lunar series against a vendored JPL
Horizons fixture, Meeus's own printed worked example, and published ΔT values.
tests/test_hijri.c covers calendar arithmetic, predicate thresholds, and a
longitude sweep asserting each observer's own local evening is used.
The research baseline is a generated artifact, committed so changes to it are visible in review:
gcc -std=c11 -Wall -Wextra -Wpedantic -O2 tests/hijri_research_probe.c -lm -o /tmp/probe
/tmp/probe > /tmp/baseline.csv
cmp /tmp/baseline.csv docs/research/hijri-2020-2025-baseline.csv
Any change to the ephemeris, the predicates, or the evening calculation will
break that cmp until the baseline is regenerated, and nothing in tests/
enforces it — so run it after touching those areas. No value in that CSV is
reference truth: it is produced by the library it is used to check, and its
nine-decimal Julian Days imply precision the underlying accuracy does not
support.
Sources, conventions, and fixture admission decisions are recorded in
docs/research/.
Documentation
docs/KEMENAG_METHOD.md— prayer-time mathematics (Indonesian)docs/INTERNATIONAL_METHODS.md— method parametersdocs/HIJRI_CALCULATIONS.md— Hijri calculationsdocs/METHOD_TOLERANCES.md— accuracy expectationsROADMAP.md— what is planned and what is deliberately not- Understanding Islamic Prayer Time Calculations
Contributing
Changes to calculation methods must be verified against a source, and the
source recorded. docs/research/hijri-2020-2025-sources.md shows the standard:
a fixture is admitted only when its value and its conventions are
unambiguous, and an unknown convention is recorded as a gap rather than guessed.
License
MIT. Copyright 2025 muslimtify-org.