Beispiel #1
0
 /// <summary>
 /// Creates an <see cref="IComparer{T}"/> for periods, using the given "base" local date/time.
 /// </summary>
 /// <remarks>
 /// Certain periods can't naturally be compared without more context - how "one month" compares to
 /// "30 days" depends on where you start. In order to compare two periods, the returned comparer
 /// effectively adds both periods to the "base" specified by <paramref name="baseDateTime"/> and compares
 /// the results. In some cases this arithmetic isn't actually required - when two periods can be
 /// converted to durations, the comparer uses that conversion for efficiency.
 /// </remarks>
 /// <param name="baseDateTime">The base local date/time to use for comparisons.</param>
 /// <returns>The new comparer.</returns>
 public static IComparer <Period> CreateComparer(LocalDateTime baseDateTime)
 {
     return(new PeriodComparer(baseDateTime));
 }
Beispiel #2
0
 /// <summary>
 /// Returns the exact difference between two date/times.
 /// </summary>
 /// <remarks>
 /// If <paramref name="end"/> is before <paramref name="start" />, each property in the returned period
 /// will be negative.
 /// </remarks>
 /// <param name="start">Start date/time</param>
 /// <param name="end">End date/time</param>
 /// <returns>The period between the two date and time values, using all units.</returns>
 public static Period Between(LocalDateTime start, LocalDateTime end)
 {
     return(Between(start, end, PeriodUnits.DateAndTime));
 }
 /// <summary>
 /// To LocalDateTime
 /// </summary>
 /// <param name="lt"></param>
 /// <param name="calendar"></param>
 /// <returns></returns>
 public static LocalDateTime ToLocalDateTime(this LocalTime lt, CalendarSystem calendar) =>
 LocalDateTime.FromDateTime(DateTime.Today, calendar).SetTime(lt);
Beispiel #4
0
 /// <summary>
 /// Internal constructor used by other code that has already validated and
 /// computed the appropriate field values. No further validation is performed.
 /// </summary>
 internal ZonedDateTime(LocalDateTime localDateTime, Offset offset, DateTimeZone zone)
 {
     this.localDateTime = localDateTime;
     this.offset        = offset;
     this.zone          = zone;
 }
Beispiel #5
0
 /// <summary>
 /// Constructs a new offset date/time with the given local date and time, and the given offset from UTC.
 /// </summary>
 /// <param name="localDateTime">Local date and time to represent</param>
 /// <param name="offset">Offset from UTC</param>
 public OffsetDateTime(LocalDateTime localDateTime, Offset offset)
     : this(localDateTime.Date.YearMonthDayCalendar, CombineNanoOfDayAndOffset(localDateTime.NanosecondOfDay, offset))
 {
 }
Beispiel #6
0
 /// <summary>
 /// Constructs a new offset date/time with the given local date and time, and the given offset from UTC.
 /// </summary>
 /// <param name="localDateTime">Local date and time to represent</param>
 /// <param name="offset">Offset from UTC</param>
 public OffsetDateTime(LocalDateTime localDateTime, Offset offset)
     : this(localDateTime.Date, new OffsetTime(localDateTime.NanosecondOfDay, offset.Seconds))
 {
 }
Beispiel #7
0
 public static Period Between(LocalDateTime start, LocalDateTime end) => Between(start, end, PeriodUnits.DateAndTime);
Beispiel #8
0
        public OffsetDateTime WithOffset(Offset offset)
        {
            LocalDateTime newLocalDateTime = new LocalDateTime(LocalDateTime.LocalInstant.Minus(this.Offset).Plus(offset), Calendar);

            return(new OffsetDateTime(newLocalDateTime, offset));
        }
