improve time display
Closed this issue · 5 comments
Time is stored in the database in seconds. For the first iteration of displaying time on user profiles, I simply converted to hours and rounded to 2 decimal places. Some sites with very little time still show 0.0 hours (less ~36 seconds). I need a better way to display this...
To display hours or minutes or seconds, do something like this:
if seconds >= 3600
seconds / 3600.0 + " hours" # round this to 1 decimal place
elsif seconds >= 60
seconds / 60.0 + " minutes" # round this to 1 decimal place
else
seconds + " seconds"
Pros
- Display lower time values with greater precision.
- More plain English
Cons
- Could jumble the display
Here's my JS implementation of the above.. is_diff
is a trick to prevent non-decimal values from being forced to show 1 decimal place.
// time: time in seconds
function format_time(time){
if(time >= 3600){
return (time / 3600.0).toFixed(is_diff(time, 3600)) + " hours";
}
else if(time >= 60.0){
return (time / 60.0).toFixed(is_diff(time, 60)) + " minutes";
}
else{
return time + " seconds";
}
}
// returns 0 if the numbers are equal, 1 otherwise
function is_diff(num1, num2){
return Math.abs(Math.sign(num1 - num2));
}
I can't help but look at this and think there is a way to write this using a strategy pattern-esque thing to prevent repetition and easily add more units (days/months/years)...
Here's a DRY solution implemented in the client popup.js
.
// input: time in seconds
// output: "3.4 minutes", "3 weeks", "1 day", for example
function format_time(time){
var units = [
{
name: "year",
seconds: 31536000
},
{
name: "month",
seconds: 2592000
},
{
name: "week",
seconds: 604800
},
{
name: "day",
seconds: 86400
},
{
name: "hour",
seconds: 3600
},
{
name: "minute",
seconds: 60
},
{
name: "second",
seconds: 1
}
];
for(var unit of units){
if(time >= unit.seconds){
return (time / unit.seconds).toFixed(is_divisible(time, unit.seconds)) + " " + unit.name +
Array(1 + is_equal(time, unit.seconds)).join('s'); // plural or not
}
}
// returns 0 if the numbers are equal, 1 otherwise
function is_equal(num1, num2){
return Math.abs(Math.sign((num1/num2).toFixed(1) - 1));
}
// returns 0 if the first number is divisible by the second, 1 otherwise
function is_divisible(num1, num2){
return Math.abs(Math.sign((num1/num2).toFixed(1) % 1));
}
}
TODO: Implement in RoR and replace all instances of "# hours".
Ruby implementation is a bit more cryptic than JS..
def format_time num
units = [
{
name: "year",
seconds: 31536000.0
},
{
name: "month",
seconds: 2592000.0
},
{
name: "week",
seconds: 604800.0
},
{
name: "day",
seconds: 86400.0
},
{
name: "hour",
seconds: 3600.0
},
{
name: "minute",
seconds: 60.0
},
{
name: "second",
seconds: 1.0
}
]
# 0 if the numbers are equal, 1 otherwise
is_equal = Proc.new do |num1, num2|
# ~= Math.abs(Math.sign((num1/num2).toFixed(1) - 1));
((('%.1f' % (num1 / num2)).to_f - 1) <=> 0).abs
end
# 0 if the first number is divisible by the second, 1 otherwise
is_divisible = Proc.new do |num1, num2|
# ~=Math.abs(Math.sign((num1/num2).toFixed(1) % 1));
((('%.1f' % (num1 / num2)).to_f % 1) <=> 0).abs
end
units.each do |unit|
if num >= unit[:seconds]
dec_format = ('%.' + (is_divisible.call(num, unit[:seconds])).to_s + 'f') % (num / unit[:seconds])
s = 's' * is_equal.call(num, unit[:seconds]) # 's' or ''
return dec_format + " " + unit[:name] + s
end
end
end