コード例 #1
0
ファイル: PeriodPattern.cs プロジェクト: wase932/nodatime
            public ParseResult <Period> Parse(string text)
            {
                if (text is null)
                {
                    return(ParseResult <Period> .ArgumentNull("text"));
                }
                if (text.Length == 0)
                {
                    return(ParseResult <Period> .ValueStringEmpty);
                }

                ValueCursor valueCursor = new ValueCursor(text);

                valueCursor.MoveNext();
                if (valueCursor.Current != 'P')
                {
                    return(ParseResult <Period> .MismatchedCharacter(valueCursor, 'P'));
                }
                bool          inDate     = true;
                PeriodBuilder builder    = new PeriodBuilder();
                PeriodUnits   unitsSoFar = 0;

                while (valueCursor.MoveNext())
                {
                    if (inDate && valueCursor.Current == 'T')
                    {
                        inDate = false;
                        continue;
                    }
                    var failure = valueCursor.ParseInt64 <Period>(out long unitValue);
                    if (failure != null)
                    {
                        return(failure);
                    }
                    if (valueCursor.Length == valueCursor.Index)
                    {
                        return(ParseResult <Period> .EndOfString(valueCursor));
                    }
                    // Various failure cases:
                    // - Repeated unit (e.g. P1M2M)
                    // - Time unit is in date part (e.g. P5M)
                    // - Date unit is in time part (e.g. PT1D)
                    // - Unit is in incorrect order (e.g. P5D1Y)
                    // - Unit is invalid (e.g. P5J)
                    // - Unit is missing (e.g. P5)
                    PeriodUnits unit;
                    switch (valueCursor.Current)
                    {
                    case 'Y': unit = PeriodUnits.Years; break;

                    case 'M': unit = inDate ? PeriodUnits.Months : PeriodUnits.Minutes; break;

                    case 'W': unit = PeriodUnits.Weeks; break;

                    case 'D': unit = PeriodUnits.Days; break;

                    case 'H': unit = PeriodUnits.Hours; break;

                    case 'S': unit = PeriodUnits.Seconds; break;

                    case 's': unit = PeriodUnits.Milliseconds; break;

                    case 't': unit = PeriodUnits.Ticks; break;

                    case 'n': unit = PeriodUnits.Nanoseconds; break;

                    default: return(InvalidUnit(valueCursor, valueCursor.Current));
                    }
                    if ((unit & unitsSoFar) != 0)
                    {
                        return(RepeatedUnit(valueCursor, valueCursor.Current));
                    }

                    // This handles putting months before years, for example. Less significant units
                    // have higher integer representations.
                    if (unit < unitsSoFar)
                    {
                        return(MisplacedUnit(valueCursor, valueCursor.Current));
                    }
                    // The result of checking "there aren't any time units in this unit" should be
                    // equal to "we're still in the date part".
                    if ((unit & PeriodUnits.AllTimeUnits) == 0 != inDate)
                    {
                        return(MisplacedUnit(valueCursor, valueCursor.Current));
                    }
                    builder[unit] = unitValue;
                    unitsSoFar   |= unit;
                }
                return(ParseResult <Period> .ForValue(builder.Build()));
            }