Beispiel #9
0
 /// <summary>
 /// Creates an <see cref="IComparer{T}"/> for periods, using the given "base" local date/time.
 /// </summary>
 /// <remarks>
 /// Certain periods can't naturally be compared without more context - how "one month" compares to
 /// "30 days" depends on where you start. In order to compare two periods, the returned comparer
 /// effectively adds both periods to the "base" specified by <paramref name="baseDateTime"/> and compares
 /// the results. In some cases this arithmetic isn't actually required - when two periods can be
 /// converted to durations, the comparer uses that conversion for efficiency.
 /// </remarks>
 /// <param name="baseDateTime">The base local date/time to use for comparisons.</param>
 /// <returns>The new comparer.</returns>
 public static IComparer <Period?> CreateComparer(LocalDateTime baseDateTime) => new PeriodComparer(baseDateTime);
Beispiel #10
0
        /// <summary>
        /// Returns the period between a start and an end date/time, using only the given units.
        /// </summary>
        /// <remarks>
        /// If <paramref name="end"/> is before <paramref name="start" />, each property in the returned period
        /// will be negative. If the given set of units cannot exactly reach the end point (e.g. finding
        /// the difference between 1am and 3:15am in hours) the result will be such that adding it to <paramref name="start"/>
        /// will give a value between <paramref name="start"/> and <paramref name="end"/>. In other words,
        /// any rounding is "towards start"; this is true whether the resulting period is negative or positive.
        /// </remarks>
        /// <param name="start">Start date/time</param>
        /// <param name="end">End date/time</param>
        /// <param name="units">Units to use for calculations</param>
        /// <exception cref="ArgumentException"><paramref name="units"/> is empty or contained unknown values.</exception>
        /// <exception cref="ArgumentException"><paramref name="start"/> and <paramref name="end"/> use different calendars.</exception>
        /// <returns>The period between the given date/times, using the given units.</returns>
        public static Period Between(LocalDateTime start, LocalDateTime end, PeriodUnits units)
        {
            Preconditions.CheckArgument(units != 0, nameof(units), "Units must not be empty");
            Preconditions.CheckArgument((units & ~PeriodUnits.AllUnits) == 0, nameof(units), "Units contains an unknown value: {0}", units);
            CalendarSystem calendar = start.Calendar;

            Preconditions.CheckArgument(calendar.Equals(end.Calendar), nameof(end), "start and end must use the same calendar system");

            if (start == end)
            {
                return(Zero);
            }

            // Adjust for situations like "days between 5th January 10am and 7th January 5am" which should be one
            // day, because if we actually reach 7th January with date fields, we've overshot.
            // The date adjustment will always be valid, because it's just moving it towards start.
            // We need this for all date-based period fields. We could potentially optimize by not doing this
            // in cases where we've only got time fields...
            LocalDate endDate = end.Date;

            if (start < end)
            {
                if (start.TimeOfDay > end.TimeOfDay)
                {
                    endDate = endDate.PlusDays(-1);
                }
            }
            else if (start > end && start.TimeOfDay < end.TimeOfDay)
            {
                endDate = endDate.PlusDays(1);
            }

            // Optimization for single field
            switch (units)
            {
            case PeriodUnits.Years: return(FromYears(DatePeriodFields.YearsField.UnitsBetween(start.Date, endDate)));

            case PeriodUnits.Months: return(FromMonths(DatePeriodFields.MonthsField.UnitsBetween(start.Date, endDate)));

            case PeriodUnits.Weeks: return(FromWeeks(DatePeriodFields.WeeksField.UnitsBetween(start.Date, endDate)));

            case PeriodUnits.Days: return(FromDays(InternalDaysBetween(start.Date, endDate)));

            case PeriodUnits.Hours: return(FromHours(TimePeriodField.Hours.UnitsBetween(start, end)));

            case PeriodUnits.Minutes: return(FromMinutes(TimePeriodField.Minutes.UnitsBetween(start, end)));

            case PeriodUnits.Seconds: return(FromSeconds(TimePeriodField.Seconds.UnitsBetween(start, end)));

            case PeriodUnits.Milliseconds: return(FromMilliseconds(TimePeriodField.Milliseconds.UnitsBetween(start, end)));

            case PeriodUnits.Ticks: return(FromTicks(TimePeriodField.Ticks.UnitsBetween(start, end)));

            case PeriodUnits.Nanoseconds: return(FromNanoseconds(TimePeriodField.Nanoseconds.UnitsBetween(start, end)));
            }

            // Multiple fields
            LocalDateTime remaining = start;
            int           years = 0, months = 0, weeks = 0, days = 0;

            if ((units & PeriodUnits.AllDateUnits) != 0)
            {
                LocalDate remainingDate = DateComponentsBetween(
                    start.Date, endDate, units, out years, out months, out weeks, out days);
                remaining = new LocalDateTime(remainingDate, start.TimeOfDay);
            }
            if ((units & PeriodUnits.AllTimeUnits) == 0)
            {
                return(new Period(years, months, weeks, days));
            }

            // The remainder of the computation is with fixed-length units, so we can do it all with
            // Duration instead of Local* values. We don't know for sure that this is small though - we *could*
            // be trying to find the difference between 9998 BC and 9999 CE in nanoseconds...
            // Where we can optimize, do everything with long arithmetic (as we do for Between(LocalTime, LocalTime)).
            // Otherwise (rare case), use duration arithmetic.
            long hours, minutes, seconds, milliseconds, ticks, nanoseconds;
            var  duration = end.ToLocalInstant().TimeSinceLocalEpoch - remaining.ToLocalInstant().TimeSinceLocalEpoch;

            if (duration.IsInt64Representable)
            {
                TimeComponentsBetween(duration.ToInt64Nanoseconds(), units, out hours, out minutes, out seconds, out milliseconds, out ticks, out nanoseconds);
            }
            else
            {
                hours        = UnitsBetween(PeriodUnits.Hours, TimePeriodField.Hours);
                minutes      = UnitsBetween(PeriodUnits.Minutes, TimePeriodField.Minutes);
                seconds      = UnitsBetween(PeriodUnits.Seconds, TimePeriodField.Seconds);
                milliseconds = UnitsBetween(PeriodUnits.Milliseconds, TimePeriodField.Milliseconds);
                ticks        = UnitsBetween(PeriodUnits.Ticks, TimePeriodField.Ticks);
                nanoseconds  = UnitsBetween(PeriodUnits.Ticks, TimePeriodField.Nanoseconds);
            }
            return(new Period(years, months, weeks, days, hours, minutes, seconds, milliseconds, ticks, nanoseconds));

            long UnitsBetween(PeriodUnits mask, TimePeriodField timeField)
            {
                if ((mask & units) == 0)
                {
                    return(0);
                }
                long value = timeField.GetUnitsInDuration(duration);

                duration -= timeField.ToDuration(value);
                return(value);
            }
        }
Beispiel #11
0
 /// <summary>
 /// Constructs a single-point date time interval that starts and ends at the given <see cref="LocalDateTime"/>.
 /// </summary>
 /// <param name="point">The single date time included in the interval.</param>
 /// <returns>A single-point date time interval only including the given date time.</returns>
 public DateTimeInterval(LocalDateTime point)
 {
     Start = End = point;
 }
Beispiel #12
0
 /// <summary>
 /// Maps the given <see cref="LocalDateTime"/> to the corresponding <see cref="ZonedDateTime"/> in a lenient
 /// manner: ambiguous values map to the later of the alternatives, and "skipped" values map to the start of the
 /// zone interval after the "gap".
 /// </summary>
 /// <remarks>
 /// See <see cref="AtStrictly"/> and <see cref="ResolveLocal"/> for alternative ways to map a local time to a
 /// specific instant.
 /// </remarks>
 /// <param name="localDateTime">The local date/time to map.</param>
 /// <returns>The unambiguous mapping if there is one, the later result if the mapping is ambiguous,
 /// or the start of the later zone interval if the given local date/time is skipped.</returns>
 public ZonedDateTime AtLeniently(LocalDateTime localDateTime)
 {
     return(ResolveLocal(localDateTime, Resolvers.LenientResolver));
 }
