52

This is a bit wierd. Parsing a text field with a valid timespan fails if I try to be precise!

const string tmp = "17:23:24";
//works
var t1 = TimeSpan.Parse(tmp);
//fails
var t2 = TimeSpan.ParseExact(tmp, "hh:mm:ss", System.Globalization.CultureInfo.InvariantCulture);

The second parse fails with an exception "Input string was not in a correct format." from DateTime.

Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
Quango
  • 12,338
  • 6
  • 48
  • 83
  • 6
    Maybe you need `HH` instead of `hh` (24 hr format) – V4Vendetta Jul 30 '12 at 09:53
  • @V4Vendetta: you should post that as an answer; it's likely correct. – Dan Puzey Jul 30 '12 at 09:54
  • @JohnTotetWoo: Which date? There's no date in a `TimeSpan`. – Nuffin Jul 30 '12 at 09:56
  • 8
    Thanks for all the comments/answers - no HH is NOT a TimeSpan format string, that's not the answer. It's Jon's reply: TimeSpan.ParseExact does not handle separators, which is why it's failing. But Parse does - go figure! You have to escape the : values – Quango Jul 30 '12 at 10:00

6 Answers6

104

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)
Jon
  • 428,835
  • 81
  • 738
  • 806
  • 7
    Nice answer, Jon - I'd never realised that `ParseExact` ignores the 12/24 hour convention with the formatters. – Dan Puzey Jul 30 '12 at 10:01
  • 1
    So it is - learned something new today! Odd that Parse handles separators but ParseExact doesn't! – Quango Jul 30 '12 at 10:02
  • I was hoping this would solve my problem related to converting from `string` to `TimeSpan` in the Expression string of `DataTable.Select()`. However, no luck. Filed a bug [here](https://connect.microsoft.com/VisualStudio/feedback/details/806804/datatable-select-unable-to-convert-string-to-timespan-net-framework-4). – Conrad Dec 04 '13 at 14:09
  • 1
    you could also use `@"hh\:mm\:ss"`. – Peter Oct 14 '16 at 14:22
  • I have a question about this answer: Why does **TimeSpan.ParseExact(tmp, "HH:mm:ss.ffffff", CultureInfo.InvariantCulture)** work perfectly without any separators? – Flopdong Mar 20 '19 at 21:43
10

Try this:

var t2 = TimeSpan.ParseExact(tmp, "c", System.Globalization.CultureInfo.InvariantCulture);

Source: Standard TimeSpan Format Strings

M. Mennan Kara
  • 10,072
  • 2
  • 35
  • 39
  • Thanks for the reply - I hadn't noticed the 'c' format, which takes care of the separator issue: another new thing learned! – Quango Jul 30 '12 at 10:11
6

If you don't want to deal with the difference in format specifiers between TimeSpan.ParseExact and DateTime.ParseExact you can just parse your string as a DateTime and get the TimeOfDay component as a TimeSpan like this:

var t2 = DateTime.ParseExact(tmp, "hh:mm:ss", CultureInfo.InvariantCulture).TimeOfDay;
samgak
  • 23,944
  • 4
  • 60
  • 82
  • See [this answer](https://stackoverflow.com/a/2552455/696391) for how to go the other way: formatting a TimeSpan using DateTime format specifiers. – samgak Jun 28 '17 at 04:20
4

It seems that HH is not really for TimeSpan

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.

Hence the correct way would be as Jon mentioned to escape using "\" Read More

Your TimeSpan is "17:23:24" which is in the 24 hour format and it should be parsed using HH format and not hh which is for 12 hour formats.

TimeSpan.ParseExact(tmp, "HH:mm:ss",System.Globalization.CultureInfo.InvariantCulture);

Check out the formats

V4Vendetta
  • 37,194
  • 9
  • 78
  • 82
  • Not relevant: the specifier for hours that are not counted as part of days is `hh`. – Jon Jul 30 '12 at 09:58
  • 1
    You are linking to the `DateTime` format strings, which are different than the [`TimeSpan` format strings](http://msdn.microsoft.com/en-us/library/ee372287). – Jon Jul 30 '12 at 10:02
  • 2
    Nope, not correct. Timespan does not support HH, it only supports hh – Quango Jul 30 '12 at 10:02
  • @Jon Indeed that's the case, real eye opener for me, thank you – V4Vendetta Jul 30 '12 at 10:10
1

Use this It works use

TimeSpan.ParseExact(value, “h\\:mm”, CultureInfo.InvariantCulture);
Amit Verma
  • 40,709
  • 21
  • 93
  • 115
0

Try this:

     var t2 = TimeSpan.ParseExact(tmp, "HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
speti43
  • 2,886
  • 1
  • 20
  • 23