Why does TimeSpan.ParseExact not work
From the documentation:
Any other unescaped character in a format string, including a
white-space character, is interpreted as a custom format specifier. In
most cases, the presence of any other unescaped character results in a
FormatException.There are two ways to include a literal character in a format string:
Enclose it in single quotation marks (the literal string delimiter).
Precede it with a backslash ("\"), which is interpreted as an escape character. This means that, in C#, the format string must
either be @-quoted, or the literal character must be preceded by an
additional backslash.
The .NET Framework does not define a grammar for separators in time
intervals. This means that the separators between days and hours,
hours and minutes, minutes and seconds, and seconds and fractions of a
second must all be treated as character literals in a format string.
So, the solution is to specify the format string as
TimeSpan.ParseExact(tmp, "hh\\:mm\\:ss", CultureInfo.InvariantCulture)
TimeSpan.ParseExact does not recognize input format
I'm don't know why that is so or where it is documented, but three digit timespans seem not to be supported in TimeSpan.ParseExact
. So you could workaround it by padding it with leading zeros:
string ts = "800";
var x = TimeSpan.ParseExact(ts.PadLeft(4, '0'), "hhmm", CultureInfo.InvariantCulture);
I guess that the reason why TimeSpan
cannot parse this is related to the reason why DateTime.ParseExact
cannot parse 7 digits with one or two digit month and without a delimiter.
Any workaround to TimeSpan.ParseExact with more than 59 seconds?
Ok guys, I ended up with this custom method to do the work.
It's not a method to execute many times in a row because of the huge performance issues it will have, but to parse the introduced data from the front end it's more than acceptable:
/// <summary>
/// Given a time and a format it creates a <see cref="TimeSpan"/> ignoring the format digit limitations.
/// The format is not validated, so better ensure a correct one is provided ;)
/// </summary>
/// <param name="time"></param>
/// <param name="format"></param>
/// <param name="timeSpan"></param>
/// <returns></returns>
public static bool TryParseTime(string time, string format, out TimeSpan timeSpan)
{
// Regex to match the components of the time format (ss:fff matches ss and fff)
var formatRegex = new Regex(@"(?<=(?<!\\)(?:\\{2})*)(%?([fFsmhd])(\2*))");
var matches = formatRegex.Matches(format);
if (matches.Count > 0)
{
// We build a big regex to extract the values from time
string formatExtractionRegex = string.Empty;
int pivot = 0;
foreach (Match match in matches)
{
if (match.Success)
{
char c = match.Value.ToLower()[0];
formatExtractionRegex += $@"{format.Substring(pivot, match.Index - pivot)}(?<{c}>\d+)";
pivot = match.Index + match.Length;
}
}
var timeParts = new Regex(formatExtractionRegex).Match(time);
int d, h, m, s, f;
int.TryParse(timeParts.Groups["d"].ToString(), out d);
int.TryParse(timeParts.Groups["h"].ToString(), out h);
int.TryParse(timeParts.Groups["m"].ToString(), out m);
int.TryParse(timeParts.Groups["s"].ToString(), out s);
int.TryParse(timeParts.Groups["f"].ToString(), out f);
timeSpan = new TimeSpan(d, h, m, s, f);
return true;
}
timeSpan = default;
return false;
}
The method extracts the data from the time by building a big regex that replaces the digit type for the regex expression \d+
, so we select entire digit groups when they are longer than what the format specifies.
If we provide a time 100:100:5000
and a format mm\:ss\:fff
, the generated regex will be (?<m>\\d+)\\:(?<s>\\d+)\\:(?<f>\\d+)
.
Finally we parse the matched groups and we parse them to be given to the TimeSpan Constructor.
TimeSpan.TryParseExact not working
The problem is simply in the format string for the TimeSpan, you have specified "HH:mm:ss"
. The specifier HH
(upper case) is not valid for timespan. You should use hh
. Format strings are indeed case sensitive.
The colon character (:
) also needs to be escaped, so use "hh\\:mm\\:ss"
, @"hh\:mm\:ss"
or "hh':'mm':'ss"
. All three forms will have the same effect.
You can review a list of valid custom format strings for TimeSpan here. and the standard format strings for TimeSpan are here.
While HH
is valid for DateTime and DateTimeOffset where it represents the 24 hour clock and lower case hh represents a 12 hour clock, For TimeSpan - the hours component is always based on 24 hours. You would think that the HH
format would be the one chosen, for uniformity, but nope - it's hh
.
TimeSpan.ParseExact giving error
I believe you need to parse the colons, basically. I would also suggest using the invariant culture instead of the current thread culture:
var ts = TimeSpan.ParseExact("0:0:4:410", @"h\:m\:s\:fff",
CultureInfo.InvariantCulture);
From the documentation:
The custom TimeSpan format specifiers do not include placeholder separator symbols, such as the symbols that separate days from hours, hours from minutes, or seconds from fractional seconds. Instead, these symbols must be included in the custom format string as string literals. For example, "dd.hh:mm" defines a period (.) as the separator between days and hours, and a colon (:) as the separator between hours and minutes.
I would also suggest using a format of h:mm:ss.fff
instead - I believe this would be clearer than your current format. Note that you can use the format directly instead of your currently formatting approach:
const string TimeSpanFormat = @"h\:mm\:ss\.fff";
string text = ts.ToString(TimeSpanFormat, CultureInfo.InvariantCulture);
...
TimeSpan parsed = TimeSpan.ParseExact(text, TimeSpanFormat,
CultureInfo.InvariantCulture);
Can't Parse TimeSpan with commas for separation
You only need to escape out the ,
parts of the string (as the documentation states), which is achieved by surrounding them with single quotes ('
):
var tmp = TimeSpan.TryParseExact("1, 2, 3, 4, 5", "d', 'h', 'm', 's', 'f", null, out ts);
Example fiddle: https://dotnetfiddle.net/M7GOWR
TimeSpan.ParseExact returns System.FormatException
According to ParseExact definition, the syntax is:
input format
, etc
The System.FormatException
exception message is about the input
parameter, the first parameter from the list that is in the function's prototype. I would double check the value of the input
parameter from your code.
+/- sign in TimeSpan's ParseExact()?
You could check if it starts with -
, then apply the appropriate format string:
string[] timespans = { "-0530", "+0100" };
foreach (string timespan in timespans)
{
bool isNegative = timespan.StartsWith("-");
string format = isNegative ? "\\-hhmm" : "\\+hhmm";
TimeSpanStyles tss = isNegative ? TimeSpanStyles.AssumeNegative : TimeSpanStyles.None;
TimeSpan ts;
if (TimeSpan.TryParseExact(timespan, format, null, tss, out ts))
{
Console.WriteLine("{0} successfully parsed to: {1}", timespan, ts);
}
else
{
Console.WriteLine("Could not be parsed: {0}", timespan);
}
}
Note that i use TimeSpanStyles.AssumeNegative
in TryParseExact
, otherwise the timespans would be always positive even if they are prepended with a minus.
TimeSpan.ParseExact() returns false for apparently valid format
Use @"hh\:mm\:ss"
for your format.
TimeSpan.ParseExact with ms
First, you are using .
as a separator, but your string uses :
.
Second, that is a quite weird representation of seconds (which is a 60 based number) and milliseconds (which is a 100-based one), so you more likely have:
string time = "12:25:11.97" // remember the quotes
Which should be parsed with:
TimeSpan t = TimeSpan.ParseExact(time, "hh':'mm':'ss.ff", CultureInfo.InvariantCulture);
If you indeed have 12:25:1197
then you can use hh':'mm':'ssff
, but that's indeed weird
Btw, if that's two digits for what you call ms
, then that's hundreths of seconds
, not milliseconds
(which woulf be three digits)
Related Topics
C# How to Loop While Mouse Button Is Held Down
What Does System.Double[*] Mean
.Net - Convert Generic Collection to Datatable
How to Align Text in Columns Using Console.Writeline
Should I Use Appdomain.Currentdomain.Basedirectory or System.Environment.Currentdirectory
How to Generate a Hashcode from a Byte Array in C#
Minimizing All Open Windows in C#
Convert Datetime to Date Format Dd/Mm/Yyyy
How to "Zip" or "Rotate" a Variable Number of Lists
Fake-Scrolling Containers with Very Many Controls
3D Relative Angle Sum Calculation
Routing with Multiple Get Methods in ASP.NET Web API
How Does Entity Framework Work with Recursive Hierarchies? Include() Seems Not to Work with It
Ascending/Descending in Linq - Can One Change the Order via Parameter