Beispiel #13
0
 /// <summary>
 /// Maps the given <see cref="LocalDateTime"/> to the corresponding <see cref="ZonedDateTime"/>, if and only if
 /// that mapping is unambiguous in this time zone.  Otherwise, <see cref="SkippedTimeException"/> or
 /// <see cref="AmbiguousTimeException"/> is thrown, depending on whether the mapping is ambiguous or the local
 /// date/time is skipped entirely.
 /// </summary>
 /// <remarks>
 /// See <see cref="AtLeniently"/> and <see cref="ResolveLocal"/> for alternative ways to map a local time to a
 /// specific instant.
 /// </remarks>
 /// <param name="localDateTime">The local date and time to map into this time zone.</param>
 /// <exception cref="SkippedTimeException">The given local date/time is skipped in this time zone.</exception>
 /// <exception cref="AmbiguousTimeException">The given local date/time is ambiguous in this time zone.</exception>
 /// <returns>The unambiguous matching <see cref="ZonedDateTime"/> if it exists.</returns>
 public ZonedDateTime AtStrictly(LocalDateTime localDateTime)
 {
     return(MapLocal(localDateTime).Single());
 }
Beispiel #14
0
 internal PeriodComparer(LocalDateTime baseDateTime)
 {
     this.baseDateTime = baseDateTime;
 }
Beispiel #15
0
 /// <summary>
 /// Creates a new instance for the given local date/time and time zone.
 /// </summary>
 /// <remarks>
 /// User code is unlikely to need to deliberately call this constructor except
 /// possibly for testing.
 /// </remarks>
 /// <param name="localDateTime">The local date/time which is skipped in the specified time zone.</param>
 /// <param name="zone">The time zone in which the local date/time does not exist.</param>
 public SkippedTimeException(LocalDateTime localDateTime, DateTimeZone zone)
     : base("Local time " + localDateTime + " is invalid in time zone " + zone.Id)
 {
     this.localDateTime = localDateTime;
     this.zone          = zone;
 }
Beispiel #16
0
 public static OffsetDateTime FromDateTimeOffset(DateTimeOffset dateTimeOffset)
 {
     return(new OffsetDateTime(LocalDateTime.FromDateTime(dateTimeOffset.DateTime),
                               Offset.FromTimeSpan(dateTimeOffset.Offset)));
 }
Beispiel #17
0
 // Visible for extension methods.
 internal LocalDate(LocalDateTime localTime)
 {
     this.localTime = localTime;
 }
Beispiel #18
0
 /// <summary>
 /// Constructs a new offset date/time with the given local date and time, and the given offset from UTC.
 /// </summary>
 /// <param name="localDateTime">Local date and time to represent</param>
 /// <param name="offset">Offset from UTC</param>
 public OffsetDateTime(LocalDateTime localDateTime, Offset offset)
 {
     this.localDateTime = localDateTime;
     this.offset        = offset;
 }
Beispiel #19
0
 /// <summary>
 /// Maps the given <see cref="LocalDateTime"/> to the corresponding <see cref="ZonedDateTime"/>, following
 /// the given <see cref="ZoneLocalMappingResolver"/> to handle ambiguity and skipped times.
 /// </summary>
 /// <remarks>
 /// <para>
 /// This is a convenience method for calling <see cref="MapLocal"/> and passing the result to the resolver.
 /// Common options for resolvers are provided in the static <see cref="Resolvers"/> class.
 /// </para>
 /// <para>
 /// See <see cref="AtStrictly"/> and <see cref="AtLeniently"/> for alternative ways to map a local time to a
 /// specific instant.
 /// </para>
 /// </remarks>
 /// <param name="localDateTime">The local date and time to map in this time zone.</param>
 /// <param name="resolver">The resolver to apply to the mapping.</param>
 /// <returns>The result of resolving the mapping.</returns>
 public ZonedDateTime ResolveLocal(LocalDateTime localDateTime, [NotNull] ZoneLocalMappingResolver resolver)
 {
     Preconditions.CheckNotNull(resolver, nameof(resolver));
     return(resolver(MapLocal(localDateTime)));
 }
