TimeSpan "pretty time" format in C#
Asked Answered
P

3

20

Typing in the title to this question brought me to this question. I'm looking for the same thing, but something perhaps less statically formatted if you get what I mean?

I'm writing a quick program that will be taking a TimeSpan duration of two DateTime objects and outputting them for printing to paper.

The format that would be preferred is: XX days, YY hours, ZZ minutes (seconds are irrelevant; as are days because I don't expect the timespan to incorporate more than a few hours).

Say the following code (as an example):

DateTime start = DateTime.Now;
DateTime end = DateTime.Now.AddMinutes(135);
TimeSpan duration = (end - start);

// output duration as XX hours, YY minutes

Thanks,
Zack

P.S. I also ran across "PrettyTime.NET", but it output things like "3 days ago", etc. Every other topic I found on google to format time duration strings like the above examples lead me to a Java-based solution. :\


UPDATE 2014-09-08:

To follow-up after 3 years, I've found an awesome library on NuGet and Github called "Humanizer" which would solve this issue I was having. I haven't used it that much, but I did try it and it works beautifully. It's quite large of a library though (it emits a whole ton of folders for different cultures to your project's build path (I'm sure there's a way to to customize it)).

Pico answered 25/3, 2011 at 21:35 Comment(4)
Post the link to the Java versions...should be doable in C# :)Brotherson
@MattC: That'll take me a few minutes. I closed them already. :/Pico
@MattC: eh. Here's one that's similar, but different format. Same generally anyway. #3471897Pico
Zack: FYI - Instead of making an end date time just for making a timespan, you can just use: TimeSpan.FromMinutes(135) directly: msdn.microsoft.com/en-us/library/…Odo
D
39

And if you care about pluralization:

public static string ToPrettyFormat(this TimeSpan span) {

    if (span == TimeSpan.Zero) return "0 minutes";

    var sb = new StringBuilder();
    if (span.Days > 0)
        sb.AppendFormat("{0} day{1} ", span.Days, span.Days > 1 ? "s" : String.Empty);
    if (span.Hours > 0)
        sb.AppendFormat("{0} hour{1} ", span.Hours, span.Hours > 1 ? "s" : String.Empty);
    if (span.Minutes > 0)
        sb.AppendFormat("{0} minute{1} ", span.Minutes, span.Minutes > 1 ? "s" : String.Empty);
    return sb.ToString();

}
Driskell answered 25/3, 2011 at 22:23 Comment(3)
Ahhh. That looks nice. +1 Thanks to everyone who posted an answer here. ;)Pico
This will chop off the trailing space: sb.Remove(sb.Length - 1, 1);Afresh
For anyone considering this, there is a bug in the above code. If the duration is greater than zero seconds but less than 1 minute, it passes the TimeSpan.Zero check but then returns an empty string. You need to evaluate span.Seconds before returning sb.Nevlin
O
10

You can just output this directly:

 string result = string.Format("{0} days, {1} hours, {2} minutes", duration.Days, duration.Hours, duration.Minutes);

If you are going to be handling "short" times, and you want this to be cleaner, you could do something like:

public string PrettyFormatTimeSpan(TimeSpan span)
{
    if (span.Days > 0)
         return string.Format("{0} days, {1} hours, {2} minutes", span.Days, span.Hours, span.Minutes);
    if (span.Hours > 0)
         return string.Format("{0} hours, {1} minutes", span.Hours, span.Minutes);

    return  string.Format("{0} minutes", span.Minutes);
}
Odo answered 25/3, 2011 at 21:38 Comment(0)
T
5

With C# 7:

string FormatTimeSpan(TimeSpan timeSpan)
{
    string FormatPart(int quantity, string name) => quantity > 0 ? $"{quantity} {name}{(quantity > 1 ? "s" : "")}" : null;
    return string.Join(", ", new[] { FormatPart(timeSpan.Days, "day"), FormatPart(timeSpan.Hours, "hour"), FormatPart(timeSpan.Minutes, "minute") }.Where(x => x != null));
}
Tithable answered 20/3, 2018 at 15:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.