< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 731
Coverable lines: 731
Total lines: 1704
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 653
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
.ctor(...)100%110%
.ctor(...)100%110%
.ctor(...)100%110%
NormalizeAndValidateFraction()0%12120%
.ctor(...)100%110%
.ctor(...)100%110%
GetNextToken()0%22220%
BackOne()0%220%
NextChar()0%220%
FullAppCompatMatch(...)0%12120%
PartialAppCompatMatch(...)0%10100%
FullMatch(...)0%14140%
FullDMatch(...)0%660%
FullHMMatch(...)0%880%
FullDHMMatch(...)0%10100%
FullHMSMatch(...)0%10100%
FullDHMSMatch(...)0%12120%
FullHMSFMatch(...)0%12120%
Init(...)100%110%
ProcessToken(...)0%12120%
AddSep(...)0%10100%
AddNum(...)0%990%
.ctor(...)100%110%
SetNoFormatSpecifierFailure()0%220%
SetBadQuoteFailure(...)0%220%
SetInvalidStringFailure()0%220%
SetArgumentNullFailure(...)0%220%
SetOverflowFailure()0%220%
SetBadTimeSpanFailure()0%220%
SetBadFormatSpecifierFailure(...)0%220%
Pow10UpToMaxFractionDigits(...)100%110%
TryTimeToTicks(...)0%18180%
Parse(...)100%110%
TryParse(...)0%220%
ParseExact(...)100%110%
TryParseExact(...)0%220%
ParseExactMultiple(...)100%110%
TryParseExactMultiple(...)0%220%
TryParseTimeSpan(...)0%880%
ProcessTerminalState(...)0%10100%
ProcessTerminal_DHMSF(...)0%28280%
ProcessTerminal_HMS_F_D(...)0%86860%
ProcessTerminal_HM_S_D(...)0%86860%
ProcessTerminal_HM(...)0%30300%
ProcessTerminal_D(...)0%30300%
TryParseExactTimeSpan(...)0%16160%
TryParseByFormat(...)0%72720%
ParseExactDigits(...)0%220%
ParseExactDigits(...)0%660%
ParseExactLiteral(...)0%440%
TryParseTimeSpanConstant(...)100%110%
NextChar()0%440%
NextNonDigit()0%220%
TryParse(...)0%20200%
ParseInt(...)0%10100%
ParseTime(...)0%18180%
SkipBlanks()0%440%
TryParseExactMultipleTimeSpan(...)0%12120%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanParse.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4////////////////////////////////////////////////////////////////////////////
 5//
 6//  Purpose:  Used by TimeSpan to parse a time interval string.
 7//
 8//  Standard Format:
 9//  -=-=-=-=-=-=-=-
 10//  "c":  Constant format.  [-][d'.']hh':'mm':'ss['.'fffffff]
 11//  Not culture sensitive.  Default format (and null/empty format string) map to this format.
 12//
 13//  "g":  General format, short:  [-][d':']h':'mm':'ss'.'FFFFFFF
 14//  Only print what's needed.  Localized (if you want Invariant, pass in Invariant).
 15//  The fractional seconds separator is localized, equal to the culture's DecimalSeparator.
 16//
 17//  "G":  General format, long:  [-]d':'hh':'mm':'ss'.'fffffff
 18//  Always print days and 7 fractional digits.  Localized (if you want Invariant, pass in Invariant).
 19//  The fractional seconds separator is localized, equal to the culture's DecimalSeparator.
 20//
 21//  * "TryParseTimeSpan" is the main method for Parse/TryParse
 22//
 23//  - TimeSpanTokenizer.GetNextToken() is used to split the input string into number and literal tokens.
 24//  - TimeSpanRawInfo.ProcessToken() adds the next token into the parsing intermediary state structure
 25//  - ProcessTerminalState() uses the fully initialized TimeSpanRawInfo to find a legal parse match.
 26//    The terminal states are attempted as follows:
 27//    foreach (+InvariantPattern, -InvariantPattern, +LocalizedPattern, -LocalizedPattern) try
 28//       1 number  => d
 29//       2 numbers => h:m
 30//       3 numbers => h:m:s     | d.h:m   | h:m:.f
 31//       4 numbers => h:m:s.f   | d.h:m:s | d.h:m:.f
 32//       5 numbers => d.h:m:s.f
 33//
 34// Custom Format:
 35// -=-=-=-=-=-=-=
 36//
 37// * "TryParseExactTimeSpan" is the main method for ParseExact/TryParseExact methods
 38// * "TryParseExactMultipleTimeSpan" is the main method for ParseExact/TryparseExact
 39//    methods that take a string[] of formats
 40//
 41// - For single-letter formats "TryParseTimeSpan" is called (see above)
 42// - For multi-letter formats "TryParseByFormat" is called
 43// - TryParseByFormat uses helper methods (ParseExactLiteral, ParseExactDigits, etc)
 44//   which drive the underlying TimeSpanTokenizer.  However, unlike standard formatting which
 45//   operates on whole-tokens, ParseExact operates at the character-level.  As such,
 46//   TimeSpanTokenizer.NextChar and TimeSpanTokenizer.BackOne() are called directly.
 47//
 48////////////////////////////////////////////////////////////////////////////
 49
 50using System.Buffers.Text;
 51using System.Diagnostics;
 52using System.Text;
 53
 54namespace System.Globalization
 55{
 56    internal static class TimeSpanParse
 57    {
 58        private const int MaxFractionDigits = 7;
 59        private const int MaxDays = 10675199;
 60        private const int MaxHours = 23;
 61        private const int MaxMinutes = 59;
 62        private const int MaxSeconds = 59;
 63        private const int MaxFraction = 9999999;
 64
 65        [Flags]
 66        private enum TimeSpanStandardStyles : byte
 67        {
 68            // Standard Format Styles
 69            None = 0x00000000,
 70            Invariant = 0x00000001, // Allow Invariant Culture
 71            Localized = 0x00000002, // Allow Localized Culture
 72            RequireFull = 0x00000004, // Require the input to be in DHMSF format
 73            Any = Invariant | Localized,
 74        }
 75
 76        // TimeSpan Token Types
 77        private enum TTT : byte
 78        {
 79            None = 0,         // None of the TimeSpanToken fields are set
 80            End = 1,          // '\0'
 81            Num = 2,          // Number
 82            Sep = 3,          // literal
 83            NumOverflow = 4,  // Number that overflowed
 84        }
 85
 86        private ref struct TimeSpanToken
 87        {
 88            internal TTT _ttt;
 89            internal int _num;                // Store the number that we are parsing (if any)
 90            internal int _zeroes;             // Store the number of leading zeroes (if any)
 91            internal ReadOnlySpan<char> _sep; // Store the literal that we are parsing (if any)
 92
 093            public TimeSpanToken(TTT type) : this(type, 0, 0, default) { }
 94
 095            public TimeSpanToken(int number) : this(TTT.Num, number, 0, default) { }
 96
 097            public TimeSpanToken(int number, int leadingZeroes) : this(TTT.Num, number, leadingZeroes, default) { }
 98
 99            public TimeSpanToken(TTT type, int number, int leadingZeroes, ReadOnlySpan<char> separator)
 100            {
 0101                _ttt = type;
 0102                _num = number;
 0103                _zeroes = leadingZeroes;
 0104                _sep = separator;
 0105            }
 106
 107            public bool NormalizeAndValidateFraction()
 108            {
 0109                Debug.Assert(_ttt == TTT.Num);
 0110                Debug.Assert(_num > -1);
 111
 0112                if (_num == 0)
 0113                    return true;
 114
 0115                if (_zeroes == 0 && _num > MaxFraction)
 0116                    return false;
 117
 0118                int totalDigitsCount = FormattingHelpers.CountDigits((uint)_num) + _zeroes;
 119
 0120                if (totalDigitsCount == MaxFractionDigits)
 121                {
 122                    // Already normalized. no more action needed
 123                    // .9999999  normalize to 9,999,999 ticks
 124                    // .0000001  normalize to 1 ticks
 0125                    return true;
 126                }
 127
 0128                if (totalDigitsCount < MaxFractionDigits)
 129                {
 130                    // normalize the fraction to the 7-digits
 131                    // .999999  normalize to 9,999,990 ticks
 132                    // .99999   normalize to 9,999,900 ticks
 133                    // .000001  normalize to 10 ticks
 134                    // .1       normalize to 1,000,000 ticks
 135
 0136                    _num *= Pow10UpToMaxFractionDigits(MaxFractionDigits - totalDigitsCount);
 0137                    return true;
 138                }
 139
 140                // totalDigitsCount is greater then MaxFractionDigits, we'll need to do the rounding to 7-digits length
 141                // .00000001    normalized to 0 ticks
 142                // .00000005    normalized to 1 ticks
 143                // .09999999    normalize to 1,000,000 ticks
 144                // .099999999   normalize to 1,000,000 ticks
 145
 0146                Debug.Assert(_zeroes > 0); // Already validated that in the condition _zeroes == 0 && _num > MaxFraction
 147
 0148                if (_zeroes > MaxFractionDigits)
 149                {
 150                    // If there are 8 leading zeroes, it rounds to zero
 0151                    _num = 0;
 0152                    return true;
 153                }
 154
 0155                Debug.Assert(totalDigitsCount - MaxFractionDigits <= MaxFractionDigits);
 0156                uint power = (uint)Pow10UpToMaxFractionDigits(totalDigitsCount - MaxFractionDigits);
 157                // Unsigned integer division, rounding away from zero
 0158                _num = (int)(((uint)_num + power / 2) / power);
 0159                Debug.Assert(_num < MaxFraction);
 160
 0161                return true;
 162            }
 163        }
 164
 165        private ref struct TimeSpanTokenizer
 166        {
 167            private readonly ReadOnlySpan<char> _value;
 168            private int _pos;
 169
 0170            internal TimeSpanTokenizer(ReadOnlySpan<char> input) : this(input, 0) { }
 171
 172            internal TimeSpanTokenizer(ReadOnlySpan<char> input, int startPosition)
 173            {
 0174                _value = input;
 0175                _pos = startPosition;
 0176            }
 177
 178            /// <summary>Returns the next token in the input string</summary>
 179            /// <remarks>Used by the parsing routines that operate on standard-formats.</remarks>
 180            internal TimeSpanToken GetNextToken()
 181            {
 182                // Get the position of the next character to be processed.  If there is no
 183                // next character, we're at the end.
 0184                int startPos = _pos;
 0185                int pos = startPos;
 0186                ReadOnlySpan<char> value = _value;
 0187                Debug.Assert(pos > -1);
 0188                if ((uint)pos >= (uint)value.Length)
 189                {
 0190                    return new TimeSpanToken(TTT.End);
 191                }
 192
 193                // Now retrieve that character. If it's a digit, we're processing a number.
 0194                int num = value[pos] - '0';
 0195                if ((uint)num <= 9)
 196                {
 0197                    int zeroes = 0;
 0198                    if (num == 0)
 199                    {
 200                        // Read all leading zeroes.
 0201                        zeroes = 1;
 202                        while (true)
 203                        {
 204                            int digit;
 0205                            if ((uint)++pos >= (uint)value.Length || (uint)(digit = value[pos] - '0') > 9)
 206                            {
 0207                                _pos = pos;
 0208                                return new TimeSpanToken(TTT.Num, 0, zeroes, default);
 209                            }
 210
 0211                            if (digit == 0)
 212                            {
 0213                                zeroes++;
 0214                                continue;
 215                            }
 216
 0217                            num = digit;
 218                            break;
 219                        }
 220
 0221                        _pos = pos;
 222                    }
 223
 224                    // Continue to read as long as we're reading digits.
 0225                    while ((uint)++pos < (uint)value.Length)
 226                    {
 0227                        int digit = value[pos] - '0';
 0228                        if ((uint)digit > 9)
 229                        {
 230                            break;
 231                        }
 232
 0233                        num = num * 10 + digit;
 0234                        if ((num & 0xF0000000) != 0) // Max limit we can support 268435455 which is FFFFFFF
 235                        {
 0236                            _pos = pos;
 0237                            return new TimeSpanToken(TTT.NumOverflow);
 238                        }
 239                    }
 240
 0241                    _pos = pos;
 0242                    return new TimeSpanToken(TTT.Num, num, zeroes, default);
 243                }
 244
 245                // Otherwise, we're processing a separator, and we've already processed the first
 246                // character of it.  Continue processing characters as long as they're not digits.
 0247                int length = 1;
 0248                while ((uint)++pos < (uint)value.Length && !char.IsAsciiDigit(value[pos]))
 249                {
 0250                    length++;
 251                }
 0252                _pos = pos;
 253
 254                // Return the separator.
 0255                return new TimeSpanToken(TTT.Sep, 0, 0, _value.Slice(startPos, length));
 256            }
 257
 0258            internal bool EOL => _pos >= (_value.Length - 1);
 259
 260            internal void BackOne()
 261            {
 0262                if (_pos > 0) --_pos;
 0263            }
 264
 265            internal char NextChar()
 266            {
 0267                int pos = ++_pos;
 0268                return (uint)pos < (uint)_value.Length ?
 0269                    _value[pos] :
 0270                    (char)0;
 271            }
 272        }
 273
 274        /// <summary>Stores intermediary parsing state for the standard formats.</summary>
 275        private ref struct TimeSpanRawInfo
 276        {
 277            internal TimeSpanFormat.FormatLiterals PositiveLocalized
 278            {
 279                get
 280                {
 0281                    if (!_posLocInit)
 282                    {
 0283                        _posLoc = default;
 0284                        _posLoc.Init(_fullPosPattern, false);
 0285                        _posLocInit = true;
 286                    }
 0287                    return _posLoc;
 288                }
 289            }
 290
 291            internal TimeSpanFormat.FormatLiterals NegativeLocalized
 292            {
 293                get
 294                {
 0295                    if (!_negLocInit)
 296                    {
 0297                        _negLoc = default;
 0298                        _negLoc.Init(_fullNegPattern, false);
 0299                        _negLocInit = true;
 300                    }
 0301                    return _negLoc;
 302                }
 303            }
 304
 305            internal bool FullAppCompatMatch(TimeSpanFormat.FormatLiterals pattern) =>
 0306                _sepCount == 5
 0307                && _numCount == 4
 0308                && _literals0.EqualsOrdinal(pattern.Start)
 0309                && _literals1.EqualsOrdinal(pattern.DayHourSep)
 0310                && _literals2.EqualsOrdinal(pattern.HourMinuteSep)
 0311                && _literals3.EqualsOrdinal(pattern.AppCompatLiteral)
 0312                && _literals4.EqualsOrdinal(pattern.End);
 313
 314            internal bool PartialAppCompatMatch(TimeSpanFormat.FormatLiterals pattern) =>
 0315                _sepCount == 4
 0316                && _numCount == 3
 0317                && _literals0.EqualsOrdinal(pattern.Start)
 0318                && _literals1.EqualsOrdinal(pattern.HourMinuteSep)
 0319                && _literals2.EqualsOrdinal(pattern.AppCompatLiteral)
 0320                && _literals3.EqualsOrdinal(pattern.End);
 321
 322            /// <summary>DHMSF (all values matched)</summary>
 323            internal bool FullMatch(TimeSpanFormat.FormatLiterals pattern) =>
 0324                _sepCount == MaxLiteralTokens
 0325                && _numCount == MaxNumericTokens
 0326                && _literals0.EqualsOrdinal(pattern.Start)
 0327                && _literals1.EqualsOrdinal(pattern.DayHourSep)
 0328                && _literals2.EqualsOrdinal(pattern.HourMinuteSep)
 0329                && _literals3.EqualsOrdinal(pattern.MinuteSecondSep)
 0330                && _literals4.EqualsOrdinal(pattern.SecondFractionSep)
 0331                && _literals5.EqualsOrdinal(pattern.End);
 332
 333            /// <summary>D (no hours, minutes, seconds, or fractions)</summary>
 334            internal bool FullDMatch(TimeSpanFormat.FormatLiterals pattern) =>
 0335                _sepCount == 2
 0336                && _numCount == 1
 0337                && _literals0.EqualsOrdinal(pattern.Start)
 0338                && _literals1.EqualsOrdinal(pattern.End);
 339
 340            /// <summary>HM (no days, seconds, or fractions)</summary>
 341            internal bool FullHMMatch(TimeSpanFormat.FormatLiterals pattern) =>
 0342                _sepCount == 3
 0343                && _numCount == 2
 0344                && _literals0.EqualsOrdinal(pattern.Start)
 0345                && _literals1.EqualsOrdinal(pattern.HourMinuteSep)
 0346                && _literals2.EqualsOrdinal(pattern.End);
 347
 348            /// <summary>DHM (no seconds or fraction)</summary>
 349            internal bool FullDHMMatch(TimeSpanFormat.FormatLiterals pattern) =>
 0350                _sepCount == 4
 0351                && _numCount == 3
 0352                && _literals0.EqualsOrdinal(pattern.Start)
 0353                && _literals1.EqualsOrdinal(pattern.DayHourSep)
 0354                && _literals2.EqualsOrdinal(pattern.HourMinuteSep)
 0355                && _literals3.EqualsOrdinal(pattern.End);
 356
 357            /// <summary>HMS (no days or fraction)</summary>
 358            internal bool FullHMSMatch(TimeSpanFormat.FormatLiterals pattern) =>
 0359                _sepCount == 4
 0360                && _numCount == 3
 0361                && _literals0.EqualsOrdinal(pattern.Start)
 0362                && _literals1.EqualsOrdinal(pattern.HourMinuteSep)
 0363                && _literals2.EqualsOrdinal(pattern.MinuteSecondSep)
 0364                && _literals3.EqualsOrdinal(pattern.End);
 365
 366            /// <summary>DHMS (no fraction)</summary>
 367            internal bool FullDHMSMatch(TimeSpanFormat.FormatLiterals pattern) =>
 0368                _sepCount == 5
 0369                && _numCount == 4
 0370                && _literals0.EqualsOrdinal(pattern.Start)
 0371                && _literals1.EqualsOrdinal(pattern.DayHourSep)
 0372                && _literals2.EqualsOrdinal(pattern.HourMinuteSep)
 0373                && _literals3.EqualsOrdinal(pattern.MinuteSecondSep)
 0374                && _literals4.EqualsOrdinal(pattern.End);
 375
 376            /// <summary>HMSF (no days)</summary>
 377            internal bool FullHMSFMatch(TimeSpanFormat.FormatLiterals pattern) =>
 0378                _sepCount == 5
 0379                && _numCount == 4
 0380                && _literals0.EqualsOrdinal(pattern.Start)
 0381                && _literals1.EqualsOrdinal(pattern.HourMinuteSep)
 0382                && _literals2.EqualsOrdinal(pattern.MinuteSecondSep)
 0383                && _literals3.EqualsOrdinal(pattern.SecondFractionSep)
 0384                && _literals4.EqualsOrdinal(pattern.End);
 385
 386            internal TTT _lastSeenTTT;
 387            internal int _tokenCount;
 388            internal int _sepCount;
 389            internal int _numCount;
 390
 391            private TimeSpanFormat.FormatLiterals _posLoc;
 392            private TimeSpanFormat.FormatLiterals _negLoc;
 393            private bool _posLocInit;
 394            private bool _negLocInit;
 395            private string _fullPosPattern;
 396            private string _fullNegPattern;
 397
 398            private const int MaxTokens = 11;
 399            private const int MaxLiteralTokens = 6;
 400            private const int MaxNumericTokens = 5;
 401
 402            internal TimeSpanToken _numbers0, _numbers1, _numbers2, _numbers3, _numbers4; // MaxNumericTokens = 5
 403            internal ReadOnlySpan<char> _literals0, _literals1, _literals2, _literals3, _literals4, _literals5; // MaxLi
 404
 405            internal void Init(DateTimeFormatInfo dtfi)
 406            {
 0407                Debug.Assert(dtfi != null);
 408
 0409                _lastSeenTTT = TTT.None;
 0410                _tokenCount = 0;
 0411                _sepCount = 0;
 0412                _numCount = 0;
 413
 0414                _fullPosPattern = dtfi.FullTimeSpanPositivePattern;
 0415                _fullNegPattern = dtfi.FullTimeSpanNegativePattern;
 0416                _posLocInit = false;
 0417                _negLocInit = false;
 0418            }
 419
 420            internal bool ProcessToken(ref TimeSpanToken tok, ref TimeSpanResult result)
 421            {
 0422                switch (tok._ttt)
 423                {
 424                    case TTT.Num:
 0425                        if ((_tokenCount == 0 && !AddSep(default, ref result)) || !AddNum(tok, ref result))
 426                        {
 0427                            return false;
 428                        }
 429                        break;
 430
 431                    case TTT.Sep:
 0432                        if (!AddSep(tok._sep, ref result))
 433                        {
 0434                            return false;
 435                        }
 436                        break;
 437
 438                    case TTT.NumOverflow:
 0439                        return result.SetOverflowFailure();
 440
 441                    default:
 442                        // Some unknown token or a repeat token type in the input
 0443                        return result.SetBadTimeSpanFailure();
 444                }
 445
 0446                _lastSeenTTT = tok._ttt;
 0447                Debug.Assert(_tokenCount == (_sepCount + _numCount), "tokenCount == (SepCount + NumCount)");
 0448                return true;
 449            }
 450
 451            private bool AddSep(ReadOnlySpan<char> sep, ref TimeSpanResult result)
 452            {
 0453                if (_sepCount >= MaxLiteralTokens || _tokenCount >= MaxTokens)
 454                {
 0455                    return result.SetBadTimeSpanFailure();
 456                }
 457
 0458                switch (_sepCount++)
 459                {
 0460                    case 0: _literals0 = sep; break;
 0461                    case 1: _literals1 = sep; break;
 0462                    case 2: _literals2 = sep; break;
 0463                    case 3: _literals3 = sep; break;
 0464                    case 4: _literals4 = sep; break;
 0465                    default: _literals5 = sep; break;
 466                }
 467
 0468                _tokenCount++;
 0469                return true;
 470            }
 471            private bool AddNum(TimeSpanToken num, ref TimeSpanResult result)
 472            {
 0473                if (_numCount >= MaxNumericTokens || _tokenCount >= MaxTokens)
 474                {
 0475                    return result.SetBadTimeSpanFailure();
 476                }
 477
 0478                switch (_numCount++)
 479                {
 0480                    case 0: _numbers0 = num; break;
 0481                    case 1: _numbers1 = num; break;
 0482                    case 2: _numbers2 = num; break;
 0483                    case 3: _numbers3 = num; break;
 0484                    default: _numbers4 = num; break;
 485                }
 486
 0487                _tokenCount++;
 0488                return true;
 489            }
 490        }
 491
 492        /// <summary>Store the result of the parsing.</summary>
 493        private ref struct TimeSpanResult
 494        {
 495            internal TimeSpan parsedTimeSpan;
 496            private readonly bool _throwOnFailure;
 497            private readonly ReadOnlySpan<char> _originalTimeSpanString;
 498
 499            internal TimeSpanResult(bool throwOnFailure, ReadOnlySpan<char> originalTimeSpanString)
 500            {
 0501                parsedTimeSpan = default;
 0502                _throwOnFailure = throwOnFailure;
 0503                _originalTimeSpanString = originalTimeSpanString;
 0504            }
 505
 506            internal bool SetNoFormatSpecifierFailure()
 507            {
 0508                if (!_throwOnFailure)
 509                {
 0510                    return false;
 511                }
 512
 0513                throw new FormatException(SR.Format_NoFormatSpecifier);
 514            }
 515
 516            internal bool SetBadQuoteFailure(char failingCharacter)
 517            {
 0518                if (!_throwOnFailure)
 519                {
 0520                    return false;
 521                }
 522
 0523                throw new FormatException(SR.Format(SR.Format_BadQuote, failingCharacter));
 524            }
 525
 526            internal bool SetInvalidStringFailure()
 527            {
 0528                if (!_throwOnFailure)
 529                {
 0530                    return false;
 531                }
 532
 0533                throw new FormatException(SR.Format_InvalidString);
 534            }
 535
 536            internal bool SetArgumentNullFailure(string argumentName)
 537            {
 0538                if (_throwOnFailure)
 539                {
 0540                    Debug.Assert(argumentName != null);
 0541                    ArgumentNullException.Throw(argumentName);
 542                }
 543
 0544                return false;
 545            }
 546
 547            internal bool SetOverflowFailure()
 548            {
 0549                if (!_throwOnFailure)
 550                {
 0551                    return false;
 552                }
 553
 0554                throw new OverflowException(SR.Format(SR.Overflow_TimeSpanElementTooLarge, new string(_originalTimeSpanS
 555            }
 556
 557            internal bool SetBadTimeSpanFailure()
 558            {
 0559                if (!_throwOnFailure)
 560                {
 0561                    return false;
 562                }
 563
 0564                throw new FormatException(SR.Format(SR.Format_BadTimeSpan, new string(_originalTimeSpanString)));
 565            }
 566
 567            internal bool SetBadFormatSpecifierFailure(char? formatSpecifierCharacter = null)
 568            {
 0569                if (!_throwOnFailure)
 570                {
 0571                    return false;
 572                }
 573
 0574                throw new FormatException(SR.Format(SR.Format_BadFormatSpecifier, formatSpecifierCharacter));
 575            }
 576        }
 577
 578        internal static int Pow10UpToMaxFractionDigits(int pow)
 579        {
 0580            ReadOnlySpan<int> powersOfTen =
 0581            [
 0582                1,
 0583                10,
 0584                100,
 0585                1000,
 0586                10000,
 0587                100000,
 0588                1000000,
 0589                10000000,
 0590            ];
 0591            Debug.Assert(powersOfTen.Length == MaxFractionDigits + 1);
 0592            return powersOfTen[pow];
 593        }
 594
 595        private static bool TryTimeToTicks(bool positive, TimeSpanToken days, TimeSpanToken hours, TimeSpanToken minutes
 596        {
 0597            if (days._num > MaxDays ||
 0598                hours._num > MaxHours ||
 0599                minutes._num > MaxMinutes ||
 0600                seconds._num > MaxSeconds ||
 0601                !fraction.NormalizeAndValidateFraction())
 602            {
 0603                result = 0;
 0604                return false;
 605            }
 606
 607            const long MaxMilliSeconds = long.MaxValue / TimeSpan.TicksPerMillisecond;
 608            const long MinMilliSeconds = long.MinValue / TimeSpan.TicksPerMillisecond;
 609
 0610            long ticks = ((long)days._num * 3600 * 24 + (long)hours._num * 3600 + (long)minutes._num * 60 + seconds._num
 0611            if (ticks > MaxMilliSeconds || ticks < MinMilliSeconds)
 612            {
 0613                result = 0;
 0614                return false;
 615            }
 616
 0617            result = ticks * TimeSpan.TicksPerMillisecond + fraction._num;
 0618            if (positive && result < 0)
 619            {
 0620                result = 0;
 0621                return false;
 622            }
 623
 0624            return true;
 625        }
 626
 627        internal static TimeSpan Parse(ReadOnlySpan<char> input, IFormatProvider? formatProvider)
 628        {
 0629            var parseResult = new TimeSpanResult(throwOnFailure: true, originalTimeSpanString: input);
 0630            bool success = TryParseTimeSpan(input, TimeSpanStandardStyles.Any, formatProvider, ref parseResult);
 0631            Debug.Assert(success, "Should have thrown on failure");
 0632            return parseResult.parsedTimeSpan;
 633        }
 634
 635        internal static bool TryParse(ReadOnlySpan<char> input, IFormatProvider? formatProvider, out TimeSpan result)
 636        {
 0637            var parseResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input);
 638
 0639            if (TryParseTimeSpan(input, TimeSpanStandardStyles.Any, formatProvider, ref parseResult))
 640            {
 0641                result = parseResult.parsedTimeSpan;
 0642                return true;
 643            }
 644
 0645            result = default;
 0646            return false;
 647        }
 648
 649        internal static TimeSpan ParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider? format
 650        {
 0651            var parseResult = new TimeSpanResult(throwOnFailure: true, originalTimeSpanString: input);
 0652            bool success = TryParseExactTimeSpan(input, format, formatProvider, styles, ref parseResult);
 0653            Debug.Assert(success, "Should have thrown on failure");
 0654            return parseResult.parsedTimeSpan;
 655        }
 656
 657        internal static bool TryParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider? formatP
 658        {
 0659            var parseResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input);
 660
 0661            if (TryParseExactTimeSpan(input, format, formatProvider, styles, ref parseResult))
 662            {
 0663                result = parseResult.parsedTimeSpan;
 0664                return true;
 665            }
 666
 0667            result = default;
 0668            return false;
 669        }
 670
 671        internal static TimeSpan ParseExactMultiple(ReadOnlySpan<char> input, string?[]? formats, IFormatProvider? forma
 672        {
 0673            var parseResult = new TimeSpanResult(throwOnFailure: true, originalTimeSpanString: input);
 0674            bool success = TryParseExactMultipleTimeSpan(input, formats, formatProvider, styles, ref parseResult);
 0675            Debug.Assert(success, "Should have thrown on failure");
 0676            return parseResult.parsedTimeSpan;
 677        }
 678
 679        internal static bool TryParseExactMultiple(ReadOnlySpan<char> input, string?[]? formats, IFormatProvider? format
 680        {
 0681            var parseResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input);
 682
 0683            if (TryParseExactMultipleTimeSpan(input, formats, formatProvider, styles, ref parseResult))
 684            {
 0685                result = parseResult.parsedTimeSpan;
 0686                return true;
 687            }
 688
 0689            result = default;
 0690            return false;
 691        }
 692
 693        /// <summary>Common private Parse method called by both Parse and TryParse.</summary>
 694        private static bool TryParseTimeSpan(ReadOnlySpan<char> input, TimeSpanStandardStyles style, IFormatProvider? fo
 695        {
 0696            input = input.Trim();
 0697            if (input.IsEmpty)
 698            {
 0699                return result.SetBadTimeSpanFailure();
 700            }
 701
 0702            var tokenizer = new TimeSpanTokenizer(input);
 703
 0704            TimeSpanRawInfo raw = default;
 0705            raw.Init(DateTimeFormatInfo.GetInstance(formatProvider));
 706
 0707            TimeSpanToken tok = tokenizer.GetNextToken();
 708
 709            // The following loop will break out when we reach the end of the str or
 710            // when we can determine that the input is invalid.
 0711            while (tok._ttt != TTT.End)
 712            {
 0713                if (!raw.ProcessToken(ref tok, ref result))
 714                {
 0715                    return result.SetBadTimeSpanFailure();
 716                }
 0717                tok = tokenizer.GetNextToken();
 718            }
 0719            Debug.Assert(tokenizer.EOL);
 720
 0721            if (!ProcessTerminalState(ref raw, style, ref result))
 722            {
 0723                return result.SetBadTimeSpanFailure();
 724            }
 725
 0726            return true;
 727        }
 728
 729        /// <summary>
 730        /// Validate the terminal state of a standard format parse.
 731        /// Sets result.parsedTimeSpan on success.
 732        /// Calculates the resultant TimeSpan from the TimeSpanRawInfo.
 733        /// </summary>
 734        /// <remarks>
 735        /// try => +InvariantPattern, -InvariantPattern, +LocalizedPattern, -LocalizedPattern
 736        /// 1) Verify Start matches
 737        /// 2) Verify End matches
 738        /// 3) 1 number  => d
 739        ///    2 numbers => h:m
 740        ///    3 numbers => h:m:s | d.h:m | h:m:.f
 741        ///    4 numbers => h:m:s.f | d.h:m:s | d.h:m:.f
 742        ///    5 numbers => d.h:m:s.f
 743        /// </remarks>
 744        private static bool ProcessTerminalState(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResu
 745        {
 0746            if (raw._lastSeenTTT == TTT.Num)
 747            {
 0748                TimeSpanToken tok = default;
 0749                tok._ttt = TTT.Sep;
 0750                if (!raw.ProcessToken(ref tok, ref result))
 751                {
 0752                    return result.SetBadTimeSpanFailure();
 753                }
 754            }
 755
 0756            return raw._numCount switch
 0757            {
 0758                1 => ProcessTerminal_D(ref raw, style, ref result),
 0759                2 => ProcessTerminal_HM(ref raw, style, ref result),
 0760                3 => ProcessTerminal_HM_S_D(ref raw, style, ref result),
 0761                4 => ProcessTerminal_HMS_F_D(ref raw, style, ref result),
 0762                5 => ProcessTerminal_DHMSF(ref raw, style, ref result),
 0763                _ => result.SetBadTimeSpanFailure(),
 0764            };
 765        }
 766
 767        /// <summary>Validate the 5-number "Days.Hours:Minutes:Seconds.Fraction" terminal case.</summary>
 768        private static bool ProcessTerminal_DHMSF(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanRes
 769        {
 0770            if (raw._sepCount != 6)
 771            {
 0772                return result.SetBadTimeSpanFailure();
 773            }
 0774            Debug.Assert(raw._numCount == 5);
 775
 0776            bool inv = (style & TimeSpanStandardStyles.Invariant) != 0;
 0777            bool loc = (style & TimeSpanStandardStyles.Localized) != 0;
 0778            bool positive = false;
 0779            bool match = false;
 780
 0781            if (inv)
 782            {
 0783                if (raw.FullMatch(TimeSpanFormat.PositiveInvariantFormatLiterals))
 784                {
 0785                    match = true;
 0786                    positive = true;
 787                }
 0788                if (!match && raw.FullMatch(TimeSpanFormat.NegativeInvariantFormatLiterals))
 789                {
 0790                    match = true;
 0791                    positive = false;
 792                }
 793            }
 794
 0795            if (loc)
 796            {
 0797                if (!match && raw.FullMatch(raw.PositiveLocalized))
 798                {
 0799                    match = true;
 0800                    positive = true;
 801                }
 0802                if (!match && raw.FullMatch(raw.NegativeLocalized))
 803                {
 0804                    match = true;
 0805                    positive = false;
 806                }
 807            }
 808
 0809            if (match)
 810            {
 811
 0812                if (!TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, raw._numbers4,
 813                {
 0814                    return result.SetOverflowFailure();
 815                }
 816
 0817                if (!positive)
 818                {
 0819                    ticks = -ticks;
 0820                    if (ticks > 0)
 821                    {
 0822                        return result.SetOverflowFailure();
 823                    }
 824                }
 825
 0826                result.parsedTimeSpan = new TimeSpan(ticks);
 0827                return true;
 828            }
 829
 0830            return result.SetBadTimeSpanFailure();
 831        }
 832
 833
 834        /// <summary>
 835        /// Validate the ambiguous 4-number "Hours:Minutes:Seconds.Fraction", "Days.Hours:Minutes:Seconds",
 836        /// or "Days.Hours:Minutes:.Fraction" terminal case.
 837        /// </summary>
 838        private static bool ProcessTerminal_HMS_F_D(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanR
 839        {
 0840            if (raw._sepCount != 5 || (style & TimeSpanStandardStyles.RequireFull) != 0)
 841            {
 0842                return result.SetBadTimeSpanFailure();
 843            }
 0844            Debug.Assert(raw._numCount == 4);
 845
 0846            bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0);
 0847            bool loc = ((style & TimeSpanStandardStyles.Localized) != 0);
 848
 0849            long ticks = 0;
 0850            bool positive = false, match = false, overflow = false;
 0851            var zero = new TimeSpanToken(0);
 852
 0853            if (inv)
 854            {
 0855                if (raw.FullHMSFMatch(TimeSpanFormat.PositiveInvariantFormatLiterals))
 856                {
 0857                    positive = true;
 0858                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, o
 0859                    overflow = overflow || !match;
 860                }
 861
 0862                if (!match && raw.FullDHMSMatch(TimeSpanFormat.PositiveInvariantFormatLiterals))
 863                {
 0864                    positive = true;
 0865                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, zero, o
 0866                    overflow = overflow || !match;
 867                }
 868
 0869                if (!match && raw.FullAppCompatMatch(TimeSpanFormat.PositiveInvariantFormatLiterals))
 870                {
 0871                    positive = true;
 0872                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, raw._numbers3, o
 0873                    overflow = overflow || !match;
 874                }
 875
 0876                if (!match && raw.FullHMSFMatch(TimeSpanFormat.NegativeInvariantFormatLiterals))
 877                {
 0878                    positive = false;
 0879                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, o
 0880                    overflow = overflow || !match;
 881                }
 882
 0883                if (!match && raw.FullDHMSMatch(TimeSpanFormat.NegativeInvariantFormatLiterals))
 884                {
 0885                    positive = false;
 0886                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, zero, o
 0887                    overflow = overflow || !match;
 888                }
 889
 0890                if (!match && raw.FullAppCompatMatch(TimeSpanFormat.NegativeInvariantFormatLiterals))
 891                {
 0892                    positive = false;
 0893                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, raw._numbers3, o
 0894                    overflow = overflow || !match;
 895                }
 896            }
 897
 0898            if (loc)
 899            {
 0900                if (!match && raw.FullHMSFMatch(raw.PositiveLocalized))
 901                {
 0902                    positive = true;
 0903                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, o
 0904                    overflow = overflow || !match;
 905                }
 906
 0907                if (!match && raw.FullDHMSMatch(raw.PositiveLocalized))
 908                {
 0909                    positive = true;
 0910                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, zero, o
 0911                    overflow = overflow || !match;
 912                }
 913
 0914                if (!match && raw.FullAppCompatMatch(raw.PositiveLocalized))
 915                {
 0916                    positive = true;
 0917                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, raw._numbers3, o
 0918                    overflow = overflow || !match;
 919                }
 920
 0921                if (!match && raw.FullHMSFMatch(raw.NegativeLocalized))
 922                {
 0923                    positive = false;
 0924                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, o
 0925                    overflow = overflow || !match;
 926                }
 927
 0928                if (!match && raw.FullDHMSMatch(raw.NegativeLocalized))
 929                {
 0930                    positive = false;
 0931                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, zero, o
 0932                    overflow = overflow || !match;
 933                }
 934
 0935                if (!match && raw.FullAppCompatMatch(raw.NegativeLocalized))
 936                {
 0937                    positive = false;
 0938                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, raw._numbers3, o
 0939                    overflow = overflow || !match;
 940                }
 941            }
 942
 0943            if (match)
 944            {
 0945                if (!positive)
 946                {
 0947                    ticks = -ticks;
 0948                    if (ticks > 0)
 949                    {
 0950                        return result.SetOverflowFailure();
 951                    }
 952                }
 953
 0954                result.parsedTimeSpan = new TimeSpan(ticks);
 0955                return true;
 956            }
 957
 0958            return overflow ?
 0959                result.SetOverflowFailure() : // we found at least one literal pattern match but the numbers just didn't
 0960                result.SetBadTimeSpanFailure(); // we couldn't find a thing
 961        }
 962
 963        /// <summary>Validate the ambiguous 3-number "Hours:Minutes:Seconds", "Days.Hours:Minutes", or "Hours:Minutes:.F
 964        private static bool ProcessTerminal_HM_S_D(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanRe
 965        {
 0966            if (raw._sepCount != 4 || (style & TimeSpanStandardStyles.RequireFull) != 0)
 967            {
 0968                return result.SetBadTimeSpanFailure();
 969            }
 0970            Debug.Assert(raw._numCount == 3);
 971
 0972            bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0);
 0973            bool loc = ((style & TimeSpanStandardStyles.Localized) != 0);
 974
 0975            bool positive = false, match = false, overflow = false;
 0976            var zero = new TimeSpanToken(0);
 0977            long ticks = 0;
 978
 0979            if (inv)
 980            {
 0981                if (raw.FullHMSMatch(TimeSpanFormat.PositiveInvariantFormatLiterals))
 982                {
 0983                    positive = true;
 0984                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, zero, out ticks)
 0985                    overflow = overflow || !match;
 986                }
 987
 0988                if (!match && raw.FullDHMMatch(TimeSpanFormat.PositiveInvariantFormatLiterals))
 989                {
 0990                    positive = true;
 0991                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, zero, out ticks)
 0992                    overflow = overflow || !match;
 993                }
 994
 0995                if (!match && raw.PartialAppCompatMatch(TimeSpanFormat.PositiveInvariantFormatLiterals))
 996                {
 0997                    positive = true;
 0998                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, raw._numbers2, out ticks)
 0999                    overflow = overflow || !match;
 1000                }
 1001
 01002                if (!match && raw.FullHMSMatch(TimeSpanFormat.NegativeInvariantFormatLiterals))
 1003                {
 01004                    positive = false;
 01005                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, zero, out ticks)
 01006                    overflow = overflow || !match;
 1007                }
 1008
 01009                if (!match && raw.FullDHMMatch(TimeSpanFormat.NegativeInvariantFormatLiterals))
 1010                {
 01011                    positive = false;
 01012                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, zero, out ticks)
 01013                    overflow = overflow || !match;
 1014                }
 1015
 01016                if (!match && raw.PartialAppCompatMatch(TimeSpanFormat.NegativeInvariantFormatLiterals))
 1017                {
 01018                    positive = false;
 01019                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, raw._numbers2, out ticks)
 01020                    overflow = overflow || !match;
 1021                }
 1022            }
 1023
 01024            if (loc)
 1025            {
 01026                if (!match && raw.FullHMSMatch(raw.PositiveLocalized))
 1027                {
 01028                    positive = true;
 01029                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, zero, out ticks)
 01030                    overflow = overflow || !match;
 1031                }
 1032
 01033                if (!match && raw.FullDHMMatch(raw.PositiveLocalized))
 1034                {
 01035                    positive = true;
 01036                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, zero, out ticks)
 01037                    overflow = overflow || !match;
 1038                }
 1039
 01040                if (!match && raw.PartialAppCompatMatch(raw.PositiveLocalized))
 1041                {
 01042                    positive = true;
 01043                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, raw._numbers2, out ticks)
 01044                    overflow = overflow || !match;
 1045                }
 1046
 01047                if (!match && raw.FullHMSMatch(raw.NegativeLocalized))
 1048                {
 01049                    positive = false;
 01050                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, zero, out ticks)
 01051                    overflow = overflow || !match;
 1052                }
 1053
 01054                if (!match && raw.FullDHMMatch(raw.NegativeLocalized))
 1055                {
 01056                    positive = false;
 01057                    match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, zero, out ticks)
 01058                    overflow = overflow || !match;
 1059                }
 1060
 01061                if (!match && raw.PartialAppCompatMatch(raw.NegativeLocalized))
 1062                {
 01063                    positive = false;
 01064                    match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, raw._numbers2, out ticks)
 01065                    overflow = overflow || !match;
 1066                }
 1067            }
 1068
 01069            if (match)
 1070            {
 01071                if (!positive)
 1072                {
 01073                    ticks = -ticks;
 01074                    if (ticks > 0)
 1075                    {
 01076                        return result.SetOverflowFailure();
 1077                    }
 1078                }
 1079
 01080                result.parsedTimeSpan = new TimeSpan(ticks);
 01081                return true;
 1082            }
 1083
 01084            return overflow ?
 01085                result.SetOverflowFailure() : // we found at least one literal pattern match but the numbers just didn't
 01086                result.SetBadTimeSpanFailure(); // we couldn't find a thing
 1087        }
 1088
 1089        /// <summary>Validate the 2-number "Hours:Minutes" terminal case.</summary>
 1090        private static bool ProcessTerminal_HM(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult
 1091        {
 01092            if (raw._sepCount != 3 || (style & TimeSpanStandardStyles.RequireFull) != 0)
 1093            {
 01094                return result.SetBadTimeSpanFailure();
 1095            }
 01096            Debug.Assert(raw._numCount == 2);
 1097
 01098            bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0);
 01099            bool loc = ((style & TimeSpanStandardStyles.Localized) != 0);
 1100
 01101            bool positive = false, match = false;
 1102
 01103            if (inv)
 1104            {
 01105                if (raw.FullHMMatch(TimeSpanFormat.PositiveInvariantFormatLiterals))
 1106                {
 01107                    match = true;
 01108                    positive = true;
 1109                }
 1110
 01111                if (!match && raw.FullHMMatch(TimeSpanFormat.NegativeInvariantFormatLiterals))
 1112                {
 01113                    match = true;
 01114                    positive = false;
 1115                }
 1116            }
 1117
 01118            if (loc)
 1119            {
 01120                if (!match && raw.FullHMMatch(raw.PositiveLocalized))
 1121                {
 01122                    match = true;
 01123                    positive = true;
 1124                }
 1125
 01126                if (!match && raw.FullHMMatch(raw.NegativeLocalized))
 1127                {
 01128                    match = true;
 01129                    positive = false;
 1130                }
 1131            }
 1132
 01133            if (match)
 1134            {
 01135                var zero = new TimeSpanToken(0);
 1136
 01137                if (!TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, zero, out long ticks))
 1138                {
 01139                    return result.SetOverflowFailure();
 1140                }
 1141
 01142                if (!positive)
 1143                {
 01144                    ticks = -ticks;
 01145                    if (ticks > 0)
 1146                    {
 01147                        return result.SetOverflowFailure();
 1148                    }
 1149                }
 1150
 01151                result.parsedTimeSpan = new TimeSpan(ticks);
 01152                return true;
 1153            }
 1154
 01155            return result.SetBadTimeSpanFailure();
 1156        }
 1157
 1158        /// <summary>Validate the 1-number "Days" terminal case.</summary>
 1159        private static bool ProcessTerminal_D(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult 
 1160        {
 01161            if (raw._sepCount != 2 || (style & TimeSpanStandardStyles.RequireFull) != 0)
 1162            {
 01163                return result.SetBadTimeSpanFailure();
 1164            }
 01165            Debug.Assert(raw._numCount == 1);
 1166
 01167            bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0);
 01168            bool loc = ((style & TimeSpanStandardStyles.Localized) != 0);
 1169
 01170            bool positive = false, match = false;
 1171
 01172            if (inv)
 1173            {
 01174                if (raw.FullDMatch(TimeSpanFormat.PositiveInvariantFormatLiterals))
 1175                {
 01176                    match = true;
 01177                    positive = true;
 1178                }
 1179
 01180                if (!match && raw.FullDMatch(TimeSpanFormat.NegativeInvariantFormatLiterals))
 1181                {
 01182                    match = true;
 01183                    positive = false;
 1184                }
 1185            }
 1186
 01187            if (loc)
 1188            {
 01189                if (!match && raw.FullDMatch(raw.PositiveLocalized))
 1190                {
 01191                    match = true;
 01192                    positive = true;
 1193                }
 1194
 01195                if (!match && raw.FullDMatch(raw.NegativeLocalized))
 1196                {
 01197                    match = true;
 01198                    positive = false;
 1199                }
 1200            }
 1201
 01202            if (match)
 1203            {
 01204                var zero = new TimeSpanToken(0);
 1205
 01206                if (!TryTimeToTicks(positive, raw._numbers0, zero, zero, zero, zero, out long ticks))
 1207                {
 01208                    return result.SetOverflowFailure();
 1209                }
 1210
 01211                if (!positive)
 1212                {
 01213                    ticks = -ticks;
 01214                    if (ticks > 0)
 1215                    {
 01216                        return result.SetOverflowFailure();
 1217                    }
 1218                }
 1219
 01220                result.parsedTimeSpan = new TimeSpan(ticks);
 01221                return true;
 1222            }
 1223
 01224            return result.SetBadTimeSpanFailure();
 1225        }
 1226
 1227        /// <summary>Common private ParseExact method called by both ParseExact and TryParseExact.</summary>
 1228        private static bool TryParseExactTimeSpan(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider? 
 1229        {
 01230            if (format.Length == 0)
 1231            {
 01232                return result.SetBadFormatSpecifierFailure();
 1233            }
 1234
 01235            if (format.Length == 1)
 1236            {
 01237                return format[0] switch
 01238                {
 01239                    'c' or 't' or 'T' => TryParseTimeSpanConstant(input, ref result), // fast path for legacy style Time
 01240                    'g' => TryParseTimeSpan(input, TimeSpanStandardStyles.Localized, formatProvider, ref result),
 01241                    'G' => TryParseTimeSpan(input, TimeSpanStandardStyles.Localized | TimeSpanStandardStyles.RequireFull
 01242                    _ => result.SetBadFormatSpecifierFailure(format[0]),
 01243                };
 1244            }
 1245
 01246            return TryParseByFormat(input, format, styles, ref result);
 1247        }
 1248
 1249        /// <summary>Parse the TimeSpan instance using the specified format.  Used by TryParseExactTimeSpan.</summary>
 1250        private static bool TryParseByFormat(ReadOnlySpan<char> input, ReadOnlySpan<char> format, TimeSpanStyles styles,
 1251        {
 01252            bool seenDD = false;      // already processed days?
 01253            bool seenHH = false;      // already processed hours?
 01254            bool seenMM = false;      // already processed minutes?
 01255            bool seenSS = false;      // already processed seconds?
 01256            bool seenFF = false;      // already processed fraction?
 1257
 01258            int dd = 0;               // parsed days
 01259            int hh = 0;               // parsed hours
 01260            int mm = 0;               // parsed minutes
 01261            int ss = 0;               // parsed seconds
 01262            int leadingZeroes = 0;    // number of leading zeroes in the parsed fraction
 01263            int ff = 0;               // parsed fraction
 01264            int i = 0;                // format string position
 1265            int tokenLen;             // length of current format token, used to update index 'i'
 1266
 01267            var tokenizer = new TimeSpanTokenizer(input, -1);
 1268
 01269            while ((uint)i < (uint)format.Length)
 1270            {
 01271                char ch = format[i];
 1272                int nextFormatChar;
 1273                switch (ch)
 1274                {
 1275                    case 'h':
 01276                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
 01277                        if (tokenLen > 2 || seenHH || !ParseExactDigits(ref tokenizer, tokenLen, out hh))
 1278                        {
 01279                            return result.SetInvalidStringFailure();
 1280                        }
 01281                        seenHH = true;
 01282                        break;
 1283
 1284                    case 'm':
 01285                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
 01286                        if (tokenLen > 2 || seenMM || !ParseExactDigits(ref tokenizer, tokenLen, out mm))
 1287                        {
 01288                            return result.SetInvalidStringFailure();
 1289                        }
 01290                        seenMM = true;
 01291                        break;
 1292
 1293                    case 's':
 01294                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
 01295                        if (tokenLen > 2 || seenSS || !ParseExactDigits(ref tokenizer, tokenLen, out ss))
 1296                        {
 01297                            return result.SetInvalidStringFailure();
 1298                        }
 01299                        seenSS = true;
 01300                        break;
 1301
 1302                    case 'f':
 01303                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
 01304                        if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits || seenFF || !ParseExactDigits(ref tokeni
 1305                        {
 01306                            return result.SetInvalidStringFailure();
 1307                        }
 01308                        seenFF = true;
 01309                        break;
 1310
 1311                    case 'F':
 01312                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
 01313                        if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits || seenFF)
 1314                        {
 01315                            return result.SetInvalidStringFailure();
 1316                        }
 01317                        ParseExactDigits(ref tokenizer, tokenLen, tokenLen, out leadingZeroes, out ff);
 01318                        seenFF = true;
 01319                        break;
 1320
 1321                    case 'd':
 01322                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
 01323                        if (tokenLen > 8 || seenDD || !ParseExactDigits(ref tokenizer, (tokenLen < 2) ? 1 : tokenLen, (t
 1324                        {
 01325                            return result.SetInvalidStringFailure();
 1326                        }
 01327                        seenDD = true;
 01328                        break;
 1329
 1330                    case '\'':
 1331                    case '\"':
 01332                        var enquotedString = new ValueStringBuilder(64);
 01333                        if (!DateTimeParse.TryParseQuoteString(format, i, ref enquotedString, out tokenLen))
 1334                        {
 01335                            enquotedString.Dispose();
 01336                            return result.SetBadQuoteFailure(ch);
 1337                        }
 01338                        if (!ParseExactLiteral(ref tokenizer, ref enquotedString))
 1339                        {
 01340                            enquotedString.Dispose();
 01341                            return result.SetInvalidStringFailure();
 1342                        }
 01343                        enquotedString.Dispose();
 01344                        break;
 1345
 1346                    case '%':
 1347                        // Optional format character.
 1348                        // For example, format string "%d" will print day
 1349                        // Most of the cases, "%" can be ignored.
 01350                        nextFormatChar = DateTimeFormat.ParseNextChar(format, i);
 1351
 1352                        // nextFormatChar will be -1 if we already reach the end of the format string.
 1353                        // Besides, we will not allow "%%" appear in the pattern.
 01354                        if (nextFormatChar >= 0 && nextFormatChar != '%')
 1355                        {
 01356                            tokenLen = 1; // skip the '%' and process the format character
 01357                            break;
 1358                        }
 1359                        else
 1360                        {
 1361                            // This means that '%' is at the end of the format string or
 1362                            // "%%" appears in the format string.
 01363                            return result.SetInvalidStringFailure();
 1364                        }
 1365
 1366                    case '\\':
 1367                        // Escaped character.  Can be used to insert character into the format string.
 1368                        // For example, "\d" will insert the character 'd' into the string.
 1369                        //
 01370                        nextFormatChar = DateTimeFormat.ParseNextChar(format, i);
 01371                        if (nextFormatChar >= 0 && tokenizer.NextChar() == (char)nextFormatChar)
 1372                        {
 01373                            tokenLen = 2;
 1374                        }
 1375                        else
 1376                        {
 1377                            // This means that '\' is at the end of the format string or the literal match failed.
 01378                            return result.SetInvalidStringFailure();
 1379                        }
 1380                        break;
 1381
 1382                    default:
 01383                        return result.SetInvalidStringFailure();
 1384                }
 1385
 01386                i += tokenLen;
 1387            }
 1388
 1389
 01390            if (!tokenizer.EOL)
 1391            {
 1392                // the custom format didn't consume the entire input
 01393                return result.SetBadTimeSpanFailure();
 1394            }
 1395
 01396            bool positive = (styles & TimeSpanStyles.AssumeNegative) == 0;
 01397            if (TryTimeToTicks(positive, new TimeSpanToken(dd),
 01398                                         new TimeSpanToken(hh),
 01399                                         new TimeSpanToken(mm),
 01400                                         new TimeSpanToken(ss),
 01401                                         new TimeSpanToken(ff, leadingZeroes),
 01402                                         out long ticks))
 1403            {
 01404                if (!positive)
 1405                {
 01406                    ticks = -ticks;
 1407                }
 1408
 01409                result.parsedTimeSpan = new TimeSpan(ticks);
 01410                return true;
 1411            }
 1412            else
 1413            {
 01414                return result.SetOverflowFailure();
 1415            }
 1416        }
 1417
 1418        private static bool ParseExactDigits(ref TimeSpanTokenizer tokenizer, int minDigitLength, out int result)
 1419        {
 01420            int maxDigitLength = (minDigitLength == 1) ? 2 : minDigitLength;
 01421            return ParseExactDigits(ref tokenizer, minDigitLength, maxDigitLength, out _, out result);
 1422        }
 1423
 1424        private static bool ParseExactDigits(ref TimeSpanTokenizer tokenizer, int minDigitLength, int maxDigitLength, ou
 1425        {
 01426            int tmpResult = 0, tmpZeroes = 0;
 1427
 01428            int tokenLength = 0;
 01429            while (tokenLength < maxDigitLength)
 1430            {
 01431                char ch = tokenizer.NextChar();
 01432                if (!char.IsAsciiDigit(ch))
 1433                {
 01434                    tokenizer.BackOne();
 01435                    break;
 1436                }
 1437
 01438                tmpResult = tmpResult * 10 + (ch - '0');
 01439                if (tmpResult == 0) tmpZeroes++;
 01440                tokenLength++;
 1441            }
 1442
 01443            zeroes = tmpZeroes;
 01444            result = tmpResult;
 01445            return tokenLength >= minDigitLength;
 1446        }
 1447
 1448        private static bool ParseExactLiteral(ref TimeSpanTokenizer tokenizer, ref ValueStringBuilder enquotedString)
 1449        {
 01450            ReadOnlySpan<char> span = enquotedString.AsSpan();
 01451            for (int i = 0; i < span.Length; i++)
 1452            {
 01453                if (span[i] != tokenizer.NextChar())
 1454                {
 01455                    return false;
 1456                }
 1457            }
 1458
 01459            return true;
 1460        }
 1461
 1462        /// <summary>
 1463        /// Parses the "c" (constant) format.  This code is 100% identical to the non-globalized v1.0-v3.5 TimeSpan.Pars
 1464        /// and exists for performance/appcompat with legacy callers who cannot move onto the globalized Parse overloads
 1465        /// </summary>
 1466        private static bool TryParseTimeSpanConstant(ReadOnlySpan<char> input, ref TimeSpanResult result) =>
 01467            default(StringParser).TryParse(input, ref result);
 1468
 1469        private ref struct StringParser
 1470        {
 1471            private ReadOnlySpan<char> _str;
 1472            private char _ch;
 1473            private int _pos;
 1474
 1475            internal void NextChar()
 1476            {
 01477                ReadOnlySpan<char> str = _str;
 1478
 01479                if (_pos < str.Length)
 1480                {
 01481                    _pos++;
 1482                }
 1483
 01484                int pos = _pos;
 01485                _ch = (uint)pos < (uint)str.Length ?
 01486                    str[pos] :
 01487                    (char)0;
 01488            }
 1489
 1490            internal char NextNonDigit()
 1491            {
 01492                int i = _str.Slice(_pos).IndexOfAnyExceptInRange('0', '9');
 01493                return i < 0 ? (char)0 : _str[_pos + i];
 1494            }
 1495
 1496            internal bool TryParse(ReadOnlySpan<char> input, ref TimeSpanResult result)
 1497            {
 01498                result.parsedTimeSpan = default;
 1499
 01500                _str = input;
 01501                _pos = -1;
 01502                NextChar();
 01503                SkipBlanks();
 1504
 01505                bool negative = false;
 01506                if (_ch == '-')
 1507                {
 01508                    negative = true;
 01509                    NextChar();
 1510                }
 1511
 1512                long time;
 01513                if (NextNonDigit() == ':')
 1514                {
 01515                    if (!ParseTime(out time, ref result))
 1516                    {
 01517                        return false;
 1518                    }
 1519                }
 1520                else
 1521                {
 01522                    if (!ParseInt((int)(0x7FFFFFFFFFFFFFFFL / TimeSpan.TicksPerDay), out int days, ref result))
 1523                    {
 01524                        return false;
 1525                    }
 1526
 01527                    time = days * TimeSpan.TicksPerDay;
 1528
 01529                    if (_ch == '.')
 1530                    {
 01531                        NextChar();
 01532                        if (!ParseTime(out long remainingTime, ref result))
 1533                        {
 01534                            return false;
 1535                        }
 01536                        time += remainingTime;
 1537                    }
 1538                }
 1539
 01540                if (negative)
 1541                {
 01542                    time = -time;
 1543                    // Allow -0 as well
 01544                    if (time > 0)
 1545                    {
 01546                        return result.SetOverflowFailure();
 1547                    }
 1548                }
 1549                else
 1550                {
 01551                    if (time < 0)
 1552                    {
 01553                        return result.SetOverflowFailure();
 1554                    }
 1555                }
 1556
 01557                SkipBlanks();
 1558
 01559                if (_pos < _str.Length)
 1560                {
 01561                    return result.SetBadTimeSpanFailure();
 1562                }
 1563
 01564                result.parsedTimeSpan = new TimeSpan(time);
 01565                return true;
 1566            }
 1567
 1568            internal bool ParseInt(int max, out int i, ref TimeSpanResult result)
 1569            {
 01570                i = 0;
 01571                int p = _pos;
 01572                while (char.IsAsciiDigit(_ch))
 1573                {
 01574                    if ((i & 0xF0000000) != 0)
 1575                    {
 01576                        return result.SetOverflowFailure();
 1577                    }
 1578
 01579                    i = i * 10 + _ch - '0';
 01580                    if (i < 0)
 1581                    {
 01582                        return result.SetOverflowFailure();
 1583                    }
 1584
 01585                    NextChar();
 1586                }
 1587
 01588                if (p == _pos)
 1589                {
 01590                    return result.SetBadTimeSpanFailure();
 1591                }
 1592
 01593                if (i > max)
 1594                {
 01595                    return result.SetOverflowFailure();
 1596                }
 1597
 01598                return true;
 1599            }
 1600
 1601            internal bool ParseTime(out long time, ref TimeSpanResult result)
 1602            {
 01603                time = 0;
 1604
 01605                if (!ParseInt(23, out int unit, ref result))
 1606                {
 01607                    return false;
 1608                }
 1609
 01610                time = unit * TimeSpan.TicksPerHour;
 01611                if (_ch != ':')
 1612                {
 01613                    return result.SetBadTimeSpanFailure();
 1614                }
 1615
 01616                NextChar();
 1617
 01618                if (!ParseInt(59, out unit, ref result))
 1619                {
 01620                    return false;
 1621                }
 1622
 01623                time += unit * TimeSpan.TicksPerMinute;
 1624
 01625                if (_ch == ':')
 1626                {
 01627                    NextChar();
 1628
 1629                    // allow seconds with the leading zero
 01630                    if (_ch != '.')
 1631                    {
 01632                        if (!ParseInt(59, out unit, ref result))
 1633                        {
 01634                            return false;
 1635                        }
 01636                        time += unit * TimeSpan.TicksPerSecond;
 1637                    }
 1638
 01639                    if (_ch == '.')
 1640                    {
 01641                        NextChar();
 01642                        int f = (int)TimeSpan.TicksPerSecond;
 01643                        while (f > 1 && char.IsAsciiDigit(_ch))
 1644                        {
 01645                            f /= 10;
 01646                            time += (_ch - '0') * f;
 01647                            NextChar();
 1648                        }
 1649                    }
 1650                }
 1651
 01652                return true;
 1653            }
 1654
 1655            internal void SkipBlanks()
 1656            {
 01657                while (_ch == ' ' || _ch == '\t') NextChar();
 01658            }
 1659        }
 1660
 1661        /// <summary>Common private ParseExactMultiple method called by both ParseExactMultiple and TryParseExactMultipl
 1662        private static bool TryParseExactMultipleTimeSpan(ReadOnlySpan<char> input, string?[]? formats, IFormatProvider?
 1663        {
 01664            if (formats == null)
 1665            {
 01666                return result.SetArgumentNullFailure(nameof(formats));
 1667            }
 1668
 01669            if (input.Length == 0)
 1670            {
 01671                return result.SetBadTimeSpanFailure();
 1672            }
 1673
 01674            if (formats.Length == 0)
 1675            {
 01676                return result.SetNoFormatSpecifierFailure();
 1677            }
 1678
 1679            // Do a loop through the provided formats and see if we can parse successfully in
 1680            // one of the formats.
 01681            for (int i = 0; i < formats.Length; i++)
 1682            {
 01683                string? format = formats[i];
 1684
 01685                if (string.IsNullOrEmpty(format))
 1686                {
 01687                    return result.SetBadFormatSpecifierFailure();
 1688                }
 1689
 1690                // Create a new non-throwing result each time to ensure the runs are independent.
 01691                TimeSpanResult innerResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input);
 1692
 01693                if (TryParseExactTimeSpan(input, format, formatProvider, styles, ref innerResult))
 1694                {
 01695                    result.parsedTimeSpan = innerResult.parsedTimeSpan;
 01696                    return true;
 1697                }
 1698            }
 1699
 01700            return result.SetBadTimeSpanFailure();
 1701        }
 1702    }
 1703}
 1704

Methods/Properties

.ctor(System.Globalization.TimeSpanParse/TTT)
.ctor(System.Int32)
.ctor(System.Int32,System.Int32)
.ctor(System.Globalization.TimeSpanParse/TTT,System.Int32,System.Int32,System.ReadOnlySpan`1<System.Char>)
NormalizeAndValidateFraction()
.ctor(System.ReadOnlySpan`1<System.Char>)
.ctor(System.ReadOnlySpan`1<System.Char>,System.Int32)
GetNextToken()
EOL()
BackOne()
NextChar()
PositiveLocalized()
NegativeLocalized()
FullAppCompatMatch(System.Globalization.TimeSpanFormat/FormatLiterals)
PartialAppCompatMatch(System.Globalization.TimeSpanFormat/FormatLiterals)
FullMatch(System.Globalization.TimeSpanFormat/FormatLiterals)
FullDMatch(System.Globalization.TimeSpanFormat/FormatLiterals)
FullHMMatch(System.Globalization.TimeSpanFormat/FormatLiterals)
FullDHMMatch(System.Globalization.TimeSpanFormat/FormatLiterals)
FullHMSMatch(System.Globalization.TimeSpanFormat/FormatLiterals)
FullDHMSMatch(System.Globalization.TimeSpanFormat/FormatLiterals)
FullHMSFMatch(System.Globalization.TimeSpanFormat/FormatLiterals)
Init(System.Globalization.DateTimeFormatInfo)
ProcessToken(System.Globalization.TimeSpanParse/TimeSpanToken&,System.Globalization.TimeSpanParse/TimeSpanResult&)
AddSep(System.ReadOnlySpan`1<System.Char>,System.Globalization.TimeSpanParse/TimeSpanResult&)
AddNum(System.Globalization.TimeSpanParse/TimeSpanToken,System.Globalization.TimeSpanParse/TimeSpanResult&)
.ctor(System.Boolean,System.ReadOnlySpan`1<System.Char>)
SetNoFormatSpecifierFailure()
SetBadQuoteFailure(System.Char)
SetInvalidStringFailure()
SetArgumentNullFailure(System.String)
SetOverflowFailure()
SetBadTimeSpanFailure()
SetBadFormatSpecifierFailure(System.Nullable`1<System.Char>)
Pow10UpToMaxFractionDigits(System.Int32)
TryTimeToTicks(System.Boolean,System.Globalization.TimeSpanParse/TimeSpanToken,System.Globalization.TimeSpanParse/TimeSpanToken,System.Globalization.TimeSpanParse/TimeSpanToken,System.Globalization.TimeSpanParse/TimeSpanToken,System.Globalization.TimeSpanParse/TimeSpanToken,System.Int64&)
Parse(System.ReadOnlySpan`1<System.Char>,System.IFormatProvider)
TryParse(System.ReadOnlySpan`1<System.Char>,System.IFormatProvider,System.TimeSpan&)
ParseExact(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.IFormatProvider,System.Globalization.TimeSpanStyles)
TryParseExact(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.IFormatProvider,System.Globalization.TimeSpanStyles,System.TimeSpan&)
ParseExactMultiple(System.ReadOnlySpan`1<System.Char>,System.String[],System.IFormatProvider,System.Globalization.TimeSpanStyles)
TryParseExactMultiple(System.ReadOnlySpan`1<System.Char>,System.String[],System.IFormatProvider,System.Globalization.TimeSpanStyles,System.TimeSpan&)
TryParseTimeSpan(System.ReadOnlySpan`1<System.Char>,System.Globalization.TimeSpanParse/TimeSpanStandardStyles,System.IFormatProvider,System.Globalization.TimeSpanParse/TimeSpanResult&)
ProcessTerminalState(System.Globalization.TimeSpanParse/TimeSpanRawInfo&,System.Globalization.TimeSpanParse/TimeSpanStandardStyles,System.Globalization.TimeSpanParse/TimeSpanResult&)
ProcessTerminal_DHMSF(System.Globalization.TimeSpanParse/TimeSpanRawInfo&,System.Globalization.TimeSpanParse/TimeSpanStandardStyles,System.Globalization.TimeSpanParse/TimeSpanResult&)
ProcessTerminal_HMS_F_D(System.Globalization.TimeSpanParse/TimeSpanRawInfo&,System.Globalization.TimeSpanParse/TimeSpanStandardStyles,System.Globalization.TimeSpanParse/TimeSpanResult&)
ProcessTerminal_HM_S_D(System.Globalization.TimeSpanParse/TimeSpanRawInfo&,System.Globalization.TimeSpanParse/TimeSpanStandardStyles,System.Globalization.TimeSpanParse/TimeSpanResult&)
ProcessTerminal_HM(System.Globalization.TimeSpanParse/TimeSpanRawInfo&,System.Globalization.TimeSpanParse/TimeSpanStandardStyles,System.Globalization.TimeSpanParse/TimeSpanResult&)
ProcessTerminal_D(System.Globalization.TimeSpanParse/TimeSpanRawInfo&,System.Globalization.TimeSpanParse/TimeSpanStandardStyles,System.Globalization.TimeSpanParse/TimeSpanResult&)
TryParseExactTimeSpan(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.IFormatProvider,System.Globalization.TimeSpanStyles,System.Globalization.TimeSpanParse/TimeSpanResult&)
TryParseByFormat(System.ReadOnlySpan`1<System.Char>,System.ReadOnlySpan`1<System.Char>,System.Globalization.TimeSpanStyles,System.Globalization.TimeSpanParse/TimeSpanResult&)
ParseExactDigits(System.Globalization.TimeSpanParse/TimeSpanTokenizer&,System.Int32,System.Int32&)
ParseExactDigits(System.Globalization.TimeSpanParse/TimeSpanTokenizer&,System.Int32,System.Int32,System.Int32&,System.Int32&)
ParseExactLiteral(System.Globalization.TimeSpanParse/TimeSpanTokenizer&,System.Text.ValueStringBuilder&)
TryParseTimeSpanConstant(System.ReadOnlySpan`1<System.Char>,System.Globalization.TimeSpanParse/TimeSpanResult&)
NextChar()
NextNonDigit()
TryParse(System.ReadOnlySpan`1<System.Char>,System.Globalization.TimeSpanParse/TimeSpanResult&)
ParseInt(System.Int32,System.Int32&,System.Globalization.TimeSpanParse/TimeSpanResult&)
ParseTime(System.Int64&,System.Globalization.TimeSpanParse/TimeSpanResult&)
SkipBlanks()
TryParseExactMultipleTimeSpan(System.ReadOnlySpan`1<System.Char>,System.String[],System.IFormatProvider,System.Globalization.TimeSpanStyles,System.Globalization.TimeSpanParse/TimeSpanResult&)