Time Spans for Humans
Friday, May 14, 2010
When dealing with time spans or durations, it is nice to be able to render elapsed time in a way that is easy for the human eye to read.
In some cases, this could mean translating the way you might say it or write it (two years, ten days, four hours, thirty minutes, and fifteen seconds) or a more concise form (2y 10d 4h 30m 15s). The concise form has become popular in some web applications, and solutions exist for both in most languages including python, perl, and java. I thought I would build a word in Factor to calculate it.
First, we need some other vocabularies:
USING: kernel make math math.parser sequences ;
The
make
vocabulary can be used to execute a quotation that builds a sequence of
values at runtime. This can be a little confusing for those new to
Factor. Basically, you provide it a quotation that periodically emits
values (by calling the ,
word) that are collected into the sequence
type you provide. For example:
IN: scratchpad [ 1 , 2 , 3 , ] { } make .
{ 1 2 3 }
Next, we need an algorithm. One way is to iteratively divmod the number of seconds into each category (e.g., years, weeks, days, hours, minutes, seconds) and count it if the number in the category is non-zero.
: elapsed-time ( seconds -- string )
dup 0 < [ "negative seconds" throw ] when [
{
{ 60 "s" }
{ 60 "m" }
{ 24 "h" }
{ 7 "d" }
{ 52 "w" }
{ f "y" }
} [
[ first [ /mod ] [ dup ] if* ] [ second ] bi swap
dup 0 > [ number>string prepend , ] [ 2drop ] if
] each drop
] { } make [ "0s" ] [ reverse " " join ] if-empty ;
And then to see it work:
IN: scratchpad 123456 elapsed-time .
"1d 10h 17m 36s"