Convert milliseconds to human readable time lapse
Asked Answered
H

13

78

I would like to format some commands execution times in a human readable format, for example:

3 -> 3ms
1100 -> 1s 100ms
62000 -> 1m 2s
etc ..

Taking into account days, hours, minutes, seconds, ...

Is it possible using C#?

Homophony answered 3/4, 2012 at 13:4 Comment(6)
Basically you just have to use modulo and division.Larisa
how about new TimeSpan(30000).ToString()?Alida
Well, I'm asking because I have other things to do here, in my company, better than basic programming exercises ;-)Giffin
@DanielPeñalba: then, instead of asking whether it's possible using C# (yes, it is), you should have asked "is there a ready-made class which does this?"Guck
So you're basically asking for a TimeSpan.Format custom string that doesn't result in "0 years 0 months 0 days 0 hours 0 min 1 sec 100 ms"?Odine
If you have 'long milliseconds' then a quick way is 'milliseconds.ToString("n0")' -- this inserts commas as thousands separators, making it easy to see where the seconds are. Not the most human readable, but handy if you're in a hurry or don't want to bother creating a TimeSpan.Commission
B
139

You can use TimeSpan class, something like this:

TimeSpan t = TimeSpan.FromMilliseconds(ms);
string answer = string.Format("{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms", 
                        t.Hours, 
                        t.Minutes, 
                        t.Seconds, 
                        t.Milliseconds);

It's quite similar as this thread I've just found:

What is the best way to convert seconds into (Hour:Minutes:Seconds:Milliseconds) time?

Brittney answered 3/4, 2012 at 13:14 Comment(2)
This would produce 00h:00m:00s:003ms instead of 3ms for the input 3, so I don't think it's exactly what the OP wants ;)Endothermic
@Nuffin, he can always alter the code to suit his needs ;) I've just provided an example...Brittney
S
31

I know this is old, but I wanted to answer with a great nuget package.

Install-Package Humanizer

https://www.nuget.org/packages/Humanizer

https://github.com/MehdiK/Humanizer

Example from their readme.md

TimeSpan.FromMilliseconds(1299630020).Humanize(4) => "2 weeks, 1 day, 1 hour, 30 seconds"
Sainted answered 5/11, 2014 at 20:53 Comment(0)
G
18

What about this?

var ts = TimeSpan.FromMilliseconds(86300000 /*whatever */);
var parts = string
                .Format("{0:D2}d:{1:D2}h:{2:D2}m:{3:D2}s:{4:D3}ms",
                    ts.Days, ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds)
                .Split(':')
                .SkipWhile(s => Regex.Match(s, @"00\w").Success) // skip zero-valued components
                .ToArray();
var result = string.Join(" ", parts); // combine the result

Console.WriteLine(result);            // prints '23h 58m 20s 000ms'
Guck answered 3/4, 2012 at 13:34 Comment(1)
Nice code but it fails for 100 ms as input. The fix is to use @"^00\w" as the Regex.Inbreed
E
17

You could utilize the static TimeSpan.FromMilliseconds method as well as the resulting TimeSpan's Days, Hours, Minutes, Seconds and Milliseconds properties.

But I'm busy right now, so I'll leave the rest to you as an exercise.

Endothermic answered 3/4, 2012 at 13:15 Comment(0)
I
9

.NET 4 accepts format in TimeSpan.Tostring().

For other you can implement extension method like

    public static string Format(this TimeSpan obj)
    {
        StringBuilder sb = new StringBuilder();
        if (obj.Hours != 0)
        {
            sb.Append(obj.Hours);
            sb.Append(" "); 
            sb.Append("hours");
            sb.Append(" ");
        }
        if (obj.Minutes != 0 || sb.Length != 0)
        {
            sb.Append(obj.Minutes);
            sb.Append(" "); 
            sb.Append("minutes");
            sb.Append(" ");
        }
        if (obj.Seconds != 0 || sb.Length != 0)
        {
            sb.Append(obj.Seconds);
            sb.Append(" "); 
            sb.Append("seconds");
            sb.Append(" ");
        }
        if (obj.Milliseconds != 0 || sb.Length != 0)
        {
            sb.Append(obj.Milliseconds);
            sb.Append(" "); 
            sb.Append("Milliseconds");
            sb.Append(" ");
        }
        if (sb.Length == 0)
        {
            sb.Append(0);
            sb.Append(" "); 
            sb.Append("Milliseconds");
        }
        return sb.ToString();
    }

and call as

