Custom string formats of TimeSpan
Asked Answered
D

4

5

I want to format TimeSpans in C# in this way:

xxx day(s) yyy hours(s) zzz minute(s)

Conditions:

  1. Extra seconds should be truncated

  2. day(s) is the largest unit I want. I want 34 days to appear as 34 days rather than 1 month 4 days etc.

  3. If timespan is less than one day, I dont want the day part to show up. Likewise if span is less than 1 hour, I want only the mins part to show up.

Is there any way I can do this using built-in format strings or there is no way other than writing my own function?

Edit: Currently using my own function for this. It takes TimeSpan in minutes as input (TimeSpan.TotalMinutes) :

private static string GetTimeStringFromMinutes(double p)
        {
            var minutes = (int) p;
            int hours = minutes / 60;
            minutes = minutes % 60;
            int days = hours/24;
            hours = hours%24;
            string dayPart = days + " day(s) ";
            string hoursPart = hours + " hour(s) ";
            string minutesPart = minutes + " minute(s)";
            if (days != 0)
                return (dayPart + hoursPart + minutesPart);
            if (hours != 0)
                return (hoursPart + minutesPart);
            return (minutesPart);
        }
Dour answered 20/8, 2010 at 9:33 Comment(2)
I was just curious... What happens if the number of days is greater than zero but the hours is zero? Do you display, for instance, XX days, 0 hours, YY mins or do you display XX days, YY mins? Your code seems to do the former.Delfinadelfine
yes in that case I want the 0 hours to be displayed..Dour
S
7

TimeSpan has no formatting options at all before .NET 4.0, you'd have to convert it to DateTime through the Ticks property. Nothing remotely close in DateTime.String(format) formatting options though, you'll have to write it yourself.

In .NET 4.0, TimeSpan acquired a ToString(format) override. Custom formatting strings are described here. Your 3rd requirement is going to need code.

Stamin answered 20/8, 2010 at 9:59 Comment(1)
+1 for mentioning that there's no TimeSpan formatting before .NET 4.0. I didn't know that, and would have wasted time trying to figure out what format string I need, when I couldn't use it anyways on my .NET 2.0 project.Leuko
H
5

In .NET 3.5 and earlier you need to write your own function.

In .NET 4 support was added for formatting TimeSpan, see TimeSpan.ToString(string) for details.

Headroom answered 20/8, 2010 at 9:50 Comment(0)
D
3

There isn't any built-in way of doing your requirement at least in .NET 3.5. Here's a class that extends the TimeSpan to provide your desired functionality.

public static class TimeSpanEx
{
    public static string FormattedString(this TimeSpan ts)
    {
        int days = (int)ts.TotalDays;
        int hrs = (int)ts.Hours;
        int mins = (int)ts.Minutes;
        StringBuilder sb = new StringBuilder();

        if (days > 0)
        {
            sb.Append(days.ToString() + (days == 1 ? " day, " : " days, "));
        }

        if (hrs > 0 || days > 0)
        {
            sb.Append(hrs.ToString() + (hrs == 1 ? " hour, " : " hours, "));
        }

        sb.Append(mins.ToString() + (mins == 1 ? " min" : " mins"));

        return sb.ToString();
    }
}
Delfinadelfine answered 20/8, 2010 at 10:32 Comment(0)
E
2

Unfortunately there is nothing in .Net directly available. For myself i had resolved the problem this way:

public static class TimeSpanExtensions
{
    public static string ToDetailedString(this TimeSpan timeSpan)
    {
        if (timeSpan == null)
            throw new ArgumentNullException("timeSpan");

        var sb = new StringBuilder(30);

        var current = timeSpan.ToDaysString();

        if (!String.IsNullOrEmpty(current))
            sb.Append(current);

        current = timeSpan.ToHoursString();

        if (!String.IsNullOrEmpty(current))
        {
            if (sb.Length > 0)
                sb.Append(" ");

            sb.Append(current);
        }

        current = timeSpan.ToMinutesString();

        if (!String.IsNullOrEmpty(current))
        {
            if (sb.Length > 0)
                sb.Append(" ");

            sb.Append(current);
        }

        return sb.ToString();
    }

    public static string ToDaysString(this TimeSpan timeSpan)
    {
        if (timeSpan == null)
            throw new ArgumentNullException("timeSpan");

        int days = (int)timeSpan.TotalDays;

        switch (days)
        {
            case 0:
                return String.Empty;
            case 1:
                return "1 day";
            default:
                return days + " days";
        }
    }

    public static string ToHoursString(this TimeSpan timeSpan)
    {
        if (timeSpan == null)
            throw new ArgumentNullException("timeSpan");

        switch (timeSpan.Hours)
        {
            case 0:
                return String.Empty;
            case 1:
                return "1 hour";
            default:
                return timeSpan.Hours + " hours";
        }
    }

    public static string ToMinutesString(this TimeSpan timeSpan)
    {
        if (timeSpan == null)
            throw new ArgumentNullException("timeSpan");

        switch (timeSpan.Minutes)
        {
            case 0:
                return String.Empty;
            case 1:
                return "1 minute";
            default:
                return timeSpan.Minutes + " minutes";
        }
    }
}

Maybe it's not the most elegant solution and i think there can be done some improvements especially in the ToDetailedString() function, but it works absolutely fine.

Eugenol answered 20/8, 2010 at 10:11 Comment(1)
I'm also using my own method right now, which takes Timespan in minutes as input... edited to include that in my questionDour

© 2022 - 2024 — McMap. All rights reserved.