private static void HandleZoneAbbreviation(PatternCursor pattern,
                                            SteppedPatternBuilder <ZonedDateTime, ZonedDateTimeParseBucket> builder)
 {
     builder.AddField(PatternFields.ZoneAbbreviation, pattern.Current);
     builder.SetFormatOnly();
     builder.AddFormatAction((value, sb) => sb.Append(value.GetZoneInterval().Name));
 }
 private static void HandleZone(PatternCursor pattern,
                                SteppedPatternBuilder <ZonedDateTime, ZonedDateTimeParseBucket> builder)
 {
     builder.AddField(PatternFields.Zone, pattern.Current);
     builder.AddParseAction(ParseZone);
     builder.AddFormatAction((value, sb) => sb.Append(value.Zone.Id));
 }
        // Note: public to implement the interface. It does no harm, and it's simpler than using explicit
        // interface implementation.
        public IPattern <LocalDate> ParsePattern(string patternText, NodaFormatInfo formatInfo)
        {
            // Nullity check is performed in LocalDatePattern.
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(Messages.Parse_FormatStringEmpty);
            }

            if (patternText.Length == 1)
            {
                char patternCharacter = patternText[0];
                patternText = ExpandStandardFormatPattern(patternCharacter, formatInfo);
                if (patternText == null)
                {
                    throw new InvalidPatternException(Messages.Parse_UnknownStandardFormat, patternCharacter, typeof(LocalDate));
                }
            }

            var patternBuilder = new SteppedPatternBuilder <LocalDate, LocalDateParseBucket>(formatInfo,
                                                                                             () => new LocalDateParseBucket(templateValue));

            patternBuilder.ParseCustomPattern(patternText, PatternCharacterHandlers);
            patternBuilder.ValidateUsedFields();
            return(patternBuilder.Build());
        }
Пример #4
0
        // Note: public to implement the interface. It does no harm, and it's simpler than using explicit
        // interface implementation.
        public IPattern <AnnualDate> ParsePattern(string patternText, NodaFormatInfo formatInfo)
        {
            // Nullity check is performed in AnnualDatePattern.
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(TextErrorMessages.FormatStringEmpty);
            }

            if (patternText.Length == 1)
            {
                switch (patternText[0])
                {
                case 'G':
                    return(AnnualDatePattern.Iso);

                default:
                    throw new InvalidPatternException(TextErrorMessages.UnknownStandardFormat, patternText, typeof(AnnualDate));
                }
            }

            var patternBuilder = new SteppedPatternBuilder <AnnualDate, AnnualDateParseBucket>(formatInfo,
                                                                                               () => new AnnualDateParseBucket(templateValue));

            patternBuilder.ParseCustomPattern(patternText, PatternCharacterHandlers);
            patternBuilder.ValidateUsedFields();
            return(patternBuilder.Build(templateValue));
        }
Пример #5
0
        // Note: public to implement the interface. It does no harm, and it's simpler than using explicit
        // interface implementation.
        public IPattern <LocalTime> ParsePattern(string patternText, NodaFormatInfo formatInfo)
        {
            // Nullity check is performed in LocalTimePattern.
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(TextErrorMessages.FormatStringEmpty);
            }

            if (patternText.Length == 1)
            {
                patternText = patternText[0] switch
                {
                    't' => formatInfo.DateTimeFormat.ShortTimePattern,
                    'T' => formatInfo.DateTimeFormat.LongTimePattern,
                    'r' => "HH:mm:ss.FFFFFFFFF",
                    _ => throw new InvalidPatternException(TextErrorMessages.UnknownStandardFormat, patternText, typeof(LocalTime))
                };
            }

            var patternBuilder = new SteppedPatternBuilder <LocalTime, LocalTimeParseBucket>(formatInfo,
                                                                                             () => new LocalTimeParseBucket(templateValue));

            patternBuilder.ParseCustomPattern(patternText, PatternCharacterHandlers);
            patternBuilder.ValidateUsedFields();
            return(patternBuilder.Build(templateValue));
        }