foreach (TimeSpan span in spans)
{
    MessageBox.Show(string.Format("{0}",  span.Format()));
}
Iatric answered 3/4, 2012 at 13:28 Comment(1)
I've used this approach and I just wanted to note that the highest interval (in this case obj.Hours) should be obj.TotalHours,ToString("0"). .TotalHours so it can show values above 24h, and ,ToString("0") to convert it to a single digit instead of a comma separated value.Selfgovernment
D
8
public static string ReadableTime(int milliseconds)
{
    var parts = new List<string>();
    Action<int, string> add = (val, unit) => { if (val > 0) parts.Add(val+unit); };
    var t = TimeSpan.FromMilliseconds(milliseconds);

    add(t.Days, "d");
    add(t.Hours, "h");
    add(t.Minutes, "m");
    add(t.Seconds, "s");
    add(t.Milliseconds, "ms");

    return string.Join(" ", parts);
}
Disinclined answered 23/3, 2016 at 22:46 Comment(2)
This is a nice approach for longer time spans (for which t.TotalDays also works).Pricking
Great approach, and for optional formatting. Action<int, string, int> add = (val, unit, zeroplaceholder) => {if (val > 0) parts.Add( string.Format( "{0:DZ}X".Replace("X", unit.ToString()) .Replace("Z",zeroplaceholder.ToString()) , val ); }; and call with add(t.Milliseconds, "ms", 4); to get 2m 37s 0456msLeah
U
6

Old question, new answer:

public static string GetReadableTimeByMs(long ms)
{
   TimeSpan t = TimeSpan.FromMilliseconds(ms);
   if (t.Hours > 0) return $"{t.Hours}h:{t.Minutes}m:{t.Seconds}s";
   else if (t.Minutes > 0) return $"{t.Minutes}m:{t.Seconds}s";
   else if (t.Seconds > 0) return $"{t.Seconds}s:{t.Milliseconds}ms";
   else return $"{t.Milliseconds}ms";
}
Underexpose answered 16/12, 2021 at 17:15 Comment(0)
Z
4

This probably has a slightly different output than requested, but the result is human readable - and it can be adapted to fit many other use cases.

private static List<double> _intervals = new List<double>
{
    1.0 / 1000 / 1000,
    1.0 / 1000,
    1,
    1000,
    60 * 1000,
    60 * 60 * 1000
};
private static List<string> _units = new List<string>
{
    "ns",
    "µs",
    "ms",
    "s",
    "min",
    "h"
};

public string FormatUnits(double milliseconds, string format = "#.#")
{
    var interval = _intervals.Last(i=>i<=milliseconds);
    var index = _intervals.IndexOf(interval);

    return string.Concat((milliseconds / interval).ToString(format) , " " , _units[index]);
}

Example calls...

Console.WriteLine(FormatUnits(1));
Console.WriteLine(FormatUnits(20));
Console.WriteLine(FormatUnits(300));
Console.WriteLine(FormatUnits(4000));
Console.WriteLine(FormatUnits(50000));
Console.WriteLine(FormatUnits(600000));
Console.WriteLine(FormatUnits(7000000));
Console.WriteLine(FormatUnits(80000000));

...and results:

1000 µs
20 ms
300 ms
4 s
50 s
10 min
1.9 h
22.2 h
Zoa answered 22/5, 2019 at 22:52 Comment(0)
M
2

For example to get 00:01:35.0090000 as 0 hours, 1 minutes, 35 seconds and 9 milliseconds you can use this:

Console.WriteLine("Time elapsed:" +TimeSpan.FromMilliseconds(numberOfMilliseconds).ToString());

Your output:

Time elapsed: 00:01:35.0090000
Mariehamn answered 22/2, 2016 at 9:30 Comment(0)
B
1

Maybe something like this?

DateTime.Now.ToString("%d 'd' %h 'h' %m 'm' %s 'seconds' %ms 'ms'")
Badoglio answered 3/4, 2012 at 13:13 Comment(1)
The question is about TimeSpans, not DateTimes. With a DateTime, you'll always end up with at least one day, which wouldn't really match the input of 3 milliseconds.Endothermic
E
1

You can use TimeSpan.FromMilliseconds function

var tspan = TimeSpan.FromMilliseconds(YOUR_MILLI_SECONDS);
int h = tspan.Hours;
int m = tspan.Minutes;
int s = tspan.Seconds;
Ephraimite answered 21/9, 2021 at 7:17 Comment(0)
L
0

Well i normally hate writing if statements but some times what you really have is a nail and need a hammer.

string time;
if (elapsedTime.TotalMinutes > 2)
    time = string.Format("{0:n2} minutes", elapsedTime.TotalMinutes);
else if (elapsedTime.TotalSeconds > 15)
    time = string.Format("{0:n2} seconds", elapsedTime.TotalSeconds);
else
    time = string.Format("{0:n0}ms", elapsedTime.TotalMilliseconds);
Lamplighter answered 28/9, 2015 at 15:56 Comment(0)
U
0

Here my code working for different input value (h, m, s, ms).

public static string FormatTime(this object inputTime, bool displayOriginalValue = true, string inputType = "ms")
    {
        string originalValue = $"{inputTime}{inputType}";
        try
        {
            //"ms", "s", "min", "h", "d"
            double ms = double.Parse(inputTime.ToString());
            switch (inputType.ToUpper())
            {
                case "S":
                    ms = ms * 1000;
                    break;
                case "MIN":
                case "M":
                    ms = ms * 1000 * 60;
                    break;
                case "H":
                    ms = ms * 1000 * 60 * 60;
                    break;
                case "D":
                    ms = ms * 1000 * 60 * 60 * 24;
                    break;
                default:
                    break;
            }


            TimeSpan ts = TimeSpan.FromMilliseconds(ms);
            var parts = string
                .Format("{0:D2}d:{1:D2}h:{2:D2}m:{3:D2}s:{4:D3}ms",
                    ts.Days, ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds)
                .Split(':')
                .SkipWhile(s => Regex.Match(s, @"00\w").Success) // skip zero-valued components
                .ToArray();
            var result = string.Join(" ", parts); // combine the result
            if (ms > 0)
                result = result.Replace(" 000ms", "");

            if (string.IsNullOrWhiteSpace(result))
                result = originalValue;

            return displayOriginalValue && result.ToUpper() != originalValue.ToUpper() ? $"{result} ({inputTime}{inputType})" : result;
        }
        catch (Exception ex)
        {
            return $"Original input: {originalValue}. Error: {ex.Message}";
        }
    }
Understanding answered 11/4 at 14:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.