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

Date Time Bundle Laravel Package

mohebifar/date-time-bundle

A Symfony bundle that provides date and time form types with picker integration, making it easier to add date/time inputs and handle DateTime values cleanly in PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

The first thing to internalize: this is a Symfony 2.x bundle, not a Laravel package. There is no service provider, no facade, no config file in Laravel's config/ sense, and the Datepicker FormType extends Symfony\Component\Form\AbstractType. Do not attempt composer require mohebifar/date-time-bundle in a Laravel 9/10/11 app — the symfony/* constraints are Symfony 2-era and will either fail resolution or force a downgrade across your symfony/* transitive tree. The working path is to clone the repo into a scratch directory, read it, and lift the calendar formatting logic into app/Support.

Where to look first, in order:

  1. DependencyInjection/ and DateTimeBundle.php — skim only; you will delete all of this.
  2. The formatter class (search for strftime, format, or a Formatter/Calendar name) — this is the one file with portable value. Identify the pure functions: Gregorian→target-calendar conversion, month-length and leap-year rules, and format-token expansion.
  3. Form/Type/* — read it for the pattern (how they wire a datepicker to a transformed value), not the code. In Laravel this maps to a Blade component + a custom cast.

Minimal first use case — a framework-agnostic formatter:

// app/Support/Calendar/JalaliFormatter.php  (extracted, no Symfony imports)
namespace App\Support\Calendar;

class JalaliFormatter
{
    public function __construct(
        protected CalendarConverter $converter,
        protected string $format = 'Y/m/d',
    ) {}

    public function format(\DateTimeInterface $date, ?string $tz = null): string
    {
        $tz = $tz ? new \DateTimeZone($tz) : $date->getTimezone();
        $local = (new \DateTimeImmutable($date->format('c')))->setTimezone($tz);
        return $this->converter->format($local, $this->format);
    }
}

Bind it in a service provider, inject it into a helper/facade, and call it from a Blade directive. That's your "first use case": render created_at in a target calendar in a view. Everything else in the bundle is a reference, not a dependency.

Before committing, check the repo's composer.json for the license and for whether the conversion math is original or vendored — you need both answers before this code ships anywhere.

Implementation Patterns

Provider + singleton for the formatter. Calendar conversion is stateless and CPU-trivial; bind one instance so format/locale defaults live in config/calendar.php rather than being passed at every call site. Do not reach for a facade immediately — inject the interface so tests can swap a fake and so you can later swap engines (e.g. to morilog/jalali) without touching call sites.

// app/Providers/CalendarServiceProvider.php
public function register(): void
{
    $this->app->singleton(CalendarFormatter::class, fn ($app) =>
        new JalaliFormatter(
            converter: new JalaliConverter(),
            format: config('calendar.format', 'Y/m/d'),
        )
    );
}

Blade directive for display, component for input. Keep formatting and picking separate — the bundle conflates them, and that's the piece you should not carry over.

Blade::directive('calendar', fn ($expr) =>
    "<?php echo e(app(\App\Support\Calendar\CalendarFormatter::class)->format($expr)); ?>"
);
{{-- resources/views/components/datepicker.blade.php --}}
<div x-data x-init="flatpickr($refs.input, { plugins: [jalaliPlugin], dateFormat: 'Y-m-d' })">
    <input x-ref="input" type="text" name="{{ $name }}" value="{{ old($name, $value) }}">
</div>

The client-side picker (flatpickr + a Jalali plugin, or a maintained Persian datepicker) replaces the bundle's FormType entirely. This is the correct layer for date entry in a Laravel app — no Symfony Form bridge required, no server round-trip for the widget.

Eloquent cast for storage boundary. Keep DateTime in the model (the bundle gets this right), and format only at render.

class JalaliDate implements CastsAttributes
{
    public function get($model, $key, $value, $attributes): ?string
    {
        if ($value === null) return null;
        return app(CalendarFormatter::class)->format(
            new \DateTimeImmutable($value, new \DateTimeZone('UTC'))
        );
    }
    public function set($model, $key, $value, $attributes): ?string
    {
        return $value; // store Gregorian; never persist a formatted string
    }
}

Validation rule for user-entered calendar dates. The bundle's FormType implies validation; you have to supply it yourself.

class ValidCalendarDate implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        try { app(JalaliConverter::class)->parse($value); }
        catch (\Throwable) { $fail(__('calendar.invalid_date')); }
    }
}

Day-to-day workflow. Most of the team will only ever touch the Blade directive and the cast. The provider and converter are touched once and then tested. Treat the fork as an internal package under app/Support/Calendar with attribution in a header comment, and pin it in code review — never as a VCS dependency.

Gotchas and Tips

  • Do not attempt the install "just to try it". A failed composer require is the good outcome; a silent downgrade of a symfony/* component that Laravel's illuminate/* stack depends on is the bad one. If you must poke at the bundle directly, use a throwaway Symfony skeleton in a container, not your app.
  • Format tokens will bite you. The bundle's tokens may mirror PHP's date()/strftime() but reinterpret m, d, Y, or l for the target calendar. A developer passing 'Y-m-d' out of habit can get correct-looking-but-wrong output for months > 9 or month names. Enforce a distinct token namespace in your extracted formatter, or expose a typed API (->iso(), ->longDate()) instead of raw tokens.
  • Timezone drift is the highest-frequency bug here. Do conversion against an explicit timezone, never date_default_timezone_get(). If the bundle's formatter assumes server-local time, that assumption has to be removed during extraction, not preserved. Off-by-one-day errors around midnight and DST boundaries are the symptom.
  • Calendar edge cases are where the tests go first. Leap-year rules, varying month lengths, and year-boundary transitions in the target calendar are the defect hotspot. Write the conversion tests against known references before you trust the extracted code. Whoever understands the calendar rules becomes a single point of failure unless that knowledge lives in tests.
  • Locale must be an explicit argument. If the formatter infers locale from the request, background jobs, API responses, and queued mail will render differently from web views. Pass it in or bake it into the config value, never derive it from the container inside the formatter.
  • FormType has no Laravel analogue. Resist building a "Symfony Form bridge". The bundle's AbstractType/FormBuilderInterface machinery is dead weight in Laravel; map the ergonomics (a named field type with sensible defaults) to a Blade component and a validation rule.
  • Don't convert in hot loops. Formatting is trivial per-call, but converting tens of thousands of rows in a report is wasteful. Cache the formatted string on the model (->jalali_created_at) or format at render time, not in the query loop.
  • Extension point worth keeping: an interface for the calendar engine. The bundle hard-codes one calendar. Wrap the conversion behind CalendarConverter so a Hijri or Coptic engine (or morilog/jalali) can be swapped in without touching the provider, directive, or cast. That interface is the only architectural contribution worth carrying forward from this package.
  • Attribution and license. Get the license from the repo before any extraction ships. Keep a header comment pointing at the original source and the commit you lifted from, so a future security review can trace the provenance of the code.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource