Re: Factor

Factor: the language, the theory, and the practice.

Relative Time for Humans

Thursday, May 13, 2010


Many applications deal with events that have occurred at different points in time. Often, these times are relatively recent, such as a list of emails in an inbox or a list of status updates on a social network. When we talk about when an event occurred, it is sometimes useful to be precise (e.g., Thu May 13 19:12:02 2010), and other times it is better to be a bit softer (e.g., about a minute ago).

This function gets built from time-to-time in various languages: for example in Python and Javascript. I thought it might be fun to see how simple it could be in Factor.

A very useful type of conditional combinator is called cond. It applies to a sequence of quotations. The first elements in the sequence are pairs of quotations. The combinator proceeds to call the first quotation in each pair until a true value is yielded, at which point it calls the second quotation in that pair and stops iterating. A final quotation can be provided to handle the case where none of the pairs returned a true value.

In typical applicative languages, this would be provided by an “if/else if/else” chain. It is a general pattern and is used in Factor to implement case (a type of switch statement).

Using a few vocabularies:

USING: combinators formatting kernel math ;

We will write a word that takes the number of seconds that something happened in the past, and calculates how long ago it was in “human terms”:

: relative-time ( seconds -- string )
    dup 0 < [ "negative seconds" throw ] when {
        { [ dup 1 < ] [ drop "just now" ] }
        { [ dup 60 < ] [ drop "less than a minute ago" ] }
        { [ dup 120 < ] [ drop "about a minute ago" ] }
        { [ dup 2700 < ] [ 60 / "%d minutes ago" sprintf ] }
        { [ dup 5400 < ] [ drop "about an hour ago" ] }
        { [ dup 86400 < ] [ 3600 / "%d hours ago" sprintf ] }
        { [ dup 172800 < ] [ drop "1 day ago" ] }
        [ 86400 / "%d days ago" sprintf ]
    } cond ;

Fairly concise as it turns out. If it wasn’t for the minor stack manipulation, you might say this was getting very close to the essence of the algorithm.