document.title = 'Jirafeau - 100%';
 }
 
-function show_upload_progression (percentage, speed, time)
+function show_upload_progression (percentage, speed, time_left)
 {
     document.getElementById('uploaded_percentage').innerHTML = percentage;
     document.getElementById('uploaded_speed').innerHTML = speed;
-    document.getElementById('uploaded_time').innerHTML = time;
+    document.getElementById('uploaded_time').innerHTML = time_left;
     document.title = 'Jirafeau - ' + percentage;
 }
 
     upload_time_estimation_add(e.loaded);
     // Get speed string
     var speed_str = upload_time_estimation_speed_string();
-    // Get remaining time string
-    var time_str = upload_time_estimation_time_string();
+    // Get time string
+    var time_str = chrono_update(upload_time_estimation_time());
     
     show_upload_progression (p_str, speed_str, time_str);
 }
     upload_time_estimation_add(e.loaded + async_global_transfered);
     // Get speed string
     var speed_str = upload_time_estimation_speed_string();
-    // Get remaining time string
-    var time_str = upload_time_estimation_time_string();
-    
+    // Get time string
+    var time_str = chrono_update(upload_time_estimation_time());
+
     show_upload_progression (p_str, speed_str, time_str);
 }
 
     upload_time_estimation_transfered_size = 0;
     upload_time_estimation_moving_average_speed = 0;
     var d = new Date();
-    upload_time_estimation_transfered_date = d.getMilliseconds();
+    upload_time_estimation_transfered_date = d.getTime();
 }
 
 function upload_time_estimation_add(total_transfered_size)
     // Let's compute the current speed
     var d = new Date();
     var speed = upload_time_estimation_moving_average_speed;
-    if (d.getMilliseconds() - upload_time_estimation_transfered_date != 0)
+    if (d.getTime() - upload_time_estimation_transfered_date != 0)
         speed = (total_transfered_size - upload_time_estimation_transfered_size)
-                / (d.getMilliseconds() - upload_time_estimation_transfered_date);
+                / (d.getTime() - upload_time_estimation_transfered_date);
     // Let's compute moving average speed on 30 values
     var m = (upload_time_estimation_moving_average_speed * 29 + speed) / 30;
     // Update global values
     upload_time_estimation_transfered_size = total_transfered_size;
-    upload_time_estimation_transfered_date = d.getMilliseconds();
+    upload_time_estimation_transfered_date = d.getTime();
     upload_time_estimation_moving_average_speed = m;
 }
 
     }
     else if (s < 1000000)
     {
-        res = Math.floor(s/1000) + ((Math.floor(s/100) - (Math.floor(s/1000) * 10)) / 10);
+        res = Math.floor(s/100) / 10;
         scale = "Ko/s";
     }
     else
     {
-        res = Math.floor(s/1000000) + ((Math.floor(s/100000) - (Math.floor(s/1000000) * 10)) / 10);
+        res = Math.floor(s/100000) / 10;
         scale = "Mo/s";
     }
     if (res == 0)
         return res.toString() + ' ' + scale;
 }
 
-function milliseconds_to_date_string (milliseconds)
+function milliseconds_to_time_string (milliseconds)
 {
     function numberEnding (number) {
         return (number > 1) ? 's' : '';
     return 'less than a second';
 }
 
-function upload_time_estimation_time_string()
+function upload_time_estimation_time()
 {
     // Estimate remaining time
-    var t = (upload_time_estimation_total_size - upload_time_estimation_transfered_size)
+    if (upload_time_estimation_moving_average_speed == 0)
+        return 0;
+    return (upload_time_estimation_total_size - upload_time_estimation_transfered_size)
             / upload_time_estimation_moving_average_speed;
-    if (t == -1)
-        return ''
-    else
-        return milliseconds_to_date_string (t);
 }
 
+var chrono_last_update = 0;
+var chrono_time_ms = 0;
+var chrono_time_ms_last_update = 0;
+function chrono_update(time_ms)
+{
+    var d = new Date();
+    var chrono = 0;
+    // Don't update too often
+    if (d.getTime() - chrono_last_update < 3000 &&
+        chrono_time_ms_last_update > 0)
+        chrono = chrono_time_ms;
+    else
+    {
+        chrono_last_update = d.getTime();
+        chrono_time_ms = time_ms;
+        chrono = time_ms;
+        chrono_time_ms_last_update = d.getTime();
+    }
+
+    // Adjust chrono for smooth estimation
+    chrono = chrono - (d.getTime() - chrono_time_ms_last_update);
+
+    // Let's update chronometer
+    var time_str = '';
+    if (chrono > 0)
+        time_str = milliseconds_to_time_string (chrono);
+    return time_str;
+}