Пример #6
0
        // Note: public to implement the interface. It does no harm, and it's simpler than using explicit
        // interface implementation.
        public IPattern <Duration> ParsePattern(string patternText, NodaFormatInfo formatInfo)
        {
            Preconditions.CheckNotNull(patternText, "patternText");
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(Messages.Parse_FormatStringEmpty);
            }

            // The sole standard pattern...
            if (patternText.Length == 1)
            {
                switch (patternText[0])
                {
                case 'o':
                    return(DurationPattern.Patterns.RoundtripPatternImpl);

                default:
                    throw new InvalidPatternException(Messages.Parse_UnknownStandardFormat, patternText[0], typeof(Duration));
                }
            }

            var patternBuilder = new SteppedPatternBuilder <Duration, DurationParseBucket>(formatInfo,
                                                                                           () => new DurationParseBucket());

            patternBuilder.ParseCustomPattern(patternText, PatternCharacterHandlers);
            return(patternBuilder.Build());
        }
        // Note: public to implement the interface. It does no harm, and it's simpler than using explicit
        // interface implementation.
        public IPattern <OffsetDateTime> ParsePattern(string patternText, NodaFormatInfo formatInfo)
        {
            // Nullity check is performed in OffsetDateTimePattern.
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(Messages.Parse_FormatStringEmpty);
            }

            // Handle standard patterns
            if (patternText.Length == 1)
            {
                switch (patternText[0])
                {
                case 'G':
                    return(OffsetDateTimePattern.Patterns.GeneralIsoPatternImpl);

                case 'o':
                    return(OffsetDateTimePattern.Patterns.ExtendedIsoPatternImpl);

                case 'r':
                    return(OffsetDateTimePattern.Patterns.FullRoundtripPatternImpl);

                default:
                    throw new InvalidPatternException(Messages.Parse_UnknownStandardFormat, patternText[0], typeof(OffsetDateTime));
                }
            }

            var patternBuilder = new SteppedPatternBuilder <OffsetDateTime, OffsetDateTimeParseBucket>(formatInfo, () => new OffsetDateTimeParseBucket(templateValue));

            patternBuilder.ParseCustomPattern(patternText, PatternCharacterHandlers);
            patternBuilder.ValidateUsedFields();
            // Need to reconstruct the template value from the bits...
            return(patternBuilder.Build(templateValue));
        }
Пример #8
0
        // Note: public to implement the interface. It does no harm, and it's simpler than using explicit
        // interface implementation.
        public IPattern <Duration> ParsePattern([NotNull] string patternText, NodaFormatInfo formatInfo)
        {
            Preconditions.CheckNotNull(patternText, nameof(patternText));
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(TextErrorMessages.FormatStringEmpty);
            }

            // The sole standard pattern...
            if (patternText.Length == 1)
            {
                switch (patternText[0])
                {
                case 'o':
                    return(DurationPattern.Patterns.RoundtripPatternImpl);

                default:
                    throw new InvalidPatternException(TextErrorMessages.UnknownStandardFormat, patternText[0], typeof(Duration));
                }
            }

            var patternBuilder = new SteppedPatternBuilder <Duration, DurationParseBucket>(formatInfo,
                                                                                           () => new DurationParseBucket());

            patternBuilder.ParseCustomPattern(patternText, PatternCharacterHandlers);
            // Somewhat random sample, admittedly...
            return(patternBuilder.Build(Duration.FromHours(1) + Duration.FromMinutes(30) + Duration.FromSeconds(5) + Duration.FromMilliseconds(500)));
        }