コード例 #2
0
ファイル: PeriodPattern.cs プロジェクト: wase932/nodatime
            // TODO(misc): Tidy this up a *lot*.
            public ParseResult <Period> Parse(string text)
            {
                if (text is null)
                {
                    return(ParseResult <Period> .ArgumentNull("text"));
                }
                if (text.Length == 0)
                {
                    return(ParseResult <Period> .ValueStringEmpty);
                }

                ValueCursor valueCursor = new ValueCursor(text);

                valueCursor.MoveNext();
                if (valueCursor.Current != 'P')
                {
                    return(ParseResult <Period> .MismatchedCharacter(valueCursor, 'P'));
                }
                bool          inDate     = true;
                PeriodBuilder builder    = new PeriodBuilder();
                PeriodUnits   unitsSoFar = 0;

                while (valueCursor.MoveNext())
                {
                    if (inDate && valueCursor.Current == 'T')
                    {
                        inDate = false;
                        continue;
                    }
                    bool negative = valueCursor.Current == '-';
                    var  failure  = valueCursor.ParseInt64 <Period>(out long unitValue);
                    if (failure != null)
                    {
                        return(failure);
                    }
                    if (valueCursor.Length == valueCursor.Index)
                    {
                        return(ParseResult <Period> .EndOfString(valueCursor));
                    }
                    // Various failure cases:
                    // - Repeated unit (e.g. P1M2M)
                    // - Time unit is in date part (e.g. P5M)
                    // - Date unit is in time part (e.g. PT1D)
                    // - Unit is in incorrect order (e.g. P5D1Y)
                    // - Unit is invalid (e.g. P5J)
                    // - Unit is missing (e.g. P5)
                    PeriodUnits unit;
                    switch (valueCursor.Current)
                    {
                    case 'Y': unit = PeriodUnits.Years; break;

                    case 'M': unit = inDate ? PeriodUnits.Months : PeriodUnits.Minutes; break;

                    case 'W': unit = PeriodUnits.Weeks; break;

                    case 'D': unit = PeriodUnits.Days; break;

                    case 'H': unit = PeriodUnits.Hours; break;

                    case 'S': unit = PeriodUnits.Seconds; break;

                    case ',':
                    case '.': unit = PeriodUnits.Nanoseconds; break;     // Special handling below

                    default: return(InvalidUnit(valueCursor, valueCursor.Current));
                    }
                    if ((unit & unitsSoFar) != 0)
                    {
                        return(RepeatedUnit(valueCursor, valueCursor.Current));
                    }

                    // This handles putting months before years, for example. Less significant units
                    // have higher integer representations.
                    if (unit < unitsSoFar)
                    {
                        return(MisplacedUnit(valueCursor, valueCursor.Current));
                    }

                    // The result of checking "there aren't any time units in this unit" should be
                    // equal to "we're still in the date part".
                    if ((unit & PeriodUnits.AllTimeUnits) == 0 != inDate)
                    {
                        return(MisplacedUnit(valueCursor, valueCursor.Current));
                    }

                    // Seen a . or , which need special handling.
                    if (unit == PeriodUnits.Nanoseconds)
                    {
                        // Check for already having seen seconds, e.g. PT5S0.5
                        if ((unitsSoFar & PeriodUnits.Seconds) != 0)
                        {
                            return(MisplacedUnit(valueCursor, valueCursor.Current));
                        }
                        builder.Seconds = unitValue;

                        if (!valueCursor.MoveNext())
                        {
                            return(ParseResult <Period> .MissingNumber(valueCursor));
                        }
                        // Can cope with at most 999999999 nanoseconds
                        if (!valueCursor.ParseFraction(9, 9, out int totalNanoseconds, 1))
                        {
                            return(ParseResult <Period> .MissingNumber(valueCursor));
                        }
                        // Use whether or not the seconds value was negative (even if 0)
                        // as the indication of whether this value is negative.
                        if (negative)
                        {
                            totalNanoseconds = -totalNanoseconds;
                        }
                        builder.Milliseconds = (totalNanoseconds / NanosecondsPerMillisecond) % MillisecondsPerSecond;
                        builder.Ticks        = (totalNanoseconds / NanosecondsPerTick) % TicksPerMillisecond;
                        builder.Nanoseconds  = totalNanoseconds % NanosecondsPerTick;

                        if (valueCursor.Current != 'S')
                        {
                            return(ParseResult <Period> .MismatchedCharacter(valueCursor, 'S'));
                        }
                        if (valueCursor.MoveNext())
                        {
                            return(ParseResult <Period> .ExpectedEndOfString(valueCursor));
                        }
                        return(ParseResult <Period> .ForValue(builder.Build()));
                    }

                    builder[unit] = unitValue;
                    unitsSoFar   |= unit;
                }
                if (unitsSoFar == 0)
                {
                    return(ParseResult <Period> .ForInvalidValue(valueCursor, TextErrorMessages.EmptyPeriod));
                }
                return(ParseResult <Period> .ForValue(builder.Build()));
            }
コード例 #3
0
ファイル: ValueCursor.cs プロジェクト: ferkopar/FerkopaUtils
        /// <summary>
        /// Parses digits at the current point in the string as a signed 64-bit integer value.
        /// Currently this method only supports cultures whose negative sign is "-" (and
        /// using ASCII digits).
        /// </summary>
        /// <param name="result">The result integer value. The value of this is not guaranteed
        /// to be anything specific if the return value is non-null.</param>
        /// <returns>null if the digits were parsed, or the appropriate parse failure</returns>
        internal ParseResult <T> ParseInt64 <T>(out long result)
        {
            unchecked
            {
                result = 0L;
                int  startIndex = Index;
                bool negative   = Current == '-';
                if (negative)
                {
                    if (!MoveNext())
                    {
                        Move(startIndex);
                        return(ParseResult <T> .EndOfString(this));
                    }
                }
                int count = 0;
                int digit;
                while (result < 922337203685477580 && (digit = GetDigit()) != -1)
                {
                    result = result * 10 + digit;
                    count++;
                    if (!MoveNext())
                    {
                        break;
                    }
                }

                if (count == 0)
                {
                    Move(startIndex);
                    return(ParseResult <T> .MissingNumber(this));
                }

                if (result >= 922337203685477580 && (digit = GetDigit()) != -1)
                {
                    if (result > 922337203685477580)
                    {
                        return(BuildNumberOutOfRangeResult <T>(startIndex));
                    }
                    if (negative && digit == 8)
                    {
                        MoveNext();
                        result = long.MinValue;
                        return(null);
                    }
                    if (digit > 7)
                    {
                        return(BuildNumberOutOfRangeResult <T>(startIndex));
                    }
                    // We know we can cope with this digit...
                    result = result * 10 + digit;
                    MoveNext();
                    if (GetDigit() != -1)
                    {
                        // Too many digits. Die.
                        return(BuildNumberOutOfRangeResult <T>(startIndex));
                    }
                }
                if (negative)
                {
                    result = -result;
                }
                return(null);
            }
        }