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()); }
// 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)); }
// 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)); }
// 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)); }
// 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))); }
// 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))); }
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); }
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); }
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)); }
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); }
// 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))); }
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); }
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); }
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); }
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); }