- Architecture Overview
- Mathematical Algorithms
- Input Validation Strategy
- Error Handling
- Calculation Methods Details
- Performance Considerations
- Testing Strategy
The Prayer Times Library is designed with the following principles:
- Modularity: Core calculations separated from validation and error handling
- Robustness: Comprehensive input validation prevents incorrect calculations
- Type Safety: Extensive use of enums for method selection and error codes
- Clarity: Bilingual comments and documentation for international audience
- Efficiency: Minimal dependencies, optimized calculations
src/libpt.c and include/libpt.h
├── Public API
│ ├── get_prayer_times() - Main calculation function
│ ├── decimal_to_time() - Time format conversion
│ └── get_error_message() - Error message retrieval
├── Validation Layer
│ ├── validate_date() - Date validation
│ └── validate_coordinates() - Geographic validation
├── Calculation Engine
│ ├── sun_position() - Solar position computation
│ ├── compute_time() - Prayer time calculation
│ ├── compute_asr() - Asr-specific calculation
│ ├── equation_of_time() - Equation of time
│ └── sun_declination() - Solar declination
└── Utility Functions
├── deg2rad() / rad2deg() - Angle conversions
├── fix_angle() - Angle normalization
├── fix_hour() - Time normalization
└── get_julian_date() - Julian date calculation
Purpose: Convert calendar date to astronomical Julian Date number
Implementation: Uses the standard astronomical conversion formula:
// Input: Gregorian calendar date
// Process:
// 1. Adjust year/month for leap year calculations
// 2. Calculate day number from reference epoch (4713 BC)
// 3. Return fractional day number
// Formula components:
// a = floor(year / 100) // Century
// b = 2 - a + floor(a / 4) // Gregorian adjustment
// JD = floor(365.25 * (year + 4716)) + // Days in year
// floor(30.6001 * (month + 1)) + // Days in month
// day + b - 1524.5 // Day plus epoch correctionAccuracy: Accurate for dates 1900-2100 (outside range, accuracy degraded)
Purpose: Determine the sun's position for a given Julian Date
Process:
1. Calculate days from epoch (d = JD - 2451545.0)
- Reference epoch: J2000.0 (Jan 1, 2000)
2. Mean anomaly: g = 357.529° + 0.98560028° * d
- Describes sun's position in its orbit
3. Mean longitude: q = 280.459° + 0.98564736° * d
- Sun's ecliptic longitude
4. Apparent longitude: L = q + 1.915°*sin(g) + 0.020°*sin(2g)
- Adjusts for orbital eccentricity variations
5. Obliquity of ecliptic: ε = 23.439° - 0.00000036° * d
- Earth's axial tilt
6. Solar declination: δ = arcsin(sin(ε) * sin(L))
- Sun's angular position relative to celestial equator
7. Right ascension: RA = atan2(cos(ε)*sin(L), cos(L))
- Sun's angular position along celestial equator
8. Equation of time: EoT = q/15 - RA/15 (in hours)
- Correction for elliptical orbit and axial tilt
Accuracy: ±0.0006° (~2 minutes of arc) over 1900-2100
General Formula:
Prayer Time = Dhuhr ± arccos(sin(angle) / (cos(decl) * cos(lat)))
Where:
angle = Solar angle for specific prayer (e.g., 18° for Fajr)
decl = Solar declination
lat = Geographic latitude
Dhuhr = Solar noon time
Specific Prayer Times:
| Prayer | Angle | Formula | Notes |
|---|---|---|---|
| Fajr | -18° (or -15°, -19.5°) | Dhuhr - arccos(...) | Method-specific angles |
| Sunrise | -0.833° | Dhuhr - arccos(...) | Solar disk 0.833° below horizon |
| Dhuhr | 0° | 12 - EoT - lng/15 + tz | Solar noon |
| Asr | 1 or 2 | Depends on juristic method | Special calculation for shadow |
| Sunset | -0.833° | Dhuhr + arccos(...) | Mirror of sunrise |
| Maghrib | +0.05 | Sunset + 0.05 hours | ~3 minutes after sunset |
| Isha | -17° (or -15°, -17.5°) | Dhuhr + arccos(...) | Method-specific angles |
Standard Method (Shafi'i, Maliki, Hanbali):
Shadow length = 1 * object_height
angle = -arctan(1 / (1 + tan(|lat - decl|)))
Hanafi Method:
Shadow length = 2 * object_height
angle = -arctan(1 / (2 + tan(|lat - decl|)))
The negative angle indicates below the horizon mathematically.
Angle Normalization (0° - 360°):
// Ensures angle is in [0, 360)
angle = angle - 360.0 * floor(angle / 360.0)
if (angle < 0) angle += 360.0Hour Normalization (0:00 - 23:59):
// Ensures time is in [0, 24)
time = time - 24.0 * floor(time / 24.0)
if (time < 0) time += 24.0- Enums prevent invalid calculation methods
- Array size via TIMES_COUNT constant
- Prevents memory corruptionDate validation:
Year: 1900-2100 (astronomical algorithm precision)
Month: 1-12
Day: 1-31 (with month-specific max, leap year handling)
Coordinate validation:
Latitude: -90.0 to 90.0 degrees
Longitude: -180.0 to 180.0 degrees
Timezone: -12.0 to 14.0 hours
Special cases:
Polar regions (lat > 66°) - warning only
NULL output pointer - error- Leap year calculation for February
- Geographic coordinate realism
- Timezone range (UTC-12 to UTC+14)PT_ERR_INVALID_YEAR // Year outside 1900-2100
PT_ERR_INVALID_MONTH // Month outside 1-12
PT_ERR_INVALID_DAY // Day invalid for month (including leap years)
PT_ERR_INVALID_LATITUDE // Latitude outside -90 to 90
PT_ERR_INVALID_LONGITUDE // Longitude outside -180 to 180
PT_ERR_INVALID_TIMEZONE // Timezone outside -12 to 14
PT_ERR_NULL_OUTPUT // Output array pointer is NULL
PT_ERR_POLAR_REGION // High latitude (lat > 66°)// Early return on validation failure
if (validation_fails) return ERROR_CODE;
// Prevents cascading errors
// Ensures function never processes invalid input// English messages: Technical terminology
get_error_message(error, ERR_LANG_ENGLISH)
// Returns: "Invalid year (must be between 1900-2100)"
// Arabic messages: Clear Islamic context
get_error_message(error, ERR_LANG_ARABIC)
// Returns: "سنة غير صحيحة (يجب أن تكون بين 1900-2100)"Usage: Primary method in Saudi Arabia
Angles:
- Fajr: 18.5°
- Isha: 90 minutes after Maghrib (not angular)
Notes:
- Isha uses fixed offset instead of angle
- Designed for geographical latitude 21.4° (Mecca)
- May vary in other regions
Usage: International standard
Angles:
- Fajr: 18°
- Isha: 17°
Notes:
- More balanced than region-specific methods
- Works well globally
- Most scientifically accepted
Usage: North America
Angles:
- Fajr: 15°
- Isha: 15°
Notes:
- Adjusted for higher northern latitudes
- Accounts for extended twilight in summer
Usage: Egypt and surrounding regions
Angles:
- Fajr: 19.5°
- Isha: 17.5°
Notes:
- Officially used in Egypt
- Accounts for Mediterranean climate
Usage: Pakistan and South Asia
Angles:
- Fajr: 18°
- Isha: 18°
Notes:
- Designed for South Asian geography
- Used in Pakistan and neighboring regions
Time Complexity:
O(1) - All calculations are constant time
No loops or recursive calls
Fixed number of mathematical operations
Space Complexity:
O(1) - All parameters pass by value
Output array allocated by caller
No dynamic memory allocation
-
Precomputed Constants:
- PI: Full precision constant
- Method-specific angles: Switch statement, not lookup table
-
Efficient Math Functions:
- Uses optimized libc sin(), cos(), atan2()
- Minimal trigonometric calculations
- Avoids expensive operations like sqrt
-
Early Returns:
- Validation errors return immediately
- Prevents unnecessary computations
Single prayer time calculation: ~1 microsecond
All 7 prayer times: ~7 microseconds
Test suite (38 tests): ~50 milliseconds
Purpose: Ensure input validation works correctly
Coverage:
- Invalid year (too old: 1800)
- Invalid year (too new: 2150)
- Invalid month (0)
- Invalid month (13)
- Invalid day (32)
- Invalid latitude (95)
- Invalid latitude (-95)
- Invalid longitude (185)
- Invalid timezone (20)
- NULL output pointerPurpose: Verify prayer time calculations
Coverage:
- Algiers, Algeria (MWL method)
- Time range verification
- Time ordering (Fajr < Sunrise < Dhuhr < Asr < Sunset < Maghrib < Isha)
- Sunrise/sunset symmetry
- Maghrib proximity to sunsetPurpose: Verify different methods produce different results
Coverage:
- Umm Al-Qura vs. MWL vs. ISNA
- Method parameter differences
- Consistency across runsPurpose: Verify juristic method differences
Coverage:
- Standard method (Shafi'i)
- Hanafi method (later Asr time expected)
- Asr shadow calculationPurpose: Verify helper functions
Coverage:
- decimal_to_time(5.5) -> 5:30
- decimal_to_time(23.75) -> 23:45
- decimal_to_time(14.25) -> 14:15
- decimal_to_time(0.1) -> 0:06Purpose: Test in diverse geographic locations
Coverage:
- London (51.5°N) - high latitude
- Cairo (30.04°N) - medium latitude
- Jakarta (-6.2°S) - equatorial
- Sydney (-33.9°S) - southern hemispherePurpose: Verify error messages in both languages
Coverage:
- English messages (all error types)
- Arabic messages (all error types)
- Message completeness and clarity# Build and run all tests
make run-test
# Output includes:
- Individual test results (✓ or ✗)
- Test statistics (total, passed, failed)
- Pass rate percentage
- Detailed error information if failures occur✓ PASS - Test completed successfully
✗ FAIL - Test failed with error details
Summary:
Total Tests: 38
Passed: 38 ✓
Failed: 0 ✗
Pass Rate: 100.0%
Status: 🎉 All tests passed!
- Very High Accuracy: ±1 minute for latitudes -60° to +60°, years 1900-2100
- Good Accuracy: ±2-3 minutes for latitudes -66° to +66°, years 1900-2100
- Limited Accuracy: ±5+ minutes for polar regions, before 1900 or after 2100
-
Polar Regions (lat > 66°):
- Solar angles may exceed valid range
- Days with no sunrise/sunset (polar night/day)
- Results become unreliable
-
Year Range (1900-2100):
- Optimal precision within this range
- Extrapolation beyond range decreases accuracy
- Astronomical constants may need updates for very distant dates
-
Timezone Handling:
- Supports standard timezone offsets (-12 to +14)
- Does not handle historical timezone changes
- Does not account for daylight saving time (user responsibility)
-
Geographic Precision:
- Uses spherical Earth model
- Ellipsoid corrections not applied
- Suitable for most practical applications
-Wall # Enable all common warnings
-Wextra # Enable extra warnings
-fPIC # Generate position-independent code (for shared library)
-lm # Link math library (for trigonometric functions)
-g # Include debug symbols (debug builds only)
-O0 # No optimization (debug builds only)bin/libpt.so # Shared library
bin/test_libpt # Executable test suite
bin/prayer_times_demo # Example program
# Compile your program with library
gcc -o myprogram myprogram.c -o libpt.so -lm
# Or compile directly with source
gcc -o myprogram myprogram.c src/libpt.c -lm
# Run with shared library in LD_LIBRARY_PATH
export LD_LIBRARY_PATH=./bin:$LD_LIBRARY_PATH
./myprogram-
Comments:
- Use bilingual comments (Arabic and English)
- Document algorithm, not obvious code
- Include @brief tags for functions
-
Variable Naming:
- Clear, descriptive names
- Use underscores for multi-word names
- Avoid single-letter variables (except loop counters)
-
Testing:
- Add tests for new features
- Ensure all tests pass before committing
- Document test purpose and coverage
Document Version: 1.0 Last Updated: 2026-06-16 Audience: Developers, Contributors, Advanced Users