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