I use Noda Time, and have the following code:
var pattern = ZonedDateTimePattern.CreateWithInvariantCulture(
"yyyy-MM-dd HH:mm:ss z",
DateTimeZoneProviders.Tzdb);
var parsed = pattern.Parse("2017-11-05 01:00:00 America/Los_Angeles");
Console.WriteLine(parsed.Value);
This results in an UnparsableValueException
with the message:
The local date/time is ambiguous in the target time zone
The problem, as I understand it, is that this specific time can occur twice because of daylight saving. At 02:00, the clock is turned back one hour to 01:00. NodaTime doesn't know which "version" of 01:00 that the string refers to, and because of that the exception is thrown.
To me, it doesn't really matter which version of the time that the parse results in, I just want to avoid the exception, and get a date that is as close to reality as possible. One hour less or more is OK. What would be the best way to do that?
The only way I can think of is splitting the string and parsing the parts individually, and then add one hour, but that feels completely wrong. Is there a better solution?
The ZonedDateTimePattern
class has a Resolver
property. The resolver's role is to perform the mapping to zoned date/times and handle skipped and ambiguous times - times which cannot be mapped as they will occur never (skipped) or more than once (ambiguous) due to DST.
The ZonedDateTimePattern source code shows that the default resolver is Resolvers.StrictResolver
. As you have already discovered, this resolver throws an exception if the mapping is ambiguous or skipped.
A variety of resolvers are available. The best match for your "just give me a valid date and time please!" requirement is likely to be the LenientResolver
which behaves as follows:
Ambiguity is handled by returning the earlier occurrence, and skipped times are shifted forward by the duration of the gap.
We can specify this resolver by appending a call to WithResolver()
on our ZonedDateTimePattern
instance (the Resolver
property does not have a public setter):
var pattern = ZonedDateTimePattern.CreateWithInvariantCulture(
"yyyy-MM-dd HH:mm:ss z",
DateTimeZoneProviders.Tzdb).WithResolver(Resolvers.LenientResolver);
var parsed = pattern.Parse("2017-11-05 01:00:00 America/Los_Angeles");
Console.WriteLine(parsed.Value);
Output:
2017-11-05T01:00:00 America/Los_Angeles (-07)
Per https://github.com/nodatime/nodatime/blob/2.2.x/src/NodaTime.Web/Markdown/2.0.x/zoneddatetime-patterns.md (or wherever that is generated to)
If the pattern does not contain an offset specifier ("o<...>") the local date and time represented by the text is interpreted according to the ZoneLocalMappingResolver associated with the pattern. A new pattern can be created from an existing one, just with a different resolver, using the WithResolver method. If the resolver throws a SkippedTimeException or AmbiguousTimeException, these are converted into UnparsableValueException results. Note that a pattern without an offset specifier will always lead to potential data loss when used with time zones which aren't a single fixed offset, due to the normal issues of time zone transitions (typically for daylight saving time).
suggesting
var lenientpattern = ZonedDateTimePattern
.CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss z", DateTimeZoneProviders.Tzdb)
.WithResolver(Resolvers.LenientResolver); //or any of the other resolvers
var parsed = lenientpattern.Parse("2017-11-05 01:00:00 America/Los_Angeles");
Console.WriteLine(parsed.Value);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With