Пример #9
0
        // Note: public to implement the interface. It does no harm, and it's simpler than using explicit
        // interface implementation.
        public IPattern <ZonedDateTime> ParsePattern(string patternText, NodaFormatInfo formatInfo)
        {
            // Nullity check is performed in ZonedDateTimePattern.
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(Messages.Parse_FormatStringEmpty);
            }

            // Handle standard patterns
            if (patternText.Length == 1)
            {
                switch (patternText[0])
                {
                case 'G':
                    return(ZonedDateTimePattern.Patterns.GeneralFormatOnlyPatternImpl);

                case 'F':
                    return(ZonedDateTimePattern.Patterns.ExtendedFormatOnlyPatternImpl);

                default:
                    throw new InvalidPatternException(Messages.Parse_UnknownStandardFormat, patternText[0], typeof(ZonedDateTime));
                }
            }

            var patternBuilder = new SteppedPatternBuilder <ZonedDateTime, ZonedDateTimeParseBucket>(formatInfo,
                                                                                                     () => new ZonedDateTimeParseBucket(templateValueDate, templateValueTime, templateValueZone, resolver, zoneProvider));

            if (zoneProvider == null)
            {
                patternBuilder.SetFormatOnly();
            }
            patternBuilder.ParseCustomPattern(patternText, PatternCharacterHandlers);
            patternBuilder.ValidateUsedFields();
            return(patternBuilder.Build());
        }
        private static void HandleOffset(PatternCursor pattern,
                                         SteppedPatternBuilder <OffsetDateTime, OffsetDateTimeParseBucket> builder)
        {
            builder.AddField(PatternFields.EmbeddedOffset, pattern.Current);
            string embeddedPattern = pattern.GetEmbeddedPattern();
            var    offsetPattern   = OffsetPattern.Create(embeddedPattern, builder.FormatInfo).UnderlyingPattern;

            builder.AddEmbeddedPattern(offsetPattern, (bucket, offset) => bucket.Offset = offset, zdt => zdt.Offset);
        }
        // Note: public to implement the interface. It does no harm, and it's simpler than using explicit
        // interface implementation.
        public IPattern <LocalDateTime> ParsePattern(string patternText, NodaFormatInfo formatInfo)
        {
            // Nullity check is performed in LocalDateTimePattern.
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(TextErrorMessages.FormatStringEmpty);
            }

            if (patternText.Length == 1)
            {
                switch (patternText[0])
                {
                // Invariant standard patterns return cached implementations.
                case 'o':
                case 'O':
                    return(LocalDateTimePattern.Patterns.BclRoundtripPatternImpl);

                case 'r':
                    return(LocalDateTimePattern.Patterns.FullRoundtripPatternImpl);

                case 'R':
                    return(LocalDateTimePattern.Patterns.FullRoundtripWithoutCalendarImpl);

                case 's':
                    return(LocalDateTimePattern.Patterns.GeneralIsoPatternImpl);

                // Other standard patterns expand the pattern text to the appropriate custom pattern.
                case 'f':
                    patternText = formatInfo.DateTimeFormat.LongDatePattern + " " + formatInfo.DateTimeFormat.ShortTimePattern;
                    break;

                case 'F':
                    patternText = formatInfo.DateTimeFormat.FullDateTimePattern;
                    break;

                case 'g':
                    patternText = formatInfo.DateTimeFormat.ShortDatePattern + " " + formatInfo.DateTimeFormat.ShortTimePattern;
                    break;

                case 'G':
                    patternText = formatInfo.DateTimeFormat.ShortDatePattern + " " + formatInfo.DateTimeFormat.LongTimePattern;
                    break;

                // Unknown standard patterns fail.
                default:
                    throw new InvalidPatternException(TextErrorMessages.UnknownStandardFormat, patternText, typeof(LocalDateTime));
                }
            }

            var patternBuilder = new SteppedPatternBuilder <LocalDateTime, LocalDateTimeParseBucket>(formatInfo,
                                                                                                     () => new LocalDateTimeParseBucket(templateValueDate, templateValueTime));

            patternBuilder.ParseCustomPattern(patternText, PatternCharacterHandlers);
            patternBuilder.ValidateUsedFields();
            return(patternBuilder.Build(templateValueDate.At(templateValueTime)));
        }
Пример #12
0
        private IPartialPattern <Offset> ParsePartialPattern(string patternText, NodaFormatInfo formatInfo)
        {
            // Nullity check is performed in OffsetPattern.
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(Messages.Parse_FormatStringEmpty);
            }

            if (patternText.Length == 1)
            {
                switch (patternText)
                {
                case "g":
                    return(CreateGeneralPattern(formatInfo));

                case "G":
                    return(new ZPrefixPattern(CreateGeneralPattern(formatInfo)));

                case "l":
                    patternText = formatInfo.OffsetPatternLong;
                    break;

                case "m":
                    patternText = formatInfo.OffsetPatternMedium;
                    break;

                case "s":
                    patternText = formatInfo.OffsetPatternShort;
                    break;

                default:
                    throw new InvalidPatternException(Messages.Parse_UnknownStandardFormat, patternText, typeof(Offset));
                }
            }
            // This is the only way we'd normally end up in custom parsing land for Z on its own.
            if (patternText == "%Z")
            {
                throw new InvalidPatternException(Messages.Parse_EmptyZPrefixedOffsetPattern);
            }

            // Handle Z-prefix by stripping it, parsing the rest as a normal pattern, then building a special pattern
            // which decides whether or not to delegate.
            bool zPrefix = patternText.StartsWith("Z");

            var patternBuilder = new SteppedPatternBuilder <Offset, OffsetParseBucket>(formatInfo, () => new OffsetParseBucket());

            patternBuilder.ParseCustomPattern(zPrefix ? patternText.Substring(1) : patternText, PatternCharacterHandlers);
            // No need to validate field combinations here, but we do need to do something a bit special
            // for Z-handling.
            IPartialPattern <Offset> pattern = patternBuilder.Build(Offset.FromHoursAndMinutes(5, 30));

            return(zPrefix ? new ZPrefixPattern(pattern) : pattern);
        }
Пример #13
0
        private IPartialPattern <Offset> ParsePartialPattern(string patternText, NodaFormatInfo formatInfo)
        {
            // Nullity check is performed in OffsetPattern.
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(Messages.Parse_FormatStringEmpty);
            }

            if (patternText.Length == 1)
            {
                char patternCharacter = patternText[0];
                if (patternCharacter == 'n')
                {
                    return(new NumberPattern(formatInfo));
                }
                if (patternCharacter == 'g')
                {
                    return(CreateGeneralPattern(formatInfo));
                }
                if (patternCharacter == 'G')
                {
                    return(new ZPrefixPattern(CreateGeneralPattern(formatInfo)));
                }
                patternText = ExpandStandardFormatPattern(patternCharacter, formatInfo);
                if (patternText == null)
                {
                    throw new InvalidPatternException(Messages.Parse_UnknownStandardFormat, patternCharacter, typeof(Offset));
                }
            }
            // This is the only way we'd normally end up in custom parsing land for Z on its own.
            if (patternText == "%Z")
            {
                throw new InvalidPatternException(Messages.Parse_EmptyZPrefixedOffsetPattern);
            }

            // Handle Z-prefix by stripping it, parsing the rest as a normal pattern, then building a special pattern
            // which decides whether or not to delegate.
            bool zPrefix = patternText.StartsWith("Z");

            var patternBuilder = new SteppedPatternBuilder <Offset, OffsetParseBucket>(formatInfo, () => new OffsetParseBucket());

            patternBuilder.ParseCustomPattern(zPrefix ? patternText.Substring(1) : patternText, PatternCharacterHandlers);
            // No need to validate field combinations here, but we do need to do something a bit special
            // for Z-handling.
            IPartialPattern <Offset> pattern = patternBuilder.Build();

            return(zPrefix ? new ZPrefixPattern(pattern) : pattern);
        }
Пример #14
0
        public void FormatOnly_ParsingFails()
        {
            var builder = new SteppedPatternBuilder <LocalDate, SampleBucket>(
                NodaFormatInfo.InvariantInfo, () => new SampleBucket());

            builder.AddFormatAction((date, sb) => sb.Append("Formatted"));
            builder.SetFormatOnly();
            var pattern = builder.Build(LocalDate.MinIsoValue);

            var value  = new ValueCursor("xyz");
            var result = pattern.ParsePartial(value);

            Assert.AreEqual(ParseResult <LocalDate> .FormatOnlyPattern, result);
            result = pattern.Parse("xyz");
            Assert.AreEqual(ParseResult <LocalDate> .FormatOnlyPattern, result);
        }
        [TestCase("aBaB>", false)] // > is reserved
        public void UnhandledLiteral(string text, bool valid)
        {
            CharacterHandler <LocalDate, SampleBucket> handler = delegate { };
            var handlers = new Dictionary <char, CharacterHandler <LocalDate, SampleBucket> >
            {
                { 'a', handler },
                { 'B', handler }
            };
            var builder = new SteppedPatternBuilder <LocalDate, SampleBucket>(NodaFormatInfo.InvariantInfo, () => new SampleBucket());

            if (valid)
            {
                builder.ParseCustomPattern(text, handlers);
            }
            else
            {
                Assert.Throws <InvalidPatternException>(() => builder.ParseCustomPattern(text, handlers));
            }
        }
        private static void HandleOffset(PatternCursor pattern,
                                         SteppedPatternBuilder <OffsetDateTime, OffsetDateTimeParseBucket> builder)
        {
            builder.AddField(PatternFields.EmbeddedOffset, pattern.Current);
            string embeddedPattern = pattern.GetEmbeddedPattern('<', '>');
            var    offsetPattern   = OffsetPattern.Create(embeddedPattern, builder.FormatInfo).UnderlyingPattern;

            builder.AddParseAction((value, bucket) =>
            {
                var result = offsetPattern.ParsePartial(value);
                if (!result.Success)
                {
                    return(result.ConvertError <OffsetDateTime>());
                }
                bucket.Offset = result.Value;
                return(null);
            });
            builder.AddFormatAction((value, sb) => offsetPattern.AppendFormat(value.Offset, sb));
        }
Пример #17
0
        private static void HandleDayOfMonth(PatternCursor pattern, SteppedPatternBuilder <AnnualDate, AnnualDateParseBucket> builder)
        {
            int           count = pattern.GetRepeatCount(2);
            PatternFields field;

            switch (count)
            {
            case 1:
            case 2:
                field = PatternFields.DayOfMonth;
                // Handle real maximum value in the bucket
                builder.AddParseValueAction(count, 2, pattern.Current, 1, 99, (bucket, value) => bucket.DayOfMonth = value);
                builder.AddFormatLeftPad(count, value => value.Day, assumeNonNegative: true, assumeFitsInCount: count == 2);
                break;

            default:
                throw new InvalidOperationException("Invalid count!");
            }
            builder.AddField(field, pattern.Current);
        }
Пример #18
0
        // Note: public to implement the interface. It does no harm, and it's simpler than using explicit
        // interface implementation.
        public IPattern <LocalDateTime> ParsePattern(string patternText, NodaFormatInfo formatInfo)
        {
            // Nullity check is performed in LocalDateTimePattern.
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(TextErrorMessages.FormatStringEmpty);
            }

            if (patternText.Length == 1)
            {
                char patternCharacter = patternText[0];
                if (patternCharacter == 'o' || patternCharacter == 'O')
                {
                    return(LocalDateTimePattern.Patterns.BclRoundtripPatternImpl);
                }
                if (patternCharacter == 'r')
                {
                    return(LocalDateTimePattern.Patterns.FullRoundtripPatternImpl);
                }
                if (patternCharacter == 'R')
                {
                    return(LocalDateTimePattern.Patterns.FullRoundtripWithoutCalendarImpl);
                }
                if (patternCharacter == 's')
                {
                    return(LocalDateTimePattern.Patterns.GeneralIsoPatternImpl);
                }
                patternText = ExpandStandardFormatPattern(patternCharacter, formatInfo);
                if (patternText is null)
                {
                    throw new InvalidPatternException(TextErrorMessages.UnknownStandardFormat, patternCharacter, typeof(LocalDateTime));
                }
            }

            var patternBuilder = new SteppedPatternBuilder <LocalDateTime, LocalDateTimeParseBucket>(formatInfo,
                                                                                                     () => new LocalDateTimeParseBucket(templateValueDate, templateValueTime));

            patternBuilder.ParseCustomPattern(patternText, PatternCharacterHandlers);
            patternBuilder.ValidateUsedFields();
            return(patternBuilder.Build(templateValueDate.At(templateValueTime)));
        }
Пример #19
0
 private static void HandlePlus(PatternCursor pattern, SteppedPatternBuilder <Duration, DurationParseBucket> builder)
 {
     builder.AddField(PatternFields.Sign, pattern.Current);
     builder.AddRequiredSign((bucket, positive) => bucket.IsNegative = !positive, duration => duration.Ticks >= 0);
 }
