hijri_plus 0.1.0 copy "hijri_plus: ^0.1.0" to clipboard
hijri_plus: ^0.1.0 copied to clipboard

Offline-first Umm al-Qura Hijri conversion with auditable corrections and optional crescent forecasts.

hijri_plus #

hijri_plus is an offline-first, date-only Umm al-Qura Hijri calendar for Dart. It resolves a month start in this exact order:

  1. manual per-month override;
  2. cached, validated remote verified start;
  3. embedded Umm al-Qura table.

Crescent visibility is forecast information only. It never changes a calendar conversion, a cached verified start, or a manual override.

Range and guarantees #

The embedded table covers AH 1356 through AH 1500. With no whole-calendar adjustment, that is Gregorian 1937-03-14 through 2077-11-16 inclusive. Requests outside that range throw UnsupportedCalendarDateError; the package does not silently extrapolate and intentionally has no pre-1937 support.

The embedded table includes these AH 1446 month starts:

Hijri month start Gregorian date
1 Jumada I 1446 2024-11-03
1 Jumada II 1446 2024-12-02
1 Rajab 1446 2025-01-01

Jumada I 1446 is 29 days and Jumada II is 30 days. Manual and verified starts are validated against their neighbouring month boundaries.

GregorianDate is a civil date without a time zone. GregorianDate.fromDateTime and toHijriDateTime copy a DateTime's displayed year/month/day fields; they never change its instant to a different time zone.

Offline quick start #

import 'package:hijri_plus/hijri_plus.dart';

final calendar = UmmAlQuraCalendar();
final result = calendar.toHijri(GregorianDate(2024, 11, 3));

print(result.date); // 1 Jumada I 1446 AH
print(result.date.format('dd/mm/yyyy')); // 01/05/1446
print(result.source); // CalendarSource.embedded

final civil = calendar.toGregorian(HijriDate(1446, 6, 1));
print(civil.date); // 2024-12-02

Numeric formatting supports d, dd, m, mm, yy, and yyyy. For example, HijriDate(1446, 2, 1).format('dd/mm/yyyy') returns 01/02/1446.

Manual calibration #

For a reversible display adjustment, use one of the deliberately limited DayAdjustment values. plusOne means the displayed Hijri date is one day ahead of the resolved calendar; conversion remains inverse-consistent. It does not mutate the official embedded table.

final calendar = UmmAlQuraCalendar(dayAdjustment: DayAdjustment.plusOne);
final calibration = calendar.exportCalibration();
// Persist calibration.dayAdjustment.days and the override values using your
// application's storage format.

To define a specific month start, use a semantic override. It keeps the configuration explicit and validates both neighbouring month lengths.

calendar.setManualMonthStart(
  ManualMonthOverride(
    month: HijriMonth(1446, 6),
    startsOn: GregorianDate(2024, 12, 2),
  ),
);

final overrides = calendar.exportManualMonthOverrides();
// Later: calendar.importManualMonthOverrides(overrides);

Use replaceManualMonthOverrides, clearManualMonthStart, or clearManualMonthOverrides to manage the instance-owned set. Multiple calendar instances can safely use independent policies.

Opt-in verified starts #

Online verification is disabled by default. The package starts no background timer or scheduler: the host chooses whether to configure a provider, when to refresh it, and where to persist the resulting cache.

final calendar = UmmAlQuraCalendar(
  verificationSettings: const VerificationSettings(
    enabled: true,
    refreshInterval: Duration(days: 7),
  ),
  verifiedMonthStartProvider: myAuthorisedProvider,
  verifiedCalendarStore: myDurableStore,
);

await calendar.loadCachedVerification(); // No network request.
await calendar.refreshIfDue(DateTime.now().toUtc());
await calendar.forceRefreshVerification(DateTime.now().toUtc());

Implement VerifiedMonthStartProvider.fetch with your own backend or another recognised local authority, or use the included official Today provider. The default in-memory store can be replaced with durable application storage. Every supplied start and its adjacent boundaries are validated before caching. A failure, malformed response, invalid boundary, or lack of a supported answer leaves the last valid cache and then the embedded table usable.

Official Umm al-Qura Today provider #

OfficialUmmAlQuraTodayProvider is an explicit integration for the structured public data used by the official Umm al-Qura Today page. The page is client-rendered, so the provider uses its JSON response rather than fragile HTML parsing. It has no credentials, makes no request during construction, and is only contacted by an enabled host refresh.

For a safe boundary check, one refresh reads the selected Saudi civil date and the immediately adjacent Hijri months. The provider derives their semantic month starts and the resolver accepts them only when the resulting boundaries remain valid. Any transport or response failure is returned by the refresh result while ordinary conversions continue from the cache or embedded table.

final officialProvider = OfficialUmmAlQuraTodayProvider();
final calendar = UmmAlQuraCalendar(
  verificationSettings: const VerificationSettings(
    enabled: true,
    refreshInterval: Duration(days: 1),
  ),
  verifiedMonthStartProvider: officialProvider,
);

final refresh = await calendar.refreshIfDue(DateTime.now().toUtc());
// Inspect refresh.status if the host wants to report an attempted refresh.

// Call this during application shutdown when the provider owns its client.
officialProvider.close();

Pass a http.Client to the provider when the host owns connection lifetime, proxies, or test transport. The endpoint is configurable for a host-operated proxy or a future official change. Browser deployments remain subject to the endpoint's CORS policy. Review the source's terms and your application's network policy before enabling any remote provider.

Umm al-Qura verification is Saudi-calendar verification, not a universal local Moon-sighting authority. Supply verified starts from a suitable local authority or use manual overrides when your practice differs.

Crescent forecast #

The forecast API requires an explicit observation time and observer location. It is a deterministic, low-precision analytical estimate, not evidence of a real human sighting.

final forecast = forecastCrescentVisibility(
  observationTime: DateTime.utc(2024, 11, 3, 14, 30),
  observer: ObserverLocation(
    latitude: 23.588,
    longitude: 58.3829,
    elevationMeters: 10,
  ),
);

print(forecast.visibility.id);
print(forecast.elongationDegrees);
print(forecast.limitations);
assert(!forecast.confirmsPhysicalSighting);

The forecast uses approximate analytical Sun–Moon geometry and an Odeh-like visibility heuristic. It does not model terrain, atmospheric conditions, optics, local authority rules, or human observation. It cannot alter calendar conversion.

Public API #

  • GregorianDate, HijriDate, and HijriMonth are immutable date-only values.
  • UmmAlQuraCalendar performs conversion, calibration, and explicit refreshes.
  • CalendarConversion<T> and CalendarSource make the source auditable.
  • ManualMonthOverride and CalendarCalibration represent user configuration.
  • VerifiedMonthStartProvider and VerifiedCalendarStore keep online work host-owned.
  • ObserverLocation, CrescentForecast, and forecastCrescentVisibility provide optional forecast information.

Licence and attribution #

This repository is licensed under the MIT License. It uses a compact embedded Umm al-Qura month-start table based on the hijri reference, plus an independent reduced forecast implementation informed by moon_sighting. The required upstream BSD and MIT attribution notices are retained in NOTICE.

Private handoff/reference material is excluded from package publishing and Git tracking.

0
likes
160
points
167
downloads

Documentation

API reference

Publisher

verified publisherawrs.me

Weekly Downloads

Offline-first Umm al-Qura Hijri conversion with auditable corrections and optional crescent forecasts.

Repository (GitHub)
View/report issues

Topics

#hijri #calendar #umm-al-qura

License

MIT (license)

Dependencies

http

More

Packages that depend on hijri_plus