Mark S
Mark S

Reputation: 3799

Twig – time ago format

I'm new to Twig and I'm looking to turn a datetime format into a time ago like 2 hours ago or 3 days ago. There is a jquery plugin (jquery-timeago) that I've been using on the client side but it would be great if I can do this with twig. If twig doesn't come with this filter format are there extensions that I can use?

Upvotes: 11

Views: 23055

Answers (4)

db306
db306

Reputation: 1010

An updated version of Mark S answer with translation as requested by @wawa

class TimeAgoTwigExtension extends AbstractExtension
{
    public function __construct(private readonly TranslatorInterface $translator)
    {
    }

    public function getFilters()
    {
        return [new TwigFilter('time_ago', [$this, 'timeAgo'])];
    }

    public function getFunctions()
    {
        return [new TwigFunction('time_ago', [$this, 'timeAgo'])];
    }

    public function timeAgo(\DateTimeImmutable $datetime): string
    {
        $time = time() - $datetime->getTimestamp();

        $units = [
            31536000 => 'shared.time_ago.year',
            2592000 => 'shared.time_ago.month',
            604800 => 'shared.time_ago.week',
            86400 => 'shared.time_ago.day',
            3600 => 'shared.time_ago.hour',
            60 => 'shared.time_ago.minute',
            1 => 'shared.time_ago.second',
        ];

        foreach ($units as $unit => $text) {
            if ($time >= $unit) {
                $numberOfUnits = floor($time / $unit);

                return $this->translator->trans($text, ['%count%' => $numberOfUnits], 'app');
            }
        }

        return 'shared.time_ago.unknown';
    }
}

This can then be translated as follows:

{1}a week ago|]1,Inf[ %count% weeks ago

Upvotes: 0

10us
10us

Reputation: 1630

Twig's date extension does exactly what you ask:

{{ post.published_at|time_diff }}

The example above will output a string like 4 seconds ago or in 1 month, depending on the filtered date.

See http://twig.sensiolabs.org/doc/extensions/date.html (no longer works) Working link http://twig-extensions.readthedocs.io/en/latest/date.html

To make this work, follow these steps:

composer require twig/extensions

When working with symfony add this to your services.yml

services:
  twig.extension.date:
    class: Twig_Extensions_Extension_Date
    tags:
    - { name: twig.extension }

Upvotes: 22

nurikabe
nurikabe

Reputation: 4010

If you're using Twig inside of Symfony, check out KnpTimeBundle. Includes "ago" support in multiple languages.

Upvotes: 7

Mark S
Mark S

Reputation: 3799

I found out I can create a custom filter with twig Twig_SimpleFilter.

$filter = new Twig_SimpleFilter('timeago', function ($datetime) {

  $time = time() - strtotime($datetime); 

  $units = array (
    31536000 => 'year',
    2592000 => 'month',
    604800 => 'week',
    86400 => 'day',
    3600 => 'hour',
    60 => 'minute',
    1 => 'second'
  );

  foreach ($units as $unit => $val) {
    if ($time < $unit) continue;
    $numberOfUnits = floor($time / $unit);
    return ($val == 'second')? 'a few seconds ago' : 
           (($numberOfUnits>1) ? $numberOfUnits : 'a')
           .' '.$val.(($numberOfUnits>1) ? 's' : '').' ago';
  }

});

Then I add it to my Twig environment:

$twig = $app->view()->getEnvironment();//because I'm using Twig in Slim framework
$twig->addFilter($filter);

Use it my template like this:

{{2014-10-11 12:54:37|timeago}}

Upvotes: 15

Related Questions