Beispiel #20
0
 /// <summary>
 /// Creates a new instance for the given local date/time and time zone.
 /// </summary>
 /// <remarks>
 /// User code is unlikely to need to deliberately call this constructor except
 /// possibly for testing.
 /// </remarks>
 /// <param name="localDateTime">The local date/time which is skipped in the specified time zone.</param>
 /// <param name="zone">The time zone in which the local date/time does not exist.</param>
 public SkippedTimeException(LocalDateTime localDateTime, DateTimeZone zone)
     : base("Local time " + localDateTime + " is invalid in time zone " + Preconditions.CheckNotNull(zone, nameof(zone)).Id)
 {
     this.LocalDateTime = localDateTime;
     this.Zone          = zone;
 }
Beispiel #21
0
 /// <summary>
 /// Maps the given <see cref="LocalDateTime"/> to the corresponding <see cref="ZonedDateTime"/>, if and only if
 /// that mapping is unambiguous in this time zone.  Otherwise, <see cref="SkippedTimeException"/> or
 /// <see cref="AmbiguousTimeException"/> is thrown, depending on whether the mapping is ambiguous or the local
 /// date/time is skipped entirely.
 /// </summary>
 /// <remarks>
 /// See <see cref="AtLeniently"/> and <see cref="ResolveLocal(LocalDateTime, ZoneLocalMappingResolver)"/> for alternative ways to map a local time to a
 /// specific instant.
 /// </remarks>
 /// <param name="localDateTime">The local date and time to map into this time zone.</param>
 /// <exception cref="SkippedTimeException">The given local date/time is skipped in this time zone.</exception>
 /// <exception cref="AmbiguousTimeException">The given local date/time is ambiguous in this time zone.</exception>
 /// <returns>The unambiguous matching <see cref="ZonedDateTime"/> if it exists.</returns>
 public ZonedDateTime AtStrictly(LocalDateTime localDateTime) =>
 ResolveLocal(localDateTime, Resolvers.StrictResolver);
 /// <summary>
 /// To LocalDateTime
 /// </summary>
 /// <param name="lt"></param>
 /// <returns></returns>
 public static LocalDateTime ToLocalDateTime(this LocalTime lt) =>
 LocalDateTime.FromDateTime(DateTime.Today).SetTime(lt);
Beispiel #23
0
 /// <summary>
 /// Maps the given <see cref="LocalDateTime"/> to the corresponding <see cref="ZonedDateTime"/> in a lenient
 /// manner: ambiguous values map to the earlier of the alternatives, and "skipped" values are shifted forward
 /// by the duration of the "gap".
 /// </summary>
 /// <remarks>
 /// See <see cref="AtStrictly"/> and <see cref="ResolveLocal(LocalDateTime, ZoneLocalMappingResolver)"/> for alternative ways to map a local time to a
 /// specific instant.
 /// <para>Note: The behavior of this method was changed in version 2.0 to fit the most commonly seen real-world
 /// usage pattern.  Previous versions returned the later instance of ambiguous values, and returned the start of
 /// the zone interval after the gap for skipped value.  The previous functionality can still be used if desired,
 /// by using <see cref="ResolveLocal(LocalDateTime, AmbiguousTimeResolver, SkippedTimeResolver)"/> and passing the
 /// <see cref="Resolvers.ReturnLater"/> and <see cref="Resolvers.ReturnStartOfIntervalAfter"/> resolvers.</para>
 /// </remarks>
 /// <param name="localDateTime">The local date/time to map.</param>
 /// <returns>The unambiguous mapping if there is one, the earlier result if the mapping is ambiguous,
 /// or the forward-shifted value if the given local date/time is skipped.</returns>
 public ZonedDateTime AtLeniently(LocalDateTime localDateTime) =>
 ResolveLocal(localDateTime, Resolvers.LenientResolver);
