Category: Snippet

Human readable past date formating in Grails

Sometimes it better to write ‘2 days ago’ instad of ’28 Jan 2015′.
You can find a lot of solution in How to calculate “time ago” in Java?.

Here is a simplest snippet for making it in Grails from my project with i18n support.
Just create new tag `timeAgo` in your project taglib:

    static encodeAsForTags = [ timeAgo: [taglib:'html'] ]

    final static long ONE_SECOND = 1000;
    final static long ONE_MINUTE = ONE_SECOND * 60;
    final static long ONE_HOUR = ONE_MINUTE * 60;
    final static long ONE_DAY = ONE_HOUR * 24;

    /**
     Converts time (in milliseconds) to human-readable format
     "<w> days, <x> hours, <y> minutes ago" or "just now"
     <code>
     System.out.println(millisToLongDHMS(123));
     System.out.println(millisToLongDHMS((5 * ONE_SECOND) + 123));
     System.out.println(millisToLongDHMS(ONE_DAY + ONE_HOUR));
     System.out.println(millisToLongDHMS(ONE_DAY + 2 * ONE_SECOND));
     System.out.println(millisToLongDHMS(ONE_DAY + ONE_HOUR + (2 * ONE_MINUTE)));
     System.out.println(millisToLongDHMS((4 * ONE_DAY) + (3 * ONE_HOUR) + (2 * ONE_MINUTE) + ONE_SECOND));
     System.out.println(millisToLongDHMS(42 * ONE_DAY));
     </code>
     output :
     0 second
     5 seconds
     1 day, 1 hour
     1 day and 2 seconds
     1 day, 1 hour, 2 minutes
     4 days, 3 hours, 2 minutes
     42 days
     */
    private String millisToLongDHMS(long duration) {
        StringBuffer res = new StringBuffer();
        long temp;
        if (duration >= ONE_MINUTE) {
            temp = duration / ONE_DAY;
            if (temp > 0) {
                duration -= temp * ONE_DAY;
                res.append(temp).append(' ').append(temp > 1 ? g.message(code: 'timeAgo.days') : g.message(code: 'timeAgo.day')).append(duration >= ONE_MINUTE ? ', ' : '')
            }
            temp = duration / ONE_HOUR;
            if (temp > 0) {
                duration -= temp * ONE_HOUR;
                res.append(temp).append(' ').append(temp > 1 ? g.message(code: 'timeAgo.hours') : g.message(code: 'timeAgo.hour')).append(duration >= ONE_MINUTE ? ', ' : '')
            }
            temp = duration / ONE_MINUTE
            if (temp > 0) {
                res.append(temp).append(' ').append(temp > 1 ? g.message(code: 'timeAgo.minutes') : g.message(code: 'timeAgo.minute'))
            }
            res.append(' ').append(g.message(code: 'timeAgo.ago'))
            return res.toString()
        } else {
            return g.message(code: 'timeAgo.justNow')
        }
    }

    /**
     * @emptyTag
     *
     * @attr date the date in past
     */
    def timeAgo = { attrs ->
        Date date = attrs.date
        out << millisToLongDHMS((new Date().getTime()) - date.getTime());
    }

And then you need to add message codes in `messages.properties`:

timeAgo.justNow=just now
timeAgo.minute=minute
timeAgo.minutes=minutes
timeAgo.hour=hour
timeAgo.hours=hours
timeAgo.day=day
timeAgo.days=days
timeAgo.ago=ago
# for Russian
timeAgo.justNow=только что
timeAgo.minute=минуту
timeAgo.minutes=минут
timeAgo.hour=час
timeAgo.hours=часов
timeAgo.day=день
timeAgo.days=дней
timeAgo.ago=назад
# for Ukrainian
timeAgo.justNow=тіки що
timeAgo.minute=хвилину
timeAgo.minutes=хвилин
timeAgo.hour=годину
timeAgo.hours=годин
timeAgo.day=день
timeAgo.days=днів
timeAgo.ago=тому

Avatars in Grails with Gravatar

On every site we often need ability to show user avatars. The simplest way is to use external serive Gravatar.com.

There exists even a plugin for Grails but you don’t need it.
You can use gravatars in gsp files like this:

<img src="https://www.gravatar.com/avatar/${user.email.encodeAsMD5()}"/>

That’s all. But if you want you can create a tag in taglib:

class TagLib {
    static encodeAsForTags = [ gravatar: [taglib: 'none'] ]

    /**
     * Render img tag with user avatar from Gravatar.com
     * @emptyTag
     *
     * @attr user User
     */
    def gravatar = { attrs ->
        User user = attrs.user
        assert user
        out << "<img src='https://www.gravatar.com/avatar/${user.email.encodeAsMD5()}'/>"
    }
}