misri_hijri 0.1.0
misri_hijri: ^0.1.0 copied to clipboard
Hijri calendar dates for Dart/Flutter with a choice of calculation system — Misri (fixed tabular, 30-year cycle) or Umm al-Qura (Saudi official, astronomical lookup table) — behind one shared API.
misri_hijri #
Hijri (Islamic) calendar dates for Dart and Flutter, with a choice of calculation system behind one shared API:
| Engine | Type | How it works | Range |
|---|---|---|---|
MisriHijriCalendar |
HijriCalendarType.misri |
Fixed tabular (arithmetical) calendar: a 30-year cycle with a deterministic leap-year pattern. No lookup table, no moon-sighting. | Any year, past or future |
UmmAlQuraCalendar |
HijriCalendarType.ummAlQura |
Saudi Arabia's official calendar, backed by an astronomical month-start lookup table. Supports manual regional adjustments. | ~1356–1500 AH (14 Mar 1937 – 16 Nov 2077 CE) |
Pure Dart — no Flutter dependency, so it works in Flutter apps, server-side Dart, and CLI tools alike.
Install #
dependencies:
misri_hijri: ^0.1.0
Quick start #
import 'package:misri_hijri/misri_hijri.dart';
void main() {
// Pick an engine with a single parameter.
final today = Hijri.now(type: HijriCalendarType.ummAlQura);
print(today.format('DDDD, dd MMMM yyyy'));
// Convert from Gregorian.
final d = Hijri.fromDate(
DateTime(2025, 3, 20),
type: HijriCalendarType.misri,
);
print('${d.year}-${d.month}-${d.day}');
// Build from an explicit Hijri date and go back to Gregorian.
final eid = Hijri.fromHijri(1446, 10, 1, type: HijriCalendarType.ummAlQura);
print(eid.toDateTime()); // DateTime
}
Or use an engine directly when you always know which calendar you need:
final m = MisriHijriCalendar.fromDate(DateTime(2025, 3, 20));
final u = UmmAlQuraCalendar.fromHijri(1446, 9, 1);
The shared interface #
Both engines implement HijriCalendarBase, so application code can accept
either one:
void printDate(HijriCalendarBase date) {
print(date.format('DDDD, dd MMMM yyyy'));
}
printDate(MisriHijriCalendar.now());
printDate(UmmAlQuraCalendar.now());
HijriCalendarBase exposes the same surface for both engines:
year,month,day,weekday,daysInMonth,isLeapYearmonthName,monthNameShort,weekdayName,weekdayNameShorttoDateTime()— the Gregorian equivalenthijriToGregorian(year, month, day)— convert an arbitrary Hijri dategetDaysInMonth(year, month),lengthOfYear({year})getMonthDays(month, year)— day-of-month → weekday-name maptoList()→[year, month, day],isoFormat→yyyy-mm-dd,isValid()format(pattern)/formatDate(year, month, day, pattern)/toFormat/fullDate()— see belowaddDays(int),addMonths(int)— return a new instance of the same engine;addMonthsclamps the day to the destination month's lengthisBefore,isAfter,isAtSameMomentAs,compareTo— chronological comparison that works across engine types (compared viatoDateTime)
The engine classes add only their constructors (now, yesterday,
tomorrow, fromDate, fromHijri) and, for UmmAlQuraCalendar,
setAdjustments for regional moon-sighting corrections.
Worked examples #
Reference conversions produced by this package, for checking against an external source. Weekdays are included so you can confirm the exact day.
Note on the Misri engine: its 30-year cycle treats years 2, 5, 8, 10, 13, 16, 19, 21, 24, 27, 29 (year mod 30) as leap, and anchors 1 Muharram 1 AH to 16 July 622 CE. Some "tabular / arithmetical Hijri" converters use the leap set 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29 instead, which can shift a result by a day or two — compare against a converter that uses the same rule.
Gregorian → Misri #
| Gregorian | Misri Hijri |
|---|---|
| Sun 1 January 1950 | 13 Rabiul Awwal 1369 AH |
| Fri 31 December 1999 | 24 Ramazanul Moazzam 1420 AH |
| Wed 10 April 2024 | 2 Shawwalul Mukarram 1445 AH |
| Fri 6 June 2025 | 10 Zilhijjatil Haram 1446 AH |
| Mon 5 November 2040 | 1 Zilqadatil Haram 1462 AH |
Misri → Gregorian #
| Misri Hijri | Gregorian |
|---|---|
| 1 Moharramul Haram 1350 AH | Mon 18 May 1931 |
| 27 Ramazanul Moazzam 1420 AH | Mon 3 January 2000 |
| 10 Zilhijjatil Haram 1446 AH | Fri 6 June 2025 |
| 1 Rabiul Awwal 1447 AH | Sun 24 August 2025 |
| 1 Moharramul Haram 1460 AH | Fri 5 February 2038 |
Gregorian → Umm al-Qura #
| Gregorian | Umm al-Qura Hijri |
|---|---|
| Mon 20 May 1940 | 12 Rabi' Al-Akhir 1359 AH |
| Thu 14 August 1980 | 3 Shawwal 1400 AH |
| Mon 15 February 2010 | 1 Rabi' Al-Awwal 1431 AH |
| Sat 1 March 2025 | 1 Ramadan 1446 AH |
| Wed 30 September 2065 | 29 Jumada Al-Akhirah 1488 AH |
Umm al-Qura → Gregorian #
| Umm al-Qura Hijri | Gregorian |
|---|---|
| 1 Muharram 1356 AH | Sun 14 March 1937 |
| 1 Muharram 1400 AH | Tue 20 November 1979 |
| 1 Ramadan 1446 AH | Sat 1 March 2025 |
| 1 Shawwal 1446 AH | Sun 30 March 2025 |
| 29 Dhu Al-Hijjah 1500 AH | Mon 15 November 2077 |
The first and last Umm al-Qura rows are the boundaries of the bundled
lookup table (1 Muharram 1356 AH – 29 Dhu al-Hijja 1500 AH); dates outside
that range throw an ArgumentError.
Formatting #
format(pattern) replaces these tokens (longest match wins, so DDDD
beats DD and yyyy beats yy):
| Token | Meaning | Example (1446-09-05, en) |
|---|---|---|
d, dd |
Day of month (not zero-padded) | 5 |
m, mm |
Month number (not zero-padded) | 9 |
MM |
Short month name | Ram |
MMMM |
Long month name | Ramadan |
yy |
Last two digits of the year | 46 |
yyyy |
Full year | 1446 |
DD |
Short weekday name | Wed |
DDDD |
Long weekday name | Wednesday |
final d = UmmAlQuraCalendar.fromHijri(1446, 9, 5);
d.format('yyyy/mm/dd'); // 1446/9/5
d.format('DDDD, dd MMMM yyyy'); // Wednesday, 5 Ramadan 1446
Note: replacement is a single pass over the pattern. Literal text that contains
d,m, orywill also be substituted, so keep patterns to separators like/,-,,, spaces, and the tokens above.
Locales #
Built-in: en and ar for both engines, plus tr for Umm al-Qura.
UmmAlQuraCalendar.setLocal('ar'); // global default for new instances
final d = UmmAlQuraCalendar.fromHijri(1446, 9, 1, locale: 'ar');
d.format('dd MMMM yyyy'); // ١ رمضان ١٤٤٦ (Arabic-Indic digits)
UmmAlQuraCalendar.addLocale('fr', HijriLocale(
longMonths: {1: 'Mouharram', /* ... */},
shortMonths: {/* ... */},
days: {1: 'Lundi', /* ... 7: 'Dimanche' */},
shortDays: {/* ... */},
));
Each instance carries its own locale, so changing the global default does not affect instances that are already created.
Weekday name maps use Dart's DateTime.weekday convention:
1 = Monday … 6 = Saturday, 7 = Sunday.
Umm al-Qura adjustments #
Regional moon-sighting can shift a month's start by a day. Override
specific month-start indices (same index convention as the internal table,
hijriYearMonthIndex + 16260):
final cal = UmmAlQuraCalendar.now();
cal.setAdjustments({/* index: mcjdn */});
Accuracy caveat #
Two entries in the bundled Umm al-Qura lookup table
(lib/src/hijri_array.dart) carry inherited comments claiming a manual
"correction" to the standard table. They are flagged inline. If you rely on
this package for far-future dates, verify those entries against an
authoritative Umm al-Qura source.
Attribution #
The Umm al-Qura lookup table and JDN conversion approach are derived from
the hijri package (BSD-2-Clause,
Copyright 2018 AHMED ALJOAID). See NOTICE for details.
License #
BSD-2-Clause. See LICENSE.