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

Time Ago Bundle Laravel Package

eschmar/time-ago-bundle

TimeAgoBundle provides a simple Twig filter for Symfony that expresses time differences in words, returning actual dates beyond ±7 days. Supports many languages, configurable date format, and future times. Install via Composer; works with Symfony 2.8–5.x.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: it is a Symfony bundle, not a Laravel package. There is no TimeAgoServiceProvider, no package auto-discovery, and no Blade directive. If the app you are actually shipping is Laravel + Blade, the correct first move is to close the tab and use Carbon::parse($date)->diffForHumans() — it is already in the framework, is locale-aware via Carbon::setLocale(), has no 7-day cutoff, and is maintained. Come back to this package only if you maintain a Symfony app, or a Laravel app that genuinely renders Twig (e.g. via rcrowe/twigbridge) and you want the bundle's translation corpus.

Where to look first, once you have decided you need it:

  1. vendor/eschmar/time-ago-bundle/composer.json — confirm the Symfony constraint. ^v2.0.0 targets Symfony ^5.0; ^v1.1.0 targets ^4.x. If you are on Symfony 6/7 you will likely need a fork or a composer.json constraint patch before anything else.
  2. src/ — the bundle class, the Twig extension (ago filter), and the service that formats the difference. This is a few hundred lines; read it in one sitting rather than trusting the README.
  3. Resources/translations/ (or translations/) — 26 locales of relative-time strings. This is the single most valuable asset in the repo.
  4. DependencyInjection/ — the eschmar_time_ago.format config key.

Minimal steps in a Symfony app:

composer require eschmar/time-ago-bundle ^v2.0.0
// config/bundles.php
Eschmar\TimeAgoBundle\EschmarTimeAgoBundle::class => ['all' => true],
# config/packages/eschmar_time_ago.yaml
eschmar_time_ago:
    format: 'd/m/Y'   # used for anything older than 7 days

First use case — a list/feed where absolute timestamps are noise:

{{ post.createdAt|ago }}
{# 3 minutes ago  /  in 4 hours  /  14/03/2022 #}

Implementation Patterns

Feed and activity lists. The intended use is a single unqualified |ago on a \DateTime/DateTimeInterface in an index or activity stream. Because the filter silently degrades to a formatted date past ±7 days, one filter call handles both "recent" and "archive" rows and you avoid {% if %} branching in the template. Do not fight that default; it is the whole design.

Per-call format override. The optional argument wins over config, so use it where the fallback needs to be more verbose than your global default:

{{ comment.createdAt|ago('M j, Y \\a\\t H:i') }}

Keep these overrides few. If you find yourself passing a format to every call site, move it into eschmar_time_ago.format instead — that is what the config key is for.

Translation wiring. The output is passed through Symfony's translator, so locale comes from framework.default_locale / the request locale, not from the filter. Verify with bin/console debug:translation <locale> <domain> that the bundle's keys are loaded for the locale you care about before assuming a language is missing. Set translator.fallbacks to en so an untranslated locale degrades to English strings rather than raw keys.

Bridging into a Laravel/Twig stack. If you must use it outside Symfony, do not try to boot the Bundle class — register the extension by hand in a small service provider:

$twig->addExtension(new TimeAgoExtension($app['translator'] /* or a Laravel-backed adapter */));

Be aware the extension probably expects a Symfony\Contracts\Translation\TranslatorInterface; you will need an adapter around Laravel's Translator. At that point, compare honestly against writing a 15-line Blade directive plus diffForHumans() — usually the directive wins.

Wrapping for portability. Put |ago behind your own time_ago filter or a view presenter. When the bundle goes stale (see below) you can swap the implementation in one place instead of grepping templates.

Testing. Relative output is time-dependent, so freeze the clock (Carbon::setTestNow() or Symfony's ClockMock) and assert against an explicit reference instant. Avoid asserting "just now" in integration tests — it is a moving target and will flake on slow CI.

Gotchas and Tips

  • The ±7 day window is hardcoded. There is no config for it. If product wants "3 months ago", you are forking the formatter. Decide this before committing to the package.
  • Maintenance risk is real. 17 stars, 0 dependents, last release March 2022. It is MIT, so treat it as vendored source you are allowed to own: fork it, drop in a replaces entry if needed, and expect to patch the Symfony constraint yourself. Plan for this in your dependency policy; do not let it become a silent blocker on a Symfony upgrade.
  • Future dates are supported but thinly tested. +4 hours works, but pluralization and phrasing for future distances in less-common locales may be rough. Spot-check any locale you actually ship.
  • The fallback format defaults to Y-m-d H:i:s, which looks like a database dump in a UI. Always set eschmar_time_ago.format explicitly, and use a locale-appropriate format (d/m/Y vs m/d/Y) rather than a machine format.
  • Timezone: the difference is computed on timestamps so it is generally TZ-safe, but the fallback date string renders in the DateTime object's own timezone. Normalize stored dates to UTC at the boundary and convert for display, or your >7-day rows will silently shift.
  • Do not cache rendered relative strings. Any HTTP cache, Twig cache fragment, or ESI block containing "5 minutes ago" will serve that string forever. Cache the raw entity and render |ago outside the cached region.
  • Debugging registration: bin/console debug:twig should list the ago filter; bin/console debug:container --tag=twig.extension should show the extension service. If the filter is missing, the bundle is not in config/bundles.php (Symfony 4+) or AppKernel::registerBundles() (Symfony <4) — not a caching problem.
  • Override, don't edit vendor. If you need different phrasing, drop a translation file into your app's translations/ using the bundle's domain name (check DependencyInjection/ for the exact domain) rather than patching vendor/. The extension and translator are ordinary services, so service decoration is available if you need to change behaviour.
  • Sanity-check against Carbon first. For any single call site, diffForHumans() gives you the same output with better maintenance. The bundle earns its place only if you need its specific locale set or are already inside Symfony's Twig/translator stack.
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.
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json
refinery29/php-cs-fixer-config
hotmeteor/eco-env
mvaliolahi/hydrate
wearede/tbcpay-php
parsnick/steak
thibaud-dauce/mattermost-php
multilinguals/apollo-client
antaresbr/collection
kr0lik/phpstan-rules