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

Filament Relative Time Laravel Package

relisiuol/filament-relative-time

A Filament plugin that renders relative timestamps—such as "3 hours ago"—in tables, infolists, and forms. Swap default date columns for human-friendly relative time with configurable formatting, locale support, and easy integration into any Filament panel.

View on GitHub
Deep Wiki
Context7

Getting Started

relisiuol/filament-relative-time is a small Filament plugin that renders timestamps as human-readable relative strings ("3 hours ago", "in 2 days") inside Filament resources, rather than shipping a new concept you have to learn. Treat it as a presentation-layer convenience on top of Carbon's diffForHumans().

Minimal setup

  1. Install alongside a Filament panel you already have running:

    composer require relisiuol/filament-relative-time
    

    Check the composer.json constraint against your Filament major (v3 vs v4). Filament plugin APIs shifted between majors, and a patch release of this package will not paper over that.

  2. Register the plugin in your panel provider (the convention for Filament plugins):

    use Relisiuol\FilamentRelativeTime\RelativeTimePlugin;
    
    public function panel(Panel $panel): Panel
    {
        return $panel
            ->plugin(RelativeTimePlugin::make());
    }
    

    If the package exposes no panel-level settings you care about, registration may be optional and the column/entry classes usable directly — verify against the README before adding config you don't need.

  3. Publish config only if you need to change defaults:

    php artisan vendor:publish --tag="filament-relative-time-config"
    

Where to look first

  • README.md for the exact component class names (*Column, *Entry, and whether a form-field variant exists).
  • The published config/filament-relative-time.php — this is where locale, format, tooltip, and refresh defaults live.
  • src/ for the component classes; they are thin wrappers, so reading them takes minutes and tells you exactly which Carbon method and options are used.

First use case: replace a raw created_at column on an existing resource table:

// before
TextColumn::make('created_at')->dateTime();

// after
RelativeTimeColumn::make('created_at');

Do this on one resource, confirm the string, locale, and timezone look right, then roll it out.

Implementation Patterns

Table columns with an absolute-time escape hatch. Relative time is great for scanning, terrible for auditing. Pair it with a tooltip or toggle so users can still get the exact timestamp:

RelativeTimeColumn::make('created_at')
    ->tooltip(fn ($record) => $record->created_at->toDayDateTimeString())
    ->sortable();

Keep ->sortable() — it sorts on the underlying column value, not the rendered string, so there is no cost to using the relative display.

Infolist entries on view pages. The same treatment works in ViewRecord schemas, where relative time reads naturally next to status badges:

RelativeTimeEntry::make('last_seen_at'),

Mixed granularity per field. Use relative time for "activity" fields (last_login_at, updated_at, published_at) and keep absolute formatting for anything legally or financially meaningful (invoiced_at, paid_at). Consistency within a page matters more than consistency across the app.

Auto-refreshing dashboards. Relative strings go stale silently — "2 minutes ago" stays on screen for an hour. For live-ish widgets, lean on Filament's polling rather than adding your own JS:

->poll('30s')

or on a custom widget, wire:poll.30s. Only do this on widgets where freshness is the point; polling a 50-row table every 10 seconds for a cosmetic string is a bad trade.

Shared formatting policy. If you have several panels or non-Filament Blade views, centralize the format in config (or a small helper) instead of scattering diffForHumans() calls with different arguments. One config value, one place to change when product decides they want "3h" instead of "3 hours ago".

Locale and timezone per panel. Set locale/timezone on the panel or in the package config so relative strings match the rest of the UI:

->timezone('Europe/Lisbon')
->locale('pt_PT')

Carbon's translated relative strings depend on the app locale being set correctly; verify with a non-English panel rather than assuming.

Testing. Freeze time and assert on rendered output — relative strings are otherwise untestable:

Carbon::setTestNow('2024-01-01 12:00:00');

livewire(EditPost::class, ['record' => $post->id])
    ->assertSee('2 hours ago');

Migration pattern for existing resources. Roll out behind a config flag or per-resource, not in one sweeping find-and-replace. The visual diff is subtle and easy to miss in review, and a botched timestamp format is exactly the kind of thing users report but reviewers don't catch.

Gotchas and Tips

The v1.1.1 changelog tells you nothing. The release body is only a compare link, so there is no stated fix, feature, or breaking change. Before upgrading in a real app:

# read the actual diff, the notes won't help
open https://github.com/relisiuol/filament-relative-time/compare/v1.1.0...v1.1.1

For a single-maintainer Filament plugin, a patch bump most often means a rendering fix, a timezone/locale correction, or a Filament compatibility tweak. If you were working around a display bug, check whether the workaround is now redundant. Pin the exact version ("1.1.1" rather than "^1.1") until you've read the diff, and do the same for its Filament constraint in composer.json — a plugin patch that widens or narrows the Filament range can surface as a confusing resolution failure rather than an obvious error.

Timezone drift between DB and display. This is the number one source of "the relative time is wrong" bugs. If timestamps are stored in UTC but the app timezone is set to something else — or vice versa — relative strings inherit the error and it looks like a plugin bug. Confirm config('app.timezone'), the panel timezone, and the actual stored values agree before filing anything upstream.

Stale strings are a UX decision, not a bug. Without polling or a page refresh, a relative timestamp is a snapshot of render time. Decide up front which fields tolerate that. For anything under "last active" semantics, prefer ->poll() or fall back to absolute time.

Sorting, filtering, and search still operate on raw values. That's the desired behaviour, but it means a user sorting by a relative-time column sees rows ordered by timestamp — which is correct but occasionally reads as broken when "5 minutes ago" appears above "1 minute ago" mid-render. Not worth fixing; worth knowing so you can answer the ticket.

Future dates render as "in X". Good for scheduled_at, confusing for fields that should never be in the future. If a field can drift, guard it or use absolute formatting.

Locale coverage is Carbon's, not the plugin's. A missing translation surfaces as English text mid-page. If you ship multiple locales, spot-check one non-English panel after every upgrade — this is the most likely thing to change silently in a patch release.

Extension points worth knowing before you fork. Check whether the component exposes a ->format() / closure hook and whether views are publishable. Customizing a published view is fine until a patch release changes the markup and your override silently diverges — prefer the config/closure route, and if you must publish views, note the version you forked from.

Fallback is trivial. If the package ever lags behind a Filament major or goes unmaintained, the functionality is three lines:

TextColumn::make('created_at')
    ->formatStateUsing(fn ($state) => $state?->diffForHumans())
    ->tooltip(fn ($record) => $record->created_at?->toDayDateTimeString()),

Keep that in mind when deciding how deeply to integrate it. Use it for display convenience; don't let timezone or locale policy live only inside the plugin's config.

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