jlp
jlp

Reputation: 10358

How to parse string with hours greater than 24 to TimeSpan?

How to parse string like 30:15 to TimeSpan in C#? 30:15 means 30 hours and 15 minutes.

string span = "30:15";
TimeSpan ts = TimeSpan.FromHours(
    Convert.ToDouble(span.Split(':')[0])).
  Add(TimeSpan.FromMinutes(
    Convert.ToDouble((span.Split(':')[1]))));

This does not seem too elegant.

Upvotes: 33

Views: 24420

Answers (6)

Erik Burigo
Erik Burigo

Reputation: 317

Similar to Luke's answer:

String span = "123:45";
Int32 colon = span.IndexOf(':');
TimeSpan timeSpan = new TimeSpan(Int32.Parse(span.Substring(0, colon)),
                                 Int32.Parse(span.Substring(colon + 1)), 0);

Obviously it assumes the original string is well-formed (composed of two parts separated by colon and parsable to an integer number).

Upvotes: 5

hiro.t
hiro.t

Reputation: 61

Based on Jan's Answer

.NET 5

    /// <summary>
    /// 1 number : hours    "0" to "0:0:0" ,    "-1" to "-01:00:00"
    /// 2 numbers : hours, minutes    "1:2" to "01:02:00"
    /// 3 numbers : hours, minutes, seconds    "1:2:3" to "01:02:03"
    /// 4 numbers : days, hours, minutes, seconds    "1:2:3:4" to "1.02:03:04"
    /// Any char can be used as separator.    "1,2 3aaaa4" to "1.02:03:04"
    /// </summary>
    /// <param name="timeSpanString"></param>
    /// <param name="ts"></param>
    /// <returns>true : conversion succeeded</returns>
    public static bool GetTimeSpan(string timeSpanString, ref TimeSpan ts)
    {

        bool isNegative = timeSpanString.StartsWith("-"); // "-1:2:3" is true
        var digitsString = Regex.Replace(timeSpanString, "[^0-9]", " "); // "-1:2:3" to " 1 2 3" 
        var s = digitsString.Split(' ', StringSplitOptions.RemoveEmptyEntries); // "1","2","3"

        int days = 0;
        int hours = 0;
        int minutes = 0;
        int seconds = 0;

        switch (s.Length)
        {
            case 1:
                hours = int.Parse(s[0]);
                break;

            case 2:
                hours = int.Parse(s[0]);
                minutes = int.Parse(s[1]);
                break;

            case 3:
                hours = int.Parse(s[0]);
                minutes = int.Parse(s[1]);
                seconds = int.Parse(s[2]);
                break;

            case 4:
                days = int.Parse(s[0]);
                hours = int.Parse(s[1]);
                minutes = int.Parse(s[2]);
                seconds = int.Parse(s[3]);
                break;

            default:
                return false; //no digits or length > 4
        }

        if (isNegative)
        {
            ts = new TimeSpan(-days, -hours, -minutes, -seconds);
        }
        else
        {
            ts = new TimeSpan(days, hours, minutes, seconds);
        }

        return true;
    }

TimeSpanHelper Convert TimeSpan to over 24 hours number. TimeSpan Converter, Rule for TextBox.

Upvotes: 1

Jan
Jan

Reputation: 333

Similar to Lukes answer, with a lot more code and room for improvement. BUT it deals with negatives Hours ("-30:15") aswell, so maybe it can help someone.

public static double GetTotalHours(String s)
    {
        bool isNegative = false;
        if (s.StartsWith("-"))
            isNegative = true;

        String[] splitted = s.Split(':');
        int hours = GetNumbersAsInt(splitted[0]);
        int minutes = GetNumbersAsInt(splitted[1]);

        if (isNegative)
        {
            hours = hours * (-1);
            minutes = minutes * (-1);
        }
        TimeSpan t = new TimeSpan(hours, minutes, 0);
        return t.TotalHours;
    }

public static int GetNumbersAsInt(String input)
        {
            String output = String.Empty;
            Char[] chars = input.ToCharArray(0, input.Length);
            for (int i = 0; i < chars.Length; i++)
            {
                if (Char.IsNumber(chars[i]) == true)
                    output = output + chars[i];
            }
            return int.Parse(output);
        }

usage

double result = GetTotalHours("30:15");
double result2 = GetTotalHours("-30:15");

Upvotes: 1

LukeH
LukeH

Reputation: 269388

If you're certain that the format will always be "HH:mm" then try something like this:

string span = "35:15";
TimeSpan ts = new TimeSpan(int.Parse(span.Split(':')[0]),    // hours
                           int.Parse(span.Split(':')[1]),    // minutes
                           0);                               // seconds

Upvotes: 38

Loudenvier
Loudenvier

Reputation: 8794

I'm using a simple method that I devised a long time ago and just posted today to my blog:

public static class TimeSpanExtensions
{
    static int[] weights = { 60 * 60 * 1000, 60 * 1000, 1000, 1 };

    public static TimeSpan ToTimeSpan(this string s)
    {
        string[] parts = s.Split('.', ':');
        long ms = 0;
        for (int i = 0; i < parts.Length && i < weights.Length; i++)
            ms += Convert.ToInt64(parts[i]) * weights[i];
        return TimeSpan.FromMilliseconds(ms);
    }
}

This can handle a lot more situations than the simpler solutions provided before, but has its own shortcomings. I discuss it further here.

Now, if you're in .NET 4 you can shorten the ToTimeSpan implementation to:

public static TimeSpan ToTimeSpan(this string s)
{
    return TimeSpan.FromMilliseconds(s.Split('.', ':')
        .Zip(weights, (d, w) => Convert.ToInt64(d) * w).Sum());
}

You can even make it an one-liner if you don't mind using horizontal screen state...

Upvotes: 4

Richard
Richard

Reputation: 109015

Normally one would use TimeSpan.ParseExact where a specific format is required. But the only hours formats that can be specified are as parts of days (see Custom TimeSpan Format Strings).

Therefore you will need to do the work yourself:

string input = "30:24";
var parts = input.Split(':');
var hours = Int32.Parse(parts[0]);
var minutes = Int32.Parse(parts[1]);
var result = new TimeSpan(hours, minutes, 0);

(But with some error checking.)

The three integer constructor of timespan allows hours >= 24 overflowing into the days count.

Upvotes: 0

Related Questions