Nodatime Parsing Instant with InstantPattern fails

I use NodaTime, Version=2.2.3.0 I have set up a patter to match various Instant patterns The last pattern should match the examples below.

IPattern<Instant> pattern = new CompositePatternBuilder<Instant>
{
    { InstantPattern.CreateWithInvariantCulture("yyyy'-'MM'-'dd HH':'mm':'ss.FFFFFFF") , _ => true },
    { InstantPattern.CreateWithInvariantCulture("MM'/'dd'/'yyyy HH':'mm':'ss.FFFFFFF") , _ => false },
    { InstantPattern.CreateWithInvariantCulture("dd'-'MM'-'yyyy HH':'mm':'ss.FFFFFFF") , _ => false },
    { InstantPattern.CreateWithInvariantCulture("dd'/'MM'/'yyyy HH':'mm':'ss.FFFFFFF") , _ => false },
    { InstantPattern.CreateWithInvariantCulture("M'/'dd'/'yyyy HH':'mm':'ss.FFFFFFF") , _ => false },
    { InstantPattern.CreateWithInvariantCulture("MM'/'dd'/'yyyy HH':'mm':'ss.FFFFFFF") , _ => false },
    { InstantPattern.CreateWithInvariantCulture("M.d.yyyy HH':'mm':'ss.FFFFFFF") , _ => false },
    { InstantPattern.CreateWithInvariantCulture("dd.MM.yyyy HH':'mm':'ss.FFFFFFF") , _ => false },
    { InstantPattern.CreateWithInvariantCulture("M'/'d'/'yyyy H':'mm':'ss tt") , _ => false },
    { InstantPattern.CreateWithInvariantCulture("M'/'d'/'yyyy HH':'mm':'ss tt") , _ => false },
}
.Build();

I can parse the two first of

  1. "9/28/2017 10:55:49 AM"
  2. "9/22/2017 12:02:53 PM"
  3. "1/11/2018 12:25:59 AM"

But not the 3rd one. Why ?

error message indicates "^1/11/2018 12:25:59 AM" error at the first position of the string.

Jon Skeet
people
quotationmark

Firstly, I don't think you actually need that many patterns - I suspect you don't need both M and MM versions, for example.

But the problem is that you're using HH with tt. HH means "24-hour clock", so a value of 12 means 12pm... but then your value specifies that it's AM.

If you look at the exception message, it tries to make that clear:

Unhandled Exception: NodaTime.Text.UnparsableValueException: The individual values for the fields 'H' and 't' created an inconsistency in the NodaTime.LocalTime type. Value being parsed: '1/11/2018 12:25:59 AM'.

Basically, you should use h instead:

var pattern = InstantPattern.CreateWithInvariantCulture("M/d/yyyy h:mm:ss tt");

(Note that you don't need to escape / and : - while they are culture-sensitive, you're using the invariant culture which uses values of / and : anyway, so it's simpler just to leave them unescaped. - has no special meaning in an InstantPattern, so that doesn't need escaping either.)

The reason your first two values don't fail is that in those cases the 24-hour hour-of-day that's specified matches the AM/PM designation. "10" is in AM, and "12" is in PM.

people

See more on this question at Stackoverflow