public void CreateResolver_Skipped()
        {
            ZonedDateTime         zoned               = new ZonedDateTime(TimeInTransition.PlusDays(1).WithOffset(GapZone.EarlyInterval.WallOffset), GapZone);
            AmbiguousTimeResolver ambiguityResolver   = (earlier, later) => { Assert.Fail("Shouldn't be called"); return(default(ZonedDateTime)); };
            SkippedTimeResolver   skippedTimeResolver = (local, zone, before, after) => zoned;
            var resolver = Resolvers.CreateMappingResolver(ambiguityResolver, skippedTimeResolver);

            var resolved = resolver(GapZone.MapLocal(TimeInTransition));

            Assert.AreEqual(zoned, resolved);
        }
        public void CreateResolver_Unambiguous()
        {
            AmbiguousTimeResolver ambiguityResolver   = (earlier, later) => { Assert.Fail("Shouldn't be called"); return(default(ZonedDateTime)); };
            SkippedTimeResolver   skippedTimeResolver = (local, zone, before, after) => { Assert.Fail("Shouldn't be called"); return(default(ZonedDateTime)); };
            var resolver = Resolvers.CreateMappingResolver(ambiguityResolver, skippedTimeResolver);

            LocalDateTime localTime = new LocalDateTime(1900, 1, 1, 0, 0);
            var           resolved  = resolver(GapZone.MapLocal(localTime));

            Assert.AreEqual(new ZonedDateTime(localTime.WithOffset(GapZone.EarlyInterval.WallOffset), GapZone), resolved);
        }
Exemple #3
0
 /// <summary>
 /// Combines an <see cref="AmbiguousTimeResolver"/> and a <see cref="SkippedTimeResolver"/> to create a
 /// <see cref="ZoneLocalMappingResolver"/>.
 /// </summary>
 /// <remarks>
 /// The <c>ZoneLocalMappingResolver</c> created by this method operates in the obvious way: unambiguous mappings
 /// are returned directly, ambiguous mappings are delegated to the given <c>AmbiguousTimeResolver</c>, and
 /// "skipped" mappings are delegated to the given <c>SkippedTimeResolver</c>.
 /// </remarks>
 /// <param name="ambiguousTimeResolver">Resolver to use for ambiguous mappings.</param>
 /// <param name="skippedTimeResolver">Resolver to use for "skipped" mappings.</param>
 /// <returns>The logical combination of the two resolvers.</returns>
 public static ZoneLocalMappingResolver CreateMappingResolver(AmbiguousTimeResolver ambiguousTimeResolver, SkippedTimeResolver skippedTimeResolver)
 {
     Preconditions.CheckNotNull(ambiguousTimeResolver, nameof(ambiguousTimeResolver));
     Preconditions.CheckNotNull(skippedTimeResolver, nameof(skippedTimeResolver));
     return(mapping =>
            Preconditions.CheckNotNull(mapping, nameof(mapping)).Count switch
     {
         0 => skippedTimeResolver(mapping.LocalDateTime, mapping.Zone, mapping.EarlyInterval, mapping.LateInterval),
         1 => mapping.First(),
         2 => ambiguousTimeResolver(mapping.First(), mapping.Last()),
         _ => throw new InvalidOperationException("Mapping has count outside range 0-2; should not happen.")
     });
        internal ZonedDateTime ResolveLocal(LocalDateTime localDateTime,
                                            [Trusted][NotNull] AmbiguousTimeResolver ambiguousResolver,
                                            [Trusted][NotNull] SkippedTimeResolver skippedResolver)
        {
            Preconditions.DebugCheckNotNull(ambiguousResolver, nameof(ambiguousResolver));
            Preconditions.DebugCheckNotNull(skippedResolver, nameof(skippedResolver));
            LocalInstant localInstant = localDateTime.ToLocalInstant();
            Instant      firstGuess   = localInstant.MinusZeroOffset();
            ZoneInterval interval     = GetZoneInterval(firstGuess);

            // Most of the time we'll go into here... the local instant and the instant
            // are close enough that we've found the right instant.
            if (interval.Contains(localInstant))
            {
                ZonedDateTime guessZoned = new ZonedDateTime(localDateTime.WithOffset(interval.WallOffset), this);
                ZoneInterval  earlier    = GetEarlierMatchingInterval(interval, localInstant);
                if (earlier != null)
                {
                    ZonedDateTime earlierZoned = new ZonedDateTime(localDateTime.WithOffset(earlier.WallOffset), this);
                    return(ambiguousResolver(earlierZoned, guessZoned));
                }
                ZoneInterval later = GetLaterMatchingInterval(interval, localInstant);
                if (later != null)
                {
                    ZonedDateTime laterZoned = new ZonedDateTime(localDateTime.WithOffset(later.WallOffset), this);
                    return(ambiguousResolver(guessZoned, laterZoned));
                }
                return(guessZoned);
            }
            else
            {
                // Our first guess was wrong. Either we need to change interval by one (either direction)
                // or we're in a gap.
                ZoneInterval earlier = GetEarlierMatchingInterval(interval, localInstant);
                if (earlier != null)
                {
                    return(new ZonedDateTime(localDateTime.WithOffset(earlier.WallOffset), this));
                }
                ZoneInterval later = GetLaterMatchingInterval(interval, localInstant);
                if (later != null)
                {
                    return(new ZonedDateTime(localDateTime.WithOffset(later.WallOffset), this));
                }
                return(skippedResolver(localDateTime, this, GetIntervalBeforeGap(localInstant), GetIntervalAfterGap(localInstant)));
            }
        }
Exemple #5
0
        /// <summary>
        /// Combines an <see cref="AmbiguousTimeResolver"/> and a <see cref="SkippedTimeResolver"/> to create a
        /// <see cref="ZoneLocalMappingResolver"/>.
        /// </summary>
        /// <remarks>
        /// The <c>ZoneLocalMappingResolver</c> created by this method operates in the obvious way: unambiguous mappings
        /// are returned directly, ambiguous mappings are delegated to the given <c>AmbiguousTimeResolver</c>, and
        /// "skipped" mappings are delegated to the given <c>SkippedTimeResolver</c>.
        /// </remarks>
        /// <param name="ambiguousTimeResolver">Resolver to use for ambiguous mappings.</param>
        /// <param name="skippedTimeResolver">Resolver to use for "skipped" mappings.</param>
        /// <returns>The logical combination of the two resolvers.</returns>
        public static ZoneLocalMappingResolver CreateMappingResolver([NotNull] AmbiguousTimeResolver ambiguousTimeResolver, [NotNull] SkippedTimeResolver skippedTimeResolver)
        {
            Preconditions.CheckNotNull(ambiguousTimeResolver, nameof(ambiguousTimeResolver));
            Preconditions.CheckNotNull(skippedTimeResolver, nameof(skippedTimeResolver));
            return(mapping =>
            {
                Preconditions.CheckNotNull(mapping, nameof(mapping));
                switch (mapping.Count)
                {
                case 0: return skippedTimeResolver(mapping.LocalDateTime, mapping.Zone, mapping.EarlyInterval, mapping.LateInterval);

                case 1: return mapping.First();

                case 2: return ambiguousTimeResolver(mapping.First(), mapping.Last());

                default: throw new InvalidOperationException("Mapping has count outside range 0-2; should not happen.");
                }
            });
        }