HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcsharpMinor

convert timespan to readable text

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
converttextreadabletimespan

Problem

I'm trying to convert TimeSpan object to text that can be read like a sentence.
e.g.

TimeSpan(2, 1, 0, 0) --> "2 days and an hour"

TimeSpan(1, 2, 1, 0) --> "A day, 2 hours and a minute"


Some more samples for conversion are in the 'TestCases' object under 'TimeSpanPrettyFormatterTests' class.

Is there any better way to do it than the one i suggested here?

Thanks

```
using System;
using JetBrains.Annotations;
using NUnit.Framework;

namespace Client.Tests
{

[TestFixture]
public class TimeSpanPrettyFormatterTests
{
[UsedImplicitly]
static object[] TestCases =
{
new object[] { new TimeSpan(0, 0, 0, 0), string.Empty },

new object[] { new TimeSpan(1, 0, 0, 0), "A day" },
new object[] { new TimeSpan(2, 0, 0, 0), "2 days" },
new object[] { new TimeSpan(0, 1, 0, 0), "An hour" },
new object[] { new TimeSpan(1, 1, 0, 0), "A day and an hour" },
new object[] { new TimeSpan(2, 1, 0, 0), "2 days and an hour" },
new object[] { new TimeSpan(0, 2, 0, 0), "2 hours" },
new object[] { new TimeSpan(1, 2, 0, 0), "A day and 2 hours" },
new object[] { new TimeSpan(2, 2, 0, 0), "2 days and 2 hours" },

new object[] { new TimeSpan(0, 0, 1, 0), "A minute" },
new object[] { new TimeSpan(1, 0, 1, 0), "A day and a minute" },
new object[] { new TimeSpan(2, 0, 1, 0), "2 days and a minute" },
new object[] { new TimeSpan(0, 1, 1, 0), "An hour and a minute" },
new object[] { new TimeSpan(1, 1, 1, 0), "A day, an hour and a minute" },
new object[] { new TimeSpan(2, 1, 1, 0), "2 days, an hour and a minute" },
new object[] { new TimeSpan(0, 2, 1, 0), "2 hours and a minute" },
new object[] { new TimeSpan(1, 2, 1, 0), "A day, 2 hours and a minute" },
new object[] { new TimeSpan(2, 2, 1, 0), "2 days, 2 hours and a minute" },

new object[] { ne

Solution

ToPrettyFormat method can definitely be improved. Instead writing the conditional statement for all possible permutations of HasDays, HasHours and HasMinutes it's better to step back and define rules for resulting string:

  • string may consist of 3 parts (days, hours and minutes)



  • if there is 0 or one non-empty part - it is a final result



  • if there are 2 non-empty parts - there should be "and" between them



  • if there are 3 non-empty parts - first 2 should be separated by comma + "and" before last part. Note that we can actually generalize last two rules for N parts (months, weeks, etc) - instead of "3" we can say combine first N-1 parts with comma and add last one with "and"



As a result you can get a bit simplified code:

public static string ToPrettyFormat(this TimeSpan timeSpan)
{
    var dayParts = new[] { GetDays(timeSpan), GetHours(timeSpan), GetMinutes(timeSpan) }
        .Where(s => !string.IsNullOrEmpty(s))
        .ToArray();

    var numberOfParts = dayParts.Length;

    string result;
    if (numberOfParts < 2)
        result = dayParts.FirstOrDefault() ?? string.Empty;
    else
        result = string.Join(", ", dayParts, 0, numberOfParts - 1) + " and " + dayParts[numberOfParts - 1];

    return result.UppercaseFirst();
}

Code Snippets

public static string ToPrettyFormat(this TimeSpan timeSpan)
{
    var dayParts = new[] { GetDays(timeSpan), GetHours(timeSpan), GetMinutes(timeSpan) }
        .Where(s => !string.IsNullOrEmpty(s))
        .ToArray();

    var numberOfParts = dayParts.Length;

    string result;
    if (numberOfParts < 2)
        result = dayParts.FirstOrDefault() ?? string.Empty;
    else
        result = string.Join(", ", dayParts, 0, numberOfParts - 1) + " and " + dayParts[numberOfParts - 1];

    return result.UppercaseFirst();
}

Context

StackExchange Code Review Q#24995, answer score: 6

Revisions (0)

No revisions yet.