How to calculate and format time left for each downloading file using webclient?

jdoe doe 20 Reputation points
2024-01-09T02:49:37.8133333+00:00

This is the part that calculate the time left to download the current file:

if (e.BytesReceived > 0 && e.BytesReceived < e.TotalBytesToReceive)
{
    double downloadRate = e.BytesReceived / timeElapsed.TotalSeconds;
    double remainingBytes = totalBytes - bytesIn;
    double timeLeftInSeconds = remainingBytes / downloadRate;

    if (timeLeftInSeconds > 0)
    {
        TimeSpan timeLeft = TimeSpan.FromSeconds(timeLeftInSeconds);

        // Display time left
        lblTimeLeftReporter.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", timeLeft.Hours, timeLeft.Minutes, timeLeft.Seconds);
    }
}

The result is that much of the time I see on the label 00:00:00 and the only value that get update is the rightest end zero change in range between 1 and 2 sometimes more.

and what I wanted it should like a timer or something else formatted nice that will estimate and display counting back the time left to download.

it's updating very fast the last milliseconds?)

in the screenshot you can see the 6 but it's not seconds, it's more milliseconds or so. and I also noticed that when the file gets downloaded almost to the half then the time left label showing only 00:00:00 until the end of the file download.

it' not calculating and showing the real estimate time left to download. downloading 1 GB file at least should take some seconds if not minute/s

tl2

This is how I make the calculations:

void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    double bytesIn = e.BytesReceived;
    double totalBytes = e.TotalBytesToReceive;
    double percentage = bytesIn / totalBytes * 100;

    // Update progress bar
    progressBar1.Value = (int)Math.Truncate(percentage);

    // Calculate download speed
    DateTime now = DateTime.Now;
    TimeSpan timeElapsed = now - lastProgressUpdateTime;

    if (timeElapsed.TotalMilliseconds > 500)  // Update speed every 500 milliseconds
    {
        long bytesSinceLastUpdate = e.BytesReceived - lastProgressUpdateBytes;
        double speedInBytesPerSecond = bytesSinceLastUpdate / timeElapsed.TotalSeconds;

        // Fix the negative problem
        if (speedInBytesPerSecond < 0)
        {
            speedInBytesPerSecond = 0;
        }

        // Display download speed
        lblSpeedReporter.Text = FormatBytes(speedInBytesPerSecond) + "/s";

        lastProgressUpdateTime = now;
        lastProgressUpdateBytes = e.BytesReceived;
    }

    // Display downloaded size
    lblSizeReporter.Text = string.Format("{0} / {1}", FormatBytes(bytesIn), FormatBytes(totalBytes));

    // Calculate time left
    if (e.BytesReceived > 0 && e.BytesReceived < e.TotalBytesToReceive)
    {
        double downloadRate = e.BytesReceived / timeElapsed.TotalSeconds;
        double remainingBytes = totalBytes - bytesIn;
        double timeLeftInSeconds = remainingBytes / downloadRate;

        if (timeLeftInSeconds > 0)
        {
            TimeSpan timeLeft = TimeSpan.FromSeconds(timeLeftInSeconds);

            // Display time left
            lblTimeLeftReporter.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", timeLeft.Hours, timeLeft.Minutes, timeLeft.Seconds);
        }
    }
}
Developer technologies | Windows Forms
Developer technologies | C#
{count} votes

Accepted answer
  1. Anonymous
    2024-01-09T07:09:50.2+00:00

    Hi @jdoe doe , Welcome to Microsoft Q&A,

    First you can follow Viorel's advice and modify the part of your download speed calculation.

    Secondly, you can add a Queue<double> speedHistory to store the history of download speed in order to calculate the moving average. This makes the speed relatively accurate.

    private DateTime startTime;
    
    void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        double newBytesIn = e.BytesReceived;
        double newTotalBytes = e.TotalBytesToReceive;
        double percentage = newBytesIn / newTotalBytes * 100;
    
        // Update progress bar
        progressBar1.Value = (int)Math.Truncate(percentage);
    
        // Calculate download speed
        DateTime now = DateTime.Now;
        TimeSpan timeElapsed = now - lastProgressUpdateTime;
    
        if (timeElapsed.TotalMilliseconds > 500)  // Update speed every 500 milliseconds
        {
            long bytesSinceLastUpdate = e.BytesReceived - lastProgressUpdateBytes;
            double speedInBytesPerSecond = bytesSinceLastUpdate / timeElapsed.TotalSeconds;
    
            // Fix the negative problem
            if (speedInBytesPerSecond < 0)
            {
                speedInBytesPerSecond = 0;
            }
    
            // Add the speed to the history
            speedHistory.Enqueue(speedInBytesPerSecond);
            if (speedHistory.Count > 5) // You can adjust the number of elements to use in the moving average
            {
                speedHistory.Dequeue();
            }
    
            // Calculate average speed
            double averageSpeed = speedHistory.Average();
    
            // Display download speed
            lblSpeedReporter.Text = FormatBytes(averageSpeed) + "/s";
    
            lastProgressUpdateTime = now;
            lastProgressUpdateBytes = e.BytesReceived;
        }
    
        // Display downloaded size
        lblSizeReporter.Text = string.Format("{0} / {1}", FormatBytes(newBytesIn), FormatBytes(newTotalBytes));
    
        // Calculate time left
        if (newBytesIn > 0 && newBytesIn < newTotalBytes)
        {
            double downloadRate = averageSpeed; // Use the average speed
            double remainingBytes = newTotalBytes - newBytesIn;
            double timeLeftInSeconds = remainingBytes / downloadRate;
    
            if (timeLeftInSeconds > 0)
            {
                TimeSpan timeLeft = TimeSpan.FromSeconds(timeLeftInSeconds);
    
                // Display time left
                lblTimeLeftReporter.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", timeLeft.Hours, timeLeft.Minutes, timeLeft.Seconds);
            }
        }
    }
    
    string FormatBytes(double bytes)
    {
        string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
        int suffixIndex = 0;
        while (bytes >= 1024 && suffixIndex < suffixes.Length - 1)
        {
            bytes /= 1024;
            suffixIndex++;
        }
    
        return string.Format("{0:0.##} {1}", bytes, suffixes[suffixIndex]);
    }
    

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.