Пример #20
0
 private static void HandleMinus(PatternCursor pattern, SteppedPatternBuilder <Duration, DurationParseBucket> builder)
 {
     builder.AddField(PatternFields.Sign, pattern.Current);
     builder.AddNegativeOnlySign((bucket, positive) => bucket.IsNegative = !positive, duration => duration.FloorDays >= 0);
 }
Пример #21
0
        private IPartialPattern <Offset> ParsePartialPattern(string patternText, NodaFormatInfo formatInfo)
        {
            // Nullity check is performed in OffsetPattern.
            if (patternText.Length == 0)
            {
                throw new InvalidPatternException(TextErrorMessages.FormatStringEmpty);
            }

            if (patternText.Length == 1)
            {
                switch (patternText[0])
                {
                case 'g':
                    return(new CompositePatternBuilder <Offset>
                    {
                        { ParsePartialPattern(formatInfo.OffsetPatternLong, formatInfo), offset => true },
                        { ParsePartialPattern(formatInfo.OffsetPatternMedium, formatInfo), HasZeroSeconds },
                        { ParsePartialPattern(formatInfo.OffsetPatternShort, formatInfo), HasZeroSecondsAndMinutes },
                    }.BuildAsPartial());

                case 'G':
                    return(new ZPrefixPattern(ParsePartialPattern("g", formatInfo)));

                case 'i':
                    return(new CompositePatternBuilder <Offset>
                    {
                        { ParsePartialPattern(formatInfo.OffsetPatternLongNoPunctuation, formatInfo), offset => true },
                        { ParsePartialPattern(formatInfo.OffsetPatternMediumNoPunctuation, formatInfo), HasZeroSeconds },
                        { ParsePartialPattern(formatInfo.OffsetPatternShortNoPunctuation, formatInfo), HasZeroSecondsAndMinutes },
                    }.BuildAsPartial());

                case 'I':
                    return(new ZPrefixPattern(ParsePartialPattern("i", formatInfo)));

                case 'l':
                    patternText = formatInfo.OffsetPatternLong;
                    break;

                case 'm':
                    patternText = formatInfo.OffsetPatternMedium;
                    break;

                case 's':
                    patternText = formatInfo.OffsetPatternShort;
                    break;

                case 'L':
                    patternText = formatInfo.OffsetPatternLongNoPunctuation;
                    break;

                case 'M':
                    patternText = formatInfo.OffsetPatternMediumNoPunctuation;
                    break;

                case 'S':
                    patternText = formatInfo.OffsetPatternShortNoPunctuation;
                    break;

                default:
                    throw new InvalidPatternException(TextErrorMessages.UnknownStandardFormat, patternText, typeof(Offset));
                }
            }
            // This is the only way we'd normally end up in custom parsing land for Z on its own.
            if (patternText == "%Z")
            {
                throw new InvalidPatternException(TextErrorMessages.EmptyZPrefixedOffsetPattern);
            }

            // Handle Z-prefix by stripping it, parsing the rest as a normal pattern, then building a special pattern
            // which decides whether or not to delegate.
            bool zPrefix = patternText.StartsWith("Z");

            var patternBuilder = new SteppedPatternBuilder <Offset, OffsetParseBucket>(formatInfo, () => new OffsetParseBucket());

            patternBuilder.ParseCustomPattern(zPrefix ? patternText.Substring(1) : patternText, PatternCharacterHandlers);
            // No need to validate field combinations here, but we do need to do something a bit special
            // for Z-handling.
            IPartialPattern <Offset> pattern = patternBuilder.Build(Offset.FromHoursAndMinutes(5, 30));

            return(zPrefix ? new ZPrefixPattern(pattern) : pattern);
        }
Пример #22
0
 private static void HandleMinus(PatternCursor pattern, SteppedPatternBuilder <Offset, OffsetParseBucket> builder)
 {
     builder.AddField(PatternFields.Sign, pattern.Current);
     builder.AddNegativeOnlySign((bucket, positive) => bucket.IsNegative = !positive, offset => offset.Milliseconds >= 0);
 }