Beispiel #24
0
 public void Deconstruct(out LocalDateTime localDateTime, out DateTimeZone dateTimeZone, out Offset offset)
 {
     localDateTime = LocalDateTime;
     dateTimeZone  = Zone;
     offset        = Offset;
 }
Beispiel #25
0
        public static int DaysOff(string date, string time, string rpfTimeZone, string ingestTimeZone)
        {
            int           tensPlace     = 0;
            DateTime      localDt       = DateTime.Parse(string.Format("{0} {1}", date, time));
            LocalTime     localTime     = new LocalTime(localDt.Hour, localDt.Minute, localDt.Second);
            int           hour          = localDt.Hour;
            LocalDateTime localDateTime = LocalDateTime.FromDateTime(localDt);

            DateTimeZoneProviders dtzp = new DateTimeZoneProviders();

            DateTimeZone rpfZone    = dtzp.Tzdb[rpfTimeZone];
            DateTimeZone ingestZone = dtzp.Tzdb[ingestTimeZone];

            ZonedDateTime zonedDateTime = localDateTime.InZoneLeniently(rpfZone);
            Offset        rpfOffset     = rpfZone.GetUtcOffset(zonedDateTime.ToInstant());
            Offset        ingestOffset  = ingestZone.GetUtcOffset(zonedDateTime.ToInstant());


            ZonedDateTime zeroTime   = new LocalDateTime(LocalDate.FromDateTime(localDt), new LocalTime(0, 15)).InZoneLeniently(ingestZone);
            ZonedDateTime elevenTime = new LocalDateTime(LocalDate.FromDateTime(localDt), new LocalTime(11, 15)).InZoneLeniently(ingestZone);

            ZonedDateTime zeroTimeRpf   = new LocalDateTime(LocalDate.FromDateTime(localDt), new LocalTime(0, 15)).InZoneLeniently(rpfZone);
            ZonedDateTime elevenTimeRpf = new LocalDateTime(LocalDate.FromDateTime(localDt), new LocalTime(11, 15)).InZoneLeniently(rpfZone);

            Offset zeroOffset   = zeroTimeRpf.Offset - zeroTime.Offset;
            Offset elevenOffset = elevenTimeRpf.Offset - elevenTime.Offset;

            if (Math.Abs(zeroOffset.Milliseconds) < Math.Abs(elevenOffset.Milliseconds))
            {
                var zeroClock = new LocalTime(0, 0);
                var lowTime   = zeroClock.PlusMilliseconds(-zeroOffset.Milliseconds);
                var highTime  = zeroClock.PlusMilliseconds(-elevenOffset.Milliseconds);

                if (localTime >= lowTime && localTime < highTime)
                {
                    tensPlace = 10;
                }
            }

            /*
             *
             * at0 get offsets and subtract rpfoffat0 - ingestOffsetat0  (-4)
             * at11 get offsets and subtract rpfoffat11 - ingestoffat11 (-5)
             *
             * if these are different
             *  range is (0 in time) - at0 or (0 - -4) = 4
             *   to (0 in time) -at11 or (0 - -5) = 5
             *
             *
             */

            var offsetDelta = rpfOffset - ingestOffset;
            var hrsToAdd    = offsetDelta.Milliseconds / NodaConstants.MillisecondsPerHour;

            var newHour = (hour + hrsToAdd);

            if (newHour < 0)
            {
                return(-1 - tensPlace);
            }
            else if (newHour > 24)
            {
                return(1 + tensPlace);
            }
            else
            {
                return(0 + tensPlace);
            }
        }