diff options
-rw-r--r-- | Bugzilla/Util.pm | 70 | ||||
-rw-r--r-- | extensions/BugModal/Config.pm | 8 | ||||
-rw-r--r-- | extensions/BugModal/Extension.pm | 7 | ||||
-rw-r--r-- | extensions/BugModal/template/en/default/bug_modal/header.html.tmpl | 2 | ||||
-rw-r--r-- | extensions/BugModal/web/bug_modal.js | 11 | ||||
-rw-r--r-- | extensions/BugModal/web/time_ago.js | 142 | ||||
-rw-r--r-- | extensions/MozReview/web/js/mozreview.js | 39 | ||||
-rw-r--r-- | extensions/MyDashboard/lib/Queries.pm | 3 | ||||
-rw-r--r-- | extensions/MyDashboard/lib/TimeAgo.pm | 179 | ||||
-rw-r--r-- | extensions/RequestNagger/Extension.pm | 3 | ||||
-rw-r--r-- | extensions/RequestNagger/lib/TimeAgo.pm | 186 | ||||
-rw-r--r-- | extensions/UserProfile/Extension.pm | 3 | ||||
-rw-r--r-- | extensions/UserProfile/lib/TimeAgo.pm | 179 | ||||
-rw-r--r-- | js/util.js | 27 |
14 files changed, 114 insertions, 745 deletions
diff --git a/Bugzilla/Util.pm b/Bugzilla/Util.pm index 67798d470..f2291a812 100644 --- a/Bugzilla/Util.pm +++ b/Bugzilla/Util.pm @@ -40,12 +40,13 @@ use base qw(Exporter); validate_ip do_ssl_redirect_if_required use_attachbase diff_arrays on_main_db trim wrap_hard wrap_comment find_wrap_point - format_time validate_date validate_time datetime_from + format_time validate_date validate_time datetime_from time_ago file_mod_time is_7bit_clean bz_crypt generate_random_password validate_email_syntax clean_text get_text template_var disable_utf8 - enable_utf8 detect_encoding email_filter); + enable_utf8 detect_encoding email_filter + round); use Bugzilla::Constants; use Bugzilla::RNG qw(irand); @@ -61,6 +62,7 @@ use Scalar::Util qw(tainted blessed); use Text::Wrap; use Encode qw(encode decode resolve_alias); use Encode::Guess; +use POSIX qw(floor ceil); sub trick_taint { require Carp; @@ -603,6 +605,30 @@ sub datetime_from { return $dt; } +sub time_ago { + my ($param) = @_; + # DateTime object or seconds + my $ss = ref($param) ? time() - $param->epoch : $param; + my $mm = round($ss / 60); + my $hh = round($mm / 60); + my $dd = round($hh / 24); + my $mo = round($dd / 30); + my $yy = round($mo / 12); + + return 'just now' if $ss < 10; + return $ss . ' seconds ago' if $ss < 45; + return 'a minute ago' if $ss < 90; + return $mm . ' minutes ago' if $mm < 45; + return 'an hour ago' if $mm < 90; + return $hh . ' hours ago' if $hh < 24; + return 'a day ago' if $hh < 36; + return $dd . ' days ago' if $dd < 30; + return 'a month ago' if $dd < 45; + return $mo . ' months ago' if $mo < 12; + return 'a year ago' if $mo < 18; + return $yy . ' years ago'; +} + sub file_mod_time { my ($filename) = (@_); my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, @@ -850,6 +876,17 @@ sub _guess_iso { return $encoding; } +# From Math::Round +use constant ROUND_HALF => 0.50000000000008; +sub round { + my @res = map { + $_ >= 0 + ? floor($_ + ROUND_HALF) + : ceil($_ - ROUND_HALF); + } @_; + return (wantarray) ? @res : $res[0]; +} + 1; __END__ @@ -1161,8 +1198,15 @@ You can optionally specify a timezone for the returned date. If not specified, defaults to the currently-logged-in user's timezone, or the Bugzilla server's local timezone if there isn't a logged-in user. -=back +=item C<time_ago($datetime_object)>, C<time_ago($seconds)> + +Returns a concise representation of the time passed. eg. "11 months ago". +Accepts either a DateTime object, which is assumed to be in the past, or +seconds. + + +=back =head2 Files @@ -1239,3 +1283,23 @@ if Bugzilla is currently using the shadowdb or not. Used like: } =back + +=head2 Math and Numbers + +=over + +=item C<round(@list)> + +Rounds the number(s) to the nearest integer. In scalar context, returns a +single value; in list context, returns a list of values. Numbers that are +halfway between two integers are rounded "to infinity"; i.e., positive values +are rounded up (e.g., 2.5 becomes 3) and negative values down (e.g., -2.5 +becomes -3). + +=begin undocumented + +Lifted directly from Math::Round to avoid a new dependency for trivial code. + +=end undocumented + +=back diff --git a/extensions/BugModal/Config.pm b/extensions/BugModal/Config.pm index b4242753a..a60a99a7a 100644 --- a/extensions/BugModal/Config.pm +++ b/extensions/BugModal/Config.pm @@ -9,13 +9,7 @@ package Bugzilla::Extension::BugModal; use strict; use constant NAME => 'BugModal'; -use constant REQUIRED_MODULES => [ - { - package => 'Time-Duration', - module => 'Time::Duration', - version => 0 - }, -]; +use constant REQUIRED_MODULES => [ ]; use constant OPTIONAL_MODULES => [ ]; __PACKAGE__->NAME; diff --git a/extensions/BugModal/Extension.pm b/extensions/BugModal/Extension.pm index 0bc96e730..f09a53425 100644 --- a/extensions/BugModal/Extension.pm +++ b/extensions/BugModal/Extension.pm @@ -17,10 +17,9 @@ use Bugzilla::Extension::BugModal::MonkeyPatches; use Bugzilla::Extension::BugModal::Util qw(date_str_to_time); use Bugzilla::Constants; use Bugzilla::User::Setting; -use Bugzilla::Util qw(trick_taint datetime_from html_quote); +use Bugzilla::Util qw(trick_taint datetime_from html_quote time_ago); use List::MoreUtils qw(any); use Template::Stash; -use Time::Duration qw(ago); our $VERSION = '1'; @@ -55,7 +54,7 @@ sub template_after_create { my ($self, $args) = @_; my $context = $args->{template}->context; - # wrapper around Time::Duration::ago() + # wrapper around time_ago() $context->define_filter( time_duration => sub { my ($context) = @_; @@ -63,7 +62,7 @@ sub template_after_create { my ($timestamp) = @_; my $datetime = datetime_from($timestamp) // return $timestamp; - return ago(abs(time() - $datetime->epoch)); + return time_ago($datetime); }; }, 1 ); diff --git a/extensions/BugModal/template/en/default/bug_modal/header.html.tmpl b/extensions/BugModal/template/en/default/bug_modal/header.html.tmpl index 13ec7d567..13c146ed5 100644 --- a/extensions/BugModal/template/en/default/bug_modal/header.html.tmpl +++ b/extensions/BugModal/template/en/default/bug_modal/header.html.tmpl @@ -49,11 +49,11 @@ # assets javascript_urls.push( "extensions/ProdCompSearch/web/js/prod_comp_search.js", - "extensions/BugModal/web/time_ago.js", "extensions/BugModal/web/bug_modal.js", "extensions/BugModal/web/ZeroClipboard/ZeroClipboard.min.js", "js/field.js", "js/comments.js", + "js/util.js" ); jquery.push( "datetimepicker", diff --git a/extensions/BugModal/web/bug_modal.js b/extensions/BugModal/web/bug_modal.js index 66e214ad6..32949828f 100644 --- a/extensions/BugModal/web/bug_modal.js +++ b/extensions/BugModal/web/bug_modal.js @@ -8,6 +8,17 @@ $(function() { 'use strict'; + // update relative dates + window.setInterval(function() { + var now = Math.floor(new Date().getTime() / 1000); + $('.rel-time').each(function() { + $(this).text(timeAgo(now - $(this).data('time'))); + }); + $('.rel-time-title').each(function() { + $(this).attr('title', timeAgo(now - $(this).data('time'))); + }); + }, 60000); + // all keywords for autocompletion (lazy-loaded on edit) var keywords = []; diff --git a/extensions/BugModal/web/time_ago.js b/extensions/BugModal/web/time_ago.js deleted file mode 100644 index 59f12692a..000000000 --- a/extensions/BugModal/web/time_ago.js +++ /dev/null @@ -1,142 +0,0 @@ -/* - * this is a port of perl's Time::Duration module, which has the following - * license: - * - * Copyright 2006, Sean M. Burke C<sburke@cpan.org>, all rights reserved. This - * program is free software; you can redistribute it and/or modify it under the - * same terms as Perl itself. - * - * This program is distributed in the hope that it will be useful, but without - * any warranty; without even the implied warranty of merchantability or - * fitness for a particular purpose. - */ - -$(function() { - 'use strict'; - - function separate(seconds) { - // breakdown of seconds into units, starting with the most significant - - var remainder = seconds; - var tmp; - var wheel = []; - - // years - tmp = Math.floor(remainder / (365 * 24 * 60 * 60)); - wheel.push([ 'year', tmp, 1000000000 ]); - remainder -= tmp * (365 * 24 * 60 * 60); - - // days - tmp = Math.floor(remainder / (24 * 60 * 60)); - wheel.push([ 'day', tmp, 365 ]); - remainder -= tmp * (24 * 60 * 60); - - // hours - tmp = Math.floor(remainder / (60 * 60)); - wheel.push([ 'hour', tmp, 24 ]); - remainder -= tmp * (60 * 60); - - // minutes - tmp = Math.floor(remainder / 60); - wheel.push([ 'minute', tmp, 60 ]); - remainder -= tmp * 60; - - // seconds - wheel.push([ 'second', Math.floor(remainder), 60 ]); - return wheel; - } - - function approximate(precision, wheel) { - // now nudge the wheels into an acceptably (im)precise configuration - FIX: do { - // constraints for leaving this block: - // 1) number of nonzero wheels must be <= precision - // 2) no wheels can be improperly expressed (like having "60" for mins) - - var nonzero_count = 0; - var improperly_expressed = -1; - - for (var i = 0; i < wheel.length; i++) { - var tmp = wheel[i]; - if (tmp[1] == 0) { - continue; - } - ++nonzero_count; - if (i == 0) { - // the years wheel is never improper or over any limit; skip - continue; - } - - if (nonzero_count > precision) { - // this is one nonzero wheel too many - - // incr previous wheel if we're big enough - if (tmp[1] >= (tmp[tmp.length - 1] / 2)) { - ++wheel[i - 1][1]; - } - - // reset this and subsequent wheels to 0 - for (var j = i; j < wheel.length; j++) { - wheel[j][1] = 0; - } - - // start over - continue FIX; - - } else if (tmp[1] >= tmp[tmp.length - 1]) { - // it's an improperly expressed wheel (like "60" on the mins wheel) - improperly_expressed = i; - } - } - - if (improperly_expressed != -1) { - // only fix the least-significant improperly expressed wheel (at a time) - ++wheel[improperly_expressed - 1][1]; - wheel[improperly_expressed][1] = 0; - - // start over - continue FIX; - } - - // otherwise there's not too many nonzero wheels, and there's no - //improperly expressed wheels, so fall thru... - } while(0); - - return wheel; - } - - function render(wheel) { - var parts = []; - wheel.forEach(function(element, index) { - if (element[1] > 0) { - parts.push(element[1] + ' ' + element[0]); - if (element[1] != 1) { - parts[parts.length - 1] += 's'; - } - } - }); - - if (parts.length == 0) { - return "just now"; - } - parts[parts.length - 1] += ' ago'; - if (parts.length == 1) { - return parts[0]; - } - if (parts.length == 2) { - return parts[0] + ' and ' + parts[1]; - } - parts[parts.length - 1] = 'and ' + parts[parts.length - 1]; - return parts.join(', '); - } - - window.setInterval(function() { - var now = Math.floor(new Date().getTime() / 1000); - $('.rel-time').each(function() { - $(this).text(render(approximate(2, separate(now - $(this).data('time'))))); - }); - $('.rel-time-title').each(function() { - $(this).attr('title', render(approximate(2, separate(now - $(this).data('time'))))); - }); - }, 60000); -}); diff --git a/extensions/MozReview/web/js/mozreview.js b/extensions/MozReview/web/js/mozreview.js index 2b9575292..e927d366c 100644 --- a/extensions/MozReview/web/js/mozreview.js +++ b/extensions/MozReview/web/js/mozreview.js @@ -8,43 +8,6 @@ var MozReview = {}; -MozReview.formatElapsedTime = function(s, val) { - val = Math.floor(val); - return val + ' ' + s + (val == 1 ? '' : 's') + ' ago'; -}; - -MozReview.elapsedTime = function(d) { - var ms = Date.now() - d; - - var seconds = ms / 1000; - if (seconds < 60) { - return MozReview.formatElapsedTime('second', seconds); - } - - var minutes = seconds / 60; - if (minutes < 60) { - return MozReview.formatElapsedTime('minute', minutes); - } - - var hours = minutes / 60; - if (hours < 24) { - return MozReview.formatElapsedTime('hour', hours); - } - - var days = hours / 24; - if (days < 30) { - return MozReview.formatElapsedTime("day", days); - } - - var months = days / 30; // enh fudge it - if (months < 12) { - return MozReview.formatElapsedTime("month", months); - } - - var years = months / 12; - return MozReview.formatElapsedTime("year", years); -}; - MozReview.getReviewRequest = function() { var hostUrl = $('.mozreview-requests').data('mozreviewUrl'); var tr = $('<tr/>'); @@ -83,7 +46,7 @@ MozReview.getReviewRequest = function() { td.clone().text(rr.status), td.clone().text(rr.issue_open_count) .addClass('mozreview-open-issues'), - td.clone().text(MozReview.elapsedTime(new Date(rr.last_updated))) + td.clone().text(timeAgo(new Date(rr.last_updated))) ); if (rr.status == "discarded") { diff --git a/extensions/MyDashboard/lib/Queries.pm b/extensions/MyDashboard/lib/Queries.pm index 34c63e07b..199e8eb46 100644 --- a/extensions/MyDashboard/lib/Queries.pm +++ b/extensions/MyDashboard/lib/Queries.pm @@ -15,10 +15,9 @@ use Bugzilla::CGI; use Bugzilla::Search; use Bugzilla::Flag; use Bugzilla::Status qw(is_open_state); -use Bugzilla::Util qw(format_time datetime_from); +use Bugzilla::Util qw(format_time datetime_from time_ago); use Bugzilla::Extension::MyDashboard::Util qw(open_states quoted_open_states); -use Bugzilla::Extension::MyDashboard::TimeAgo qw(time_ago); use DateTime; diff --git a/extensions/MyDashboard/lib/TimeAgo.pm b/extensions/MyDashboard/lib/TimeAgo.pm deleted file mode 100644 index 0206bfebd..000000000 --- a/extensions/MyDashboard/lib/TimeAgo.pm +++ /dev/null @@ -1,179 +0,0 @@ -package Bugzilla::Extension::MyDashboard::TimeAgo; - -use strict; -use utf8; -use DateTime; -use Carp; -use Exporter qw(import); - -use if $ENV{ARCH_64BIT}, 'integer'; - -our @EXPORT_OK = qw(time_ago); - -our $VERSION = '0.06'; - -my @ranges = ( - [ -1, 'in the future' ], - [ 60, 'just now' ], - [ 900, 'a few minutes ago'], # 15*60 - [ 3000, 'less than an hour ago'], # 50*60 - [ 4500, 'about an hour ago'], # 75*60 - [ 7200, 'more than an hour ago'], # 2*60*60 - [ 21600, 'several hours ago'], # 6*60*60 - [ 86400, 'today', sub { # 24*60*60 - my $time = shift; - my $now = shift; - if ( $time->day < $now->day - or $time->month < $now->month - or $time->year < $now->year - ) { - return 'yesterday' - } - if ($time->hour < 5) { - return 'tonight' - } - if ($time->hour < 10) { - return 'this morning' - } - if ($time->hour < 15) { - return 'today' - } - if ($time->hour < 19) { - return 'this afternoon' - } - return 'this evening' - }], - [ 172800, 'yesterday'], # 2*24*60*60 - [ 604800, 'this week'], # 7*24*60*60 - [ 1209600, 'last week'], # 2*7*24*60*60 - [ 2678400, 'this month', sub { # 31*24*60*60 - my $time = shift; - my $now = shift; - if ($time->year == $now->year and $time->month == $now->month) { - return 'this month' - } - return 'last month' - }], - [ 5356800, 'last month'], # 2*31*24*60*60 - [ 24105600, 'several months ago'], # 9*31*24*60*60 - [ 31536000, 'about a year ago'], # 365*24*60*60 - [ 34214400, 'last year'], # (365+31)*24*60*60 - [ 63072000, 'more than a year ago'], # 2*365*24*60*60 - [ 283824000, 'several years ago'], # 9*365*24*60*60 - [ 315360000, 'about a decade ago'], # 10*365*24*60*60 - [ 630720000, 'last decade'], # 20*365*24*60*60 - [ 2838240000, 'several decades ago'], # 90*365*24*60*60 - [ 3153600000, 'about a century ago'], # 100*365*24*60*60 - [ 6307200000, 'last century'], # 200*365*24*60*60 - [ 6622560000, 'more than a century ago'], # 210*365*24*60*60 - [ 28382400000, 'several centuries ago'], # 900*365*24*60*60 - [ 31536000000, 'about a millenium ago'], # 1000*365*24*60*60 - [ 63072000000, 'more than a millenium ago'], # 2000*365*24*60*60 -); - -sub time_ago { - my ($time, $now) = @_; - - if (not defined $time or not $time->isa('DateTime')) { - croak('DateTime::Duration::Fuzzy::time_ago needs a DateTime object as first parameter') - } - if (not defined $now) { - $now = DateTime->now(); - } - if (not $now->isa('DateTime')) { - croak('Invalid second parameter provided to DateTime::Duration::Fuzzy::time_ago; it must be a DateTime object if provided') - } - - my $dur = $now->subtract_datetime_absolute($time)->in_units('seconds'); - - foreach my $range ( @ranges ) { - if ( $dur <= $range->[0] ) { - if ( $range->[2] ) { - return $range->[2]->($time, $now) - } - return $range->[1] - } - } - - return 'millenia ago' -} - -1 - -__END__ - -=head1 NAME - -DateTime::Duration::Fuzzy -- express dates as fuzzy human-friendly strings - -=head1 SYNOPSIS - - use DateTime::Duration::Fuzzy qw(time_ago); - use DateTime; - - my $now = DateTime->new( - year => 2010, month => 12, day => 12, - hour => 19, minute => 59, - ); - my $then = DateTime->new( - year => 2010, month => 12, day => 12, - hour => 15, - ); - print time_ago($then, $now); - # outputs 'several hours ago' - - print time_ago($then); - # $now taken from C<time> function - -=head1 DESCRIPTION - -DateTime::Duration::Fuzzy is inspired from the timeAgo jQuery module -L<http://timeago.yarp.com/>. - -It takes two DateTime objects -- first one representing a moment in the past -and second optional one representine the present, and returns a human-friendly -fuzzy expression of the time gone. - -=head2 functions - -=over 4 - -=item time_ago($then, $now) - -The only exportable function. - -First obligatory parameter is a DateTime object. - -Second optional parameter is also a DateTime object. -If it's not provided, then I<now> as the C<time> function returns is -substituted. - -Returns a string expression of the interval between the two DateTime -objects, like C<several hours ago>, C<yesterday> or <last century>. - -=back - -=head2 performance - -On 64bit machines, it is asvisable to 'use integer', which makes -the calculations faster. You can turn this on by setting the -C<ARCH_64BIT> environmental variable to a true value. - -If you do this on a 32bit machine, you will get wrong results for -intervals starting with "several decades ago". - -=head1 AUTHOR - -Jan Oldrich Kruza, C<< <sixtease at cpan.org> >> - -=head1 LICENSE AND COPYRIGHT - -Copyright 2010 Jan Oldrich Kruza. - -This program is free software; you can redistribute it and/or modify it -under the terms of either: the GNU General Public License as published -by the Free Software Foundation; or the Artistic License. - -See http://dev.perl.org/licenses/ for more information. - -=cut diff --git a/extensions/RequestNagger/Extension.pm b/extensions/RequestNagger/Extension.pm index 2be828fd1..0ed517244 100644 --- a/extensions/RequestNagger/Extension.pm +++ b/extensions/RequestNagger/Extension.pm @@ -14,11 +14,10 @@ use base qw(Bugzilla::Extension); use Bugzilla::Constants; use Bugzilla::Error; -use Bugzilla::Extension::RequestNagger::TimeAgo qw(time_ago); use Bugzilla::Flag; use Bugzilla::Install::Filesystem; use Bugzilla::User::Setting; -use Bugzilla::Util qw(datetime_from detaint_natural); +use Bugzilla::Util qw(datetime_from detaint_natural time_ago); use DateTime; our $VERSION = '1'; diff --git a/extensions/RequestNagger/lib/TimeAgo.pm b/extensions/RequestNagger/lib/TimeAgo.pm deleted file mode 100644 index 3dfbbeaac..000000000 --- a/extensions/RequestNagger/lib/TimeAgo.pm +++ /dev/null @@ -1,186 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -# This Source Code Form is "Incompatible With Secondary Licenses", as -# defined by the Mozilla Public License, v. 2.0. - -package Bugzilla::Extension::RequestNagger::TimeAgo; - -use strict; -use utf8; -use DateTime; -use Carp; -use Exporter qw(import); - -use if $ENV{ARCH_64BIT}, 'integer'; - -our @EXPORT_OK = qw(time_ago); - -our $VERSION = '0.06'; - -my @ranges = ( - [ -1, 'in the future' ], - [ 60, 'just now' ], - [ 900, 'a few minutes ago'], # 15*60 - [ 3000, 'less than an hour ago'], # 50*60 - [ 4500, 'about an hour ago'], # 75*60 - [ 7200, 'more than an hour ago'], # 2*60*60 - [ 21600, 'several hours ago'], # 6*60*60 - [ 86400, 'today', sub { # 24*60*60 - my $time = shift; - my $now = shift; - if ( $time->day < $now->day - or $time->month < $now->month - or $time->year < $now->year - ) { - return 'yesterday' - } - if ($time->hour < 5) { - return 'tonight' - } - if ($time->hour < 10) { - return 'this morning' - } - if ($time->hour < 15) { - return 'today' - } - if ($time->hour < 19) { - return 'this afternoon' - } - return 'this evening' - }], - [ 172800, 'yesterday'], # 2*24*60*60 - [ 604800, 'this week'], # 7*24*60*60 - [ 1209600, 'last week'], # 2*7*24*60*60 - [ 2678400, 'this month', sub { # 31*24*60*60 - my $time = shift; - my $now = shift; - if ($time->year == $now->year and $time->month == $now->month) { - return 'this month' - } - return 'last month' - }], - [ 5356800, 'last month'], # 2*31*24*60*60 - [ 24105600, 'several months ago'], # 9*31*24*60*60 - [ 31536000, 'about a year ago'], # 365*24*60*60 - [ 34214400, 'last year'], # (365+31)*24*60*60 - [ 63072000, 'more than a year ago'], # 2*365*24*60*60 - [ 283824000, 'several years ago'], # 9*365*24*60*60 - [ 315360000, 'about a decade ago'], # 10*365*24*60*60 - [ 630720000, 'last decade'], # 20*365*24*60*60 - [ 2838240000, 'several decades ago'], # 90*365*24*60*60 - [ 3153600000, 'about a century ago'], # 100*365*24*60*60 - [ 6307200000, 'last century'], # 200*365*24*60*60 - [ 6622560000, 'more than a century ago'], # 210*365*24*60*60 - [ 28382400000, 'several centuries ago'], # 900*365*24*60*60 - [ 31536000000, 'about a millenium ago'], # 1000*365*24*60*60 - [ 63072000000, 'more than a millenium ago'], # 2000*365*24*60*60 -); - -sub time_ago { - my ($time, $now) = @_; - - if (not defined $time or not $time->isa('DateTime')) { - croak('DateTime::Duration::Fuzzy::time_ago needs a DateTime object as first parameter') - } - if (not defined $now) { - $now = DateTime->now(); - } - if (not $now->isa('DateTime')) { - croak('Invalid second parameter provided to DateTime::Duration::Fuzzy::time_ago; it must be a DateTime object if provided') - } - - my $dur = $now->subtract_datetime_absolute($time)->in_units('seconds'); - - foreach my $range ( @ranges ) { - if ( $dur <= $range->[0] ) { - if ( $range->[2] ) { - return $range->[2]->($time, $now) - } - return $range->[1] - } - } - - return 'millenia ago' -} - -1 - -__END__ - -=head1 NAME - -DateTime::Duration::Fuzzy -- express dates as fuzzy human-friendly strings - -=head1 SYNOPSIS - - use DateTime::Duration::Fuzzy qw(time_ago); - use DateTime; - - my $now = DateTime->new( - year => 2010, month => 12, day => 12, - hour => 19, minute => 59, - ); - my $then = DateTime->new( - year => 2010, month => 12, day => 12, - hour => 15, - ); - print time_ago($then, $now); - # outputs 'several hours ago' - - print time_ago($then); - # $now taken from C<time> function - -=head1 DESCRIPTION - -DateTime::Duration::Fuzzy is inspired from the timeAgo jQuery module -L<http://timeago.yarp.com/>. - -It takes two DateTime objects -- first one representing a moment in the past -and second optional one representine the present, and returns a human-friendly -fuzzy expression of the time gone. - -=head2 functions - -=over 4 - -=item time_ago($then, $now) - -The only exportable function. - -First obligatory parameter is a DateTime object. - -Second optional parameter is also a DateTime object. -If it's not provided, then I<now> as the C<time> function returns is -substituted. - -Returns a string expression of the interval between the two DateTime -objects, like C<several hours ago>, C<yesterday> or <last century>. - -=back - -=head2 performance - -On 64bit machines, it is asvisable to 'use integer', which makes -the calculations faster. You can turn this on by setting the -C<ARCH_64BIT> environmental variable to a true value. - -If you do this on a 32bit machine, you will get wrong results for -intervals starting with "several decades ago". - -=head1 AUTHOR - -Jan Oldrich Kruza, C<< <sixtease at cpan.org> >> - -=head1 LICENSE AND COPYRIGHT - -Copyright 2010 Jan Oldrich Kruza. - -This program is free software; you can redistribute it and/or modify it -under the terms of either: the GNU General Public License as published -by the Free Software Foundation; or the Artistic License. - -See http://dev.perl.org/licenses/ for more information. - -=cut diff --git a/extensions/UserProfile/Extension.pm b/extensions/UserProfile/Extension.pm index 8671ba755..4fe1436c0 100644 --- a/extensions/UserProfile/Extension.pm +++ b/extensions/UserProfile/Extension.pm @@ -13,11 +13,10 @@ use warnings; use base qw(Bugzilla::Extension); use Bugzilla::Constants; -use Bugzilla::Extension::UserProfile::TimeAgo qw(time_ago); use Bugzilla::Extension::UserProfile::Util; use Bugzilla::Install::Filesystem; use Bugzilla::User; -use Bugzilla::Util qw(datetime_from); +use Bugzilla::Util qw(datetime_from time_ago); use Email::Address; use Scalar::Util qw(blessed); diff --git a/extensions/UserProfile/lib/TimeAgo.pm b/extensions/UserProfile/lib/TimeAgo.pm deleted file mode 100644 index d20f0edf5..000000000 --- a/extensions/UserProfile/lib/TimeAgo.pm +++ /dev/null @@ -1,179 +0,0 @@ -package Bugzilla::Extension::UserProfile::TimeAgo; - -use strict; -use utf8; -use DateTime; -use Carp; -use Exporter qw(import); - -use if $ENV{ARCH_64BIT}, 'integer'; - -our @EXPORT_OK = qw(time_ago); - -our $VERSION = '0.06'; - -my @ranges = ( - [ -1, 'in the future' ], - [ 60, 'just now' ], - [ 900, 'a few minutes ago'], # 15*60 - [ 3000, 'less than an hour ago'], # 50*60 - [ 4500, 'about an hour ago'], # 75*60 - [ 7200, 'more than an hour ago'], # 2*60*60 - [ 21600, 'several hours ago'], # 6*60*60 - [ 86400, 'today', sub { # 24*60*60 - my $time = shift; - my $now = shift; - if ( $time->day < $now->day - or $time->month < $now->month - or $time->year < $now->year - ) { - return 'yesterday' - } - if ($time->hour < 5) { - return 'tonight' - } - if ($time->hour < 10) { - return 'this morning' - } - if ($time->hour < 15) { - return 'today' - } - if ($time->hour < 19) { - return 'this afternoon' - } - return 'this evening' - }], - [ 172800, 'yesterday'], # 2*24*60*60 - [ 604800, 'this week'], # 7*24*60*60 - [ 1209600, 'last week'], # 2*7*24*60*60 - [ 2678400, 'this month', sub { # 31*24*60*60 - my $time = shift; - my $now = shift; - if ($time->year == $now->year and $time->month == $now->month) { - return 'this month' - } - return 'last month' - }], - [ 5356800, 'last month'], # 2*31*24*60*60 - [ 24105600, 'several months ago'], # 9*31*24*60*60 - [ 31536000, 'about a year ago'], # 365*24*60*60 - [ 34214400, 'last year'], # (365+31)*24*60*60 - [ 63072000, 'more than a year ago'], # 2*365*24*60*60 - [ 283824000, 'several years ago'], # 9*365*24*60*60 - [ 315360000, 'about a decade ago'], # 10*365*24*60*60 - [ 630720000, 'last decade'], # 20*365*24*60*60 - [ 2838240000, 'several decades ago'], # 90*365*24*60*60 - [ 3153600000, 'about a century ago'], # 100*365*24*60*60 - [ 6307200000, 'last century'], # 200*365*24*60*60 - [ 6622560000, 'more than a century ago'], # 210*365*24*60*60 - [ 28382400000, 'several centuries ago'], # 900*365*24*60*60 - [ 31536000000, 'about a millenium ago'], # 1000*365*24*60*60 - [ 63072000000, 'more than a millenium ago'], # 2000*365*24*60*60 -); - -sub time_ago { - my ($time, $now) = @_; - - if (not defined $time or not $time->isa('DateTime')) { - croak('DateTime::Duration::Fuzzy::time_ago needs a DateTime object as first parameter') - } - if (not defined $now) { - $now = DateTime->now(); - } - if (not $now->isa('DateTime')) { - croak('Invalid second parameter provided to DateTime::Duration::Fuzzy::time_ago; it must be a DateTime object if provided') - } - - my $dur = $now->subtract_datetime_absolute($time)->in_units('seconds'); - - foreach my $range ( @ranges ) { - if ( $dur <= $range->[0] ) { - if ( $range->[2] ) { - return $range->[2]->($time, $now) - } - return $range->[1] - } - } - - return 'millenia ago' -} - -1 - -__END__ - -=head1 NAME - -DateTime::Duration::Fuzzy -- express dates as fuzzy human-friendly strings - -=head1 SYNOPSIS - - use DateTime::Duration::Fuzzy qw(time_ago); - use DateTime; - - my $now = DateTime->new( - year => 2010, month => 12, day => 12, - hour => 19, minute => 59, - ); - my $then = DateTime->new( - year => 2010, month => 12, day => 12, - hour => 15, - ); - print time_ago($then, $now); - # outputs 'several hours ago' - - print time_ago($then); - # $now taken from C<time> function - -=head1 DESCRIPTION - -DateTime::Duration::Fuzzy is inspired from the timeAgo jQuery module -L<http://timeago.yarp.com/>. - -It takes two DateTime objects -- first one representing a moment in the past -and second optional one representine the present, and returns a human-friendly -fuzzy expression of the time gone. - -=head2 functions - -=over 4 - -=item time_ago($then, $now) - -The only exportable function. - -First obligatory parameter is a DateTime object. - -Second optional parameter is also a DateTime object. -If it's not provided, then I<now> as the C<time> function returns is -substituted. - -Returns a string expression of the interval between the two DateTime -objects, like C<several hours ago>, C<yesterday> or <last century>. - -=back - -=head2 performance - -On 64bit machines, it is asvisable to 'use integer', which makes -the calculations faster. You can turn this on by setting the -C<ARCH_64BIT> environmental variable to a true value. - -If you do this on a 32bit machine, you will get wrong results for -intervals starting with "several decades ago". - -=head1 AUTHOR - -Jan Oldrich Kruza, C<< <sixtease at cpan.org> >> - -=head1 LICENSE AND COPYRIGHT - -Copyright 2010 Jan Oldrich Kruza. - -This program is free software; you can redistribute it and/or modify it -under the terms of either: the GNU General Public License as published -by the Free Software Foundation; or the Artistic License. - -See http://dev.perl.org/licenses/ for more information. - -=cut diff --git a/js/util.js b/js/util.js index 78b64b516..c27dc2b11 100644 --- a/js/util.js +++ b/js/util.js @@ -341,3 +341,30 @@ function bz_toggleClass(anElement, aClass) { YAHOO.util.Dom.addClass(anElement, aClass); } } + +/* Retruns a string representation of a duration. + * + * @param ss Duration in seconds + * or + * @param date Date object + */ +function timeAgo(param) { + var ss = param.constructor === Date ? Math.round((new Date() - param) / 1000) : param; + var mm = Math.round(ss / 60), + hh = Math.round(mm / 60), + dd = Math.round(hh / 24), + mo = Math.round(dd / 30), + yy = Math.round(mo / 12); + if (ss < 10) return 'just now'; + if (ss < 45) return ss + ' seconds ago'; + if (ss < 90) return 'a minute ago'; + if (mm < 45) return mm + ' minutes ago'; + if (mm < 90) return 'an hour ago'; + if (hh < 24) return hh + ' hours ago'; + if (hh < 36) return 'a day ago'; + if (dd < 30) return dd + ' days ago'; + if (dd < 45) return 'a month ago'; + if (mo < 12) return mo + ' months ago'; + if (mo < 18) return 'a year ago'; + return yy + ' years ago'; +} |