Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Hijri Date Laravel Package

remls/hijri-date

remls/hijri-date is a lightweight PHP package for working with Hijri (Islamic) calendar dates, offering Gregorian-to-Hijri conversion and formatting helpers for Laravel and standalone PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a small, single-purpose package, so treat the README as the source of truth — read it end to end before writing code. The public surface is likely a facade (something like Hijri::) plus a handful of helpers, and a config file for the conversion method and adjustment offset. Start there rather than guessing method names.

  1. Install and publish:

    composer require remls/hijri-date
    php artisan vendor:publish --tag=hijri-date-config   # verify the actual tag in the README
    
  2. Read the config first. With a 10-star package the config is the entire behavioural contract — the calendar variant (Umm al-Qura vs. tabular/arithmetic), the day adjustment (moon-sighting offset), and default output format will all live there. Confirm what defaults you inherited before you trust a single conversion.

  3. Smoke-test the round trip in tinker before integrating anywhere:

    $h = Hijri::fromGregorian(now());       // or whatever the README exposes
    Hijri::toGregorian($h->format('Y-m-d'));
    

    If the round trip is not identity, stop — that is a converter bug, not a config issue, and you need to know now.

  4. First real use case: a display-only conversion. Render the Hijri equivalent of a Gregorian timestamp in a view or notification. Do not make it the system of record for stored dates on day one — store Gregorian (or UTC timestamps) and convert at the edges.

  5. Pin the version in composer.json ("remls/hijri-date": "^1.0", not *). At this star count there are no downstream users stress-testing releases for you.

Implementation Patterns

Convert at the boundary, never in the database. Keep created_at, published_at, and every other column Gregorian/UTC. Convert in presenters, API resources, and Blade. This keeps whereBetween, orderBy, and every other query builder call working, and means a broken calendar conversion can never corrupt stored data.

Wrap it in your own service. This is the single most valuable pattern for a low-star dependency:

final class IslamicCalendar
{
    public function toHijri(CarbonInterface $date): string
    {
        return Hijri::fromGregorian($date)->format(config('hijri.display_format'));
    }

    public function toGregorian(string $hijri): Carbon
    {
        return Carbon::instance(Hijri::toGregorian($hijri));
    }
}

Inject this everywhere. If the package is abandoned or you switch to ext-intl's islamic-umalqura calendar, you change one class instead of grepping the codebase.

Custom cast for display-only attributes. If you want $event->hijri_date on a model, use an accessor, not a real cast — an accessor that derives from the Gregorian column keeps storage honest:

protected function hijriDate(): Attribute
{
    return Attribute::get(fn () => app(IslamicCalendar::class)->toHijri($this->starts_at));
}

Blade directive for repeated rendering. Register a directive in a service provider so templates stay readable:

Blade::directive('hijri', fn ($expr) => "<?php echo app(IslamicCalendar::class)->toHijri($expr); ?>");

Middleware for locale-driven formatting. If you serve Gulf/GCC users, resolve app()->setLocale() from the request and let your wrapper pick the format string per locale (ar_SA → Arabic month names and Arabic-Indic numerals if the package supports it; otherwise a strtr map over the numeric output).

Testing with fixed dates. Never assert against now(). Seed a data provider of known Gregorian↔Hijri pairs, ideally sourced from an authority (Umm al-Qura published calendars) rather than from the package's own output — otherwise you're asserting the package agrees with itself.

#[DataProvider('knownConversions')]
public function test_conversion_matches_reference(string $g, string $h): void
{
    $this->assertSame($h, app(IslamicCalendar::class)->toHijri(Carbon::parse($g)));
}

Scheduled boundary checks. Hijri days roll over at Maghrib in most religious contexts, not midnight. If your app cares (prayer times, fasting reminders, Eid banners), you need a separate "religious date" concept driven by sunset for the user's coordinates, layered on top of whatever this package returns. Don't let the package's naive date arithmetic imply it handles this.

Gotchas and Tips

Calendar variant is the biggest trap. There are at least three "Hijri" calendars in circulation — tabular/arithmetic (deterministic, ~1–2 days off reality), Umm al-Qura (Saudi official, what most apps want), and observational (varies by country and by year, no closed-form formula). Verify which one the package implements. If it's tabular and your users expect Umm al-Qura, dates will be visibly wrong around month boundaries and you'll get bug reports you can't reproduce in tests.

Adjustment offsets are not a fix for a wrong calendar. Many of these packages expose a +/- N days config key. Users will ask you to "just add a day." Resist: the offset is meant to reconcile moon-sighting policy, not to paper over a variant mismatch. If you set it globally, every date in the app shifts, including historical ones where the offset may not apply.

Month-length and leap-year edge cases. Hijri months are 29 or 30 days depending on the year and variant, and the 30-year leap cycle is not the Gregorian one. Any code you write that does addMonth() on a Hijri string will be wrong — do all arithmetic on the underlying Gregorian/Carbon object and convert last.

Timezones will bite you. Hijri::fromGregorian(now()) on a server in UTC at 22:00 will produce the next Hijri day for a user in Riyadh who is already past midnight. Normalize to the user's timezone before converting, and be explicit about whether your Hijri date represents the local civil day or the UTC instant.

No IntlDateFormatter fallback out of the box. If the package only offers numeric output (1446-03-15), you'll need your own month-name map if you want Rabīʿ al-Awwal. That's fine — it's a small array — but know you're signing up for it, and for Arabic-Indic numeral transliteration if the locale demands it.

Validation is yours to build. There is near-certainly no hijri_date validation rule. A custom rule needs to reject 1446-02-30 and month 13, and it must round-trip through the converter to catch impossible dates. Don't let users store Hijri input raw — parse to Gregorian on save.

Debugging strategy: bisect by variant, not by code. When a conversion looks wrong, don't read the package source first. Check (a) the configured variant, (b) the adjustment offset, (c) the timezone of the input, (d) whether the input was already a Hijri string being double-converted. Those four account for almost every wrong-looking date.

Extension points are minimal — own the seams. Expect a service container binding for the converter and possibly a formatter interface. Bind your own implementation to that interface if you need per-locale formatting, and keep the package's classes confined to your IslamicCalendar wrapper. This is also your escape hatch to intl's islamic-umalqura calendar if you need an audited implementation.

Treat abandonment as likely. Ten stars, MIT, single author — plan for the package to stop receiving updates. That's acceptable for a pure date-conversion function (it's not security-sensitive and the math doesn't change), but it means: pin the version, wrap it, test it against external reference dates, and don't let it creep into ten call sites where a swap becomes a refactor.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin