Project detail
Avatar muslimtify-org

muslimtify-org/

libmuslim

Collection of islamic tools and utilities implemented in stb-style header only library

C ★ 4 ⑂ 1 Update 30 Jul 2026
C

muslimtify-org/

libmuslim

Collection of islamic tools and utilities implemented in stb-style header only library


★ 4 ⑂ 1 30 Jul 2026 Live ↗

README

GitHub ↗

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.h takes 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.0 for London in summer, 0.0 in 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

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.