Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a localized time ago String on Android

I was reviewing the Google I/O Session 2012 app and came across this TODO

public static String getTimeAgo(long time, Context ctx) {
    if (time < 1000000000000L) {
        // if timestamp given in seconds, convert to millis
        time *= 1000;
    }

    long now = getCurrentTime(ctx);
    if (time > now || time <= 0) {
        return null;
    }

    // TODO: localize
    final long diff = now - time;
    if (diff < MINUTE_MILLIS) {
        return "just now";
    } else if (diff < 2 * MINUTE_MILLIS) {
        return "a minute ago";
    } else if (diff < 50 * MINUTE_MILLIS) {
        return diff / MINUTE_MILLIS + " minutes ago";
    } else if (diff < 90 * MINUTE_MILLIS) {
        return "an hour ago";
    } else if (diff < 24 * HOUR_MILLIS) {
        return diff / HOUR_MILLIS + " hours ago";
    } else if (diff < 48 * HOUR_MILLIS) {
        return "yesterday";
    } else {
        return diff / DAY_MILLIS + " days ago";
    }
}

Which made me wonder what would be the steps to localizing it.

like image 478
Dandre Allison Avatar asked Nov 02 '12 21:11

Dandre Allison


2 Answers

If you don't need custom strings, you can also use DateUtils.getRelativeTimeSpanString, which produces strings such as:

  • 42 minutes ago
  • 10 seconds ago
  • in 1 hour

Sample usage:

final CharSequence relativeTimeSpan = DateUtils.getRelativeTimeSpanString(time, now, 0);
like image 149
ianhanniballake Avatar answered Oct 27 '22 00:10

ianhanniballake


From Ian Lake's answer:

final CharSequence relativeTimeSpan = DateUtils.getRelativeTimeSpanString(time, now, 0);

DateUtils.getRelativeTimeSpanString produces things such as the following:

  • 42 minutes ago
  • 10 seconds ago
  • in 1 hour

Alternatively, this would allow translations to be provided through the Android res framework using the given Context, useful if your desired messaging difference from what you can get out of the framework method.

public static String getTimeAgo(long time, Context context) {
    if (time < 1000000000000L)
        // if timestamp given in seconds, convert to millis
        time *= 1000;

    final long now = getCurrentTime(context);
    if (time > now || time <= 0) return "";


    final Resources res = context.getResources();
    final long time_difference = now - time;
    if (time_difference < _A_MINUTE)
        return res.getString(R.string.just_now);
    else if (time_difference < 50 * _A_MINUTE)
        return res.getString(R.string.time_ago,
                             res.getQuantityString(R.plurals.minutes, (int) time_difference / _A_MINUTE, time_difference / _A_MINUTE));
    else if (time_difference < 24 * _AN_HOUR)
        return res.getString(R.string.time_ago,
                             res.getQuantityString(R.plurals.hours, (int) time_difference / _AN_HOUR, time_difference / _AN_HOUR));
    else if (time_difference < 48 * _AN_HOUR)
        return res.getString(R.string.yesterday);
    else
        return res.getString(R.string.time_ago,
                             res.getQuantityString(R.plurals.days, (int) time_difference / _A_DAY, time_difference / _A_DAY));
}

where I defined the constants as:

/** One second (in milliseconds) */
private static final int _A_SECOND = 1000;
/** One minute (in milliseconds) */
private static final int _A_MINUTE = 60 * _A_SECOND;
/** One hour (in milliseconds) */
private static final int _AN_HOUR = 60 * _A_MINUTE;
/** One day (in milliseconds) */
private static final int _A_DAY = 24 * _AN_HOUR;

Then the rest of the work is in the structure of the plurals and string resources.

My default local is en, so res/values/strings.xml:

<!-- time ago strings -->
<string name="just_now">just now</string>
<string name="time_ago">%s ago</string>
<string name="yesterday">yesterday</string>

Then res/values/plurals.xml:

<plurals name="minutes">
    <item quantity="one">a minute</item>
    <item quantity="other">%d minutes</item>
</plurals>

<plurals name="hours">
    <item quantity="one">an hour</item>
    <item quantity="other">%d hours</item>
</plurals>

<plurals name="days">
    <item quantity="one">a day</item>
    <item quantity="other">%d days</item>
</plurals>

This approach should allow you to localize on the vocabulary and the grammar of the language, as different languages not only have different words for words like "minute", but they also have different rules about how to pluralize words based on the quantity. So the plurals resource utilizes the Android frameworks support of localizing on pluralizations. All that is left is to provide the translations.

like image 33
3 revs Avatar answered Oct 26 '22 22:10

3 revs