Skip to content

Commit da70522

Browse files
authored
Bug 1994219 - Bugs updated in the last 24-48 hours are marked as "Updated 1 days ago"
1 parent e3f41a9 commit da70522

File tree

3 files changed

+93
-38
lines changed

3 files changed

+93
-38
lines changed

Bugzilla/Util.pm

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -649,25 +649,26 @@ sub time_ago {
649649

650650
# DateTime object or seconds
651651
my $ss = ref($param) ? time() - $param->epoch : $param;
652-
my $mm = round($ss / 60);
653-
my $hh = round($ss / (60 * 60));
654-
my $dd = round($ss / (60 * 60 * 24));
652+
# Use floor for intermediate calculations to avoid rounding issues
653+
my $mm = floor($ss / 60);
654+
my $hh = floor($ss / (60 * 60));
655+
my $dd = floor($ss / (60 * 60 * 24));
655656
# They are not the best definition of month and year,
656657
# but they should be good enough to be used here.
657-
my $mo = round($ss / (60 * 60 * 24 * 30));
658-
my $yy = round($ss / (60 * 60 * 24 * 365.2422));
658+
my $mo = floor($ss / (60 * 60 * 24 * 30));
659+
my $yy = floor($ss / (60 * 60 * 24 * 365.2422));
659660

660661
return 'Just now' if $ss < 10;
661662
return $ss . ' seconds ago' if $ss < 45;
662-
return '1 minute ago' if $ss < 90;
663+
return '1 minute ago' if $mm < 2;
663664
return $mm . ' minutes ago' if $mm < 45;
664-
return '1 hour ago' if $mm < 90;
665+
return '1 hour ago' if $hh < 2;
665666
return $hh . ' hours ago' if $hh < 24;
666-
return '1 day ago' if $hh < 36;
667+
return '1 day ago' if $dd < 2;
667668
return $dd . ' days ago' if $dd < 30;
668-
return '1 month ago' if $dd < 45;
669+
return '1 month ago' if $mo < 2;
669670
return $mo . ' months ago' if $mo < 12;
670-
return '1 year ago' if $mo < 18;
671+
return '1 year ago' if $yy < 2;
671672
return $yy . ' years ago';
672673
}
673674

@@ -976,7 +977,7 @@ sub extract_nicks {
976977

977978
# This routine is used to determine the latest versions for a
978979
# given product from an external system. We need to fail gracefully
979-
# if the external system is down for any reason. If the call fails,
980+
# if the external system is down for any reason. If the call fails,
980981
# then return undefined and let the caller decide what to do.
981982
sub fetch_product_versions {
982983
my ($product) = @_;

js/util.js

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -339,34 +339,35 @@ function bz_toggleClass(anElement, aClass) {
339339
anElement?.classList.toggle(aClass);
340340
}
341341

342-
/* Returns a string representation of a duration.
343-
*
344-
* @param ss Duration in seconds
345-
* or
346-
* @param date Date object
342+
/**
343+
* Returns a string representation of a duration.
344+
* @param {number | Date} param Duration in seconds or a Date object.
345+
* @returns {string} Human-readable time ago string.
347346
*/
348-
function timeAgo(param) {
349-
var ss = param.constructor === Date ? Math.round((new Date() - param) / 1000) : param;
350-
var mm = Math.round(ss / 60),
351-
hh = Math.round(ss / (60 * 60)),
352-
dd = Math.round(ss / (60 * 60 * 24)),
353-
// They are not the best definition of month and year,
354-
// but they should be good enough to be used here.
355-
mo = Math.round(ss / (60 * 60 * 24 * 30)),
356-
yy = Math.round(ss / (60 * 60 * 24 * 365.2422));
347+
const timeAgo = (param) => {
348+
const ss = param.constructor === Date ? Math.round((new Date() - param) / 1000) : param;
349+
// Use Math.floor for intermediate calculations to avoid rounding issues
350+
const mm = Math.floor(ss / 60);
351+
const hh = Math.floor(ss / (60 * 60));
352+
const dd = Math.floor(ss / (60 * 60 * 24));
353+
// They are not the best definition of month and year,
354+
// but they should be good enough to be used here.
355+
const mo = Math.floor(ss / (60 * 60 * 24 * 30));
356+
const yy = Math.floor(ss / (60 * 60 * 24 * 365.2422));
357+
357358
if (ss < 10) return 'Just now';
358-
if (ss < 45) return ss + ' seconds ago';
359-
if (ss < 90) return '1 minute ago';
360-
if (mm < 45) return mm + ' minutes ago';
361-
if (mm < 90) return '1 hour ago';
362-
if (hh < 24) return hh + ' hours ago';
363-
if (hh < 36) return '1 day ago';
364-
if (dd < 30) return dd + ' days ago';
365-
if (dd < 45) return '1 month ago';
366-
if (mo < 12) return mo + ' months ago';
367-
if (mo < 18) return '1 year ago';
368-
return yy + ' years ago';
369-
}
359+
if (ss < 45) return `${ss} seconds ago`;
360+
if (mm < 2) return '1 minute ago';
361+
if (mm < 45) return `${mm} minutes ago`;
362+
if (hh < 2) return '1 hour ago';
363+
if (hh < 24) return `${hh} hours ago`;
364+
if (dd < 2) return '1 day ago';
365+
if (dd < 30) return `${dd} days ago`;
366+
if (mo < 2) return '1 month ago';
367+
if (mo < 12) return `${mo} months ago`;
368+
if (yy < 2) return '1 year ago';
369+
return `${yy} years ago`;
370+
};
370371

371372
/**
372373
* Format the given date as Bugzilla’s standard date format.

t/007util.t

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use warnings;
1515

1616
use lib qw(. lib local/lib/perl5 t);
1717
use Support::Files;
18-
use Test::More tests => 20;
18+
use Test::More tests => 52;
1919
use DateTime;
2020

2121
BEGIN {
@@ -114,3 +114,56 @@ my ($removed, $added) = diff_arrays(\@old_array, \@new_array);
114114
is_deeply($removed, [qw(gamma alpha gamma)],
115115
'diff_array(\@old, \@new) (check removal)');
116116
is_deeply($added, [qw(delta)], 'diff_array(\@old, \@new) (check addition)');
117+
118+
# time_ago():
119+
# Test with seconds
120+
is(time_ago(5), 'Just now', 'time_ago(5) returns "Just now"');
121+
is(time_ago(9), 'Just now', 'time_ago(9) returns "Just now"');
122+
is(time_ago(10), '10 seconds ago', 'time_ago(10) returns "10 seconds ago"');
123+
is(time_ago(30), '30 seconds ago', 'time_ago(30) returns "30 seconds ago"');
124+
is(time_ago(44), '44 seconds ago', 'time_ago(44) returns "44 seconds ago"');
125+
126+
# Test minute boundaries
127+
is(time_ago(45), '1 minute ago', 'time_ago(45) returns "1 minute ago"');
128+
is(time_ago(60), '1 minute ago', 'time_ago(60) returns "1 minute ago"');
129+
is(time_ago(90), '1 minute ago', 'time_ago(90) returns "1 minute ago"');
130+
is(time_ago(119), '1 minute ago', 'time_ago(119) returns "1 minute ago"');
131+
is(time_ago(120), '2 minutes ago', 'time_ago(120) returns "2 minutes ago"');
132+
133+
# Test hour boundaries - critical for the bug fix
134+
is(time_ago(60 * 44), '44 minutes ago', 'time_ago(44 minutes) returns "44 minutes ago"');
135+
is(time_ago(60 * 60), '1 hour ago', 'time_ago(60 minutes) returns "1 hour ago"');
136+
is(time_ago(60 * 90), '1 hour ago', 'time_ago(90 minutes) returns "1 hour ago"');
137+
is(time_ago(60 * 119), '1 hour ago', 'time_ago(119 minutes) returns "1 hour ago"');
138+
is(time_ago(60 * 120), '2 hours ago', 'time_ago(2 hours) returns "2 hours ago"');
139+
140+
# Test day boundaries - this is where the bug was most visible
141+
is(time_ago(60 * 60 * 23), '23 hours ago', 'time_ago(23 hours) returns "23 hours ago"');
142+
is(time_ago(60 * 60 * 24), '1 day ago', 'time_ago(24 hours) returns "1 day ago"');
143+
is(time_ago(60 * 60 * 36), '1 day ago', 'time_ago(36 hours) returns "1 day ago"');
144+
is(time_ago(60 * 60 * 47), '1 day ago', 'time_ago(47 hours) returns "1 day ago"');
145+
is(time_ago(60 * 60 * 48), '2 days ago', 'time_ago(48 hours) returns "2 days ago"');
146+
is(time_ago(60 * 60 * 72), '3 days ago', 'time_ago(72 hours) returns "3 days ago"');
147+
148+
# Test month boundaries
149+
is(time_ago(60 * 60 * 24 * 29), '29 days ago', 'time_ago(29 days) returns "29 days ago"');
150+
is(time_ago(60 * 60 * 24 * 30), '1 month ago', 'time_ago(30 days) returns "1 month ago"');
151+
is(time_ago(60 * 60 * 24 * 45), '1 month ago', 'time_ago(45 days) returns "1 month ago"');
152+
is(time_ago(60 * 60 * 24 * 59), '1 month ago', 'time_ago(59 days) returns "1 month ago"');
153+
is(time_ago(60 * 60 * 24 * 60), '2 months ago', 'time_ago(60 days) returns "2 months ago"');
154+
155+
# Test year boundaries
156+
is(time_ago(60 * 60 * 24 * 365), '1 year ago', 'time_ago(365 days) returns "1 year ago"');
157+
is(time_ago(60 * 60 * 24 * 547), '1 year ago', 'time_ago(547 days) returns "1 year ago"');
158+
is(time_ago(60 * 60 * 24 * 731), '2 years ago', 'time_ago(731 days) returns "2 years ago"');
159+
160+
# Test with DateTime object
161+
my $now = DateTime->now();
162+
my $past = $now->clone->subtract(hours => 25);
163+
is(time_ago($past), '1 day ago', 'time_ago(DateTime 25 hours ago) returns "1 day ago"');
164+
165+
$past = $now->clone->subtract(days => 2);
166+
is(time_ago($past), '2 days ago', 'time_ago(DateTime 2 days ago) returns "2 days ago"');
167+
168+
$past = $now->clone->subtract(months => 1);
169+
like(time_ago($past), qr/^(1 month|2[89]|3[01] days) ago$/, 'time_ago(DateTime 1 month ago) is reasonable');

0 commit comments

Comments
 (0)