1#!/usr/bin/perl
2use strict;
3use warnings;
4use v5.10;
5
6use Carp         qw[];
7use Time::Moment qw[];
8
9sub YEAR   () { 365 + 1/4 - 1/100 + 1/400 }
10sub MONTH  () { YEAR / 12                 }
11sub DAY    () { 1                         }
12sub HOUR   () { DAY / 24                  }
13sub MINUTE () { HOUR / 60                 }
14sub SECOND () { MINUTE / 60               }
15
16sub ago {
17    @_ == 1 || @_ == 2 or Carp::croak(q/Usage: ago(since [, event])/);
18    my ($since, $event) = @_;
19
20    $event //= Time::Moment->now;
21
22    ($since->is_before($event))
23      or Carp::croak(q/Given moment is in the future/);
24
25    my $d = $event->mjd - $since->mjd;
26
27    if ($d < 0.75 * DAY) {
28        if ($d < 0.75 * MINUTE) {
29            return 'a few seconds ago';
30        }
31        elsif ($d < 1.5 * MINUTE) {
32            return 'a minute ago';
33        }
34        elsif ($d < 0.75 * HOUR) {
35            return sprintf '%d minutes ago', $d / MINUTE + 0.5;
36        }
37        elsif ($d < 1.5 * HOUR) {
38            return 'an hour ago';
39        }
40        else {
41            return sprintf '%d hours ago', $d / HOUR + 0.5;
42        }
43    }
44    else {
45        if ($d < 1.5 * DAY) {
46            return 'a day ago';
47        }
48        elsif ($d < 0.75 * MONTH) {
49            return sprintf '%d days ago', $d / DAY + 0.5;
50        }
51        elsif ($d < 1.5 * MONTH) {
52            return 'a month ago';
53        }
54        elsif ($d < 0.75 * YEAR) {
55            return sprintf '%d months ago', $d / MONTH + 0.5;
56        }
57        elsif ($d < 1.5 * YEAR) {
58            return 'a year ago';
59        }
60        else {
61            return sprintf '%d years ago', $d / YEAR + 0.5;
62        }
63    }
64}
65
66my @tests = (
67    [  10 * SECOND, 'a few seconds ago' ],
68    [  75 * SECOND, 'a minute ago'      ],
69    [   1 * MINUTE, 'a minute ago'      ],
70    [  30 * MINUTE, '30 minutes ago'    ],
71    [   1 * HOUR,   'an hour ago'       ],
72    [   2 * HOUR,   '2 hours ago'       ],
73    [   1 * DAY,    'a day ago'         ],
74    [  20 * DAY,    '20 days ago'       ],
75    [   1 * MONTH,  'a month ago'       ],
76    [   2 * MONTH,  '2 months ago'      ],
77    [  13 * MONTH,  'a year ago'        ],
78    [   1 * YEAR,   'a year ago'        ],
79    [   2 * YEAR,   '2 years ago'       ],
80    [  10 * YEAR,   '10 years ago'      ],
81    [ 100 * YEAR,   '100 years ago'     ],
82);
83
84use Time::Moment 0.25;
85use Test::More   0.88;
86
87my $now = Time::Moment->now;
88foreach my $test (@tests) {
89    my ($duration, $expected) = @$test;
90    my $tm = Time::Moment->from_mjd($now->mjd - $duration);
91    is(ago($tm, $now), $expected, "$tm ($duration)");
92}
93
94done_testing();
95