예제 #1
0
        public void Scheduling()
        {
            #region Scheduling
            var nz = TimeSpan.FromHours(12);
            var availability = new TimeRange[]
            {
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 9, 0, 0,  nz), TimeSpan.FromHours(3)), // 0900 - 1200
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 14, 0, 0,  nz), TimeSpan.FromHours(3)), // 1400 - 1700
            };
            var busy = new TimeRange[]
            {
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 9, 0, 0,  nz), TimeSpan.FromMinutes(30)), // 0900 - 0930
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 9, 0, 0,  nz), TimeSpan.FromHours(1)), // 0900 - 1000
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 11, 0, 0,  nz), TimeSpan.FromHours(1)), // 1100 - 1200
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 11, 0, 0,  nz), TimeSpan.FromHours(2)), // 1100 - 1300
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 16, 0, 0,  nz), TimeSpan.FromMinutes(30)), // 1600 - 1630
            };

            // Get the free times and then find a 2 hour slot.
            var when = availability
                .SelectMany(a => a.Subtract(busy))
                .SelectMany(a => a.Divide(TimeSpan.FromHours(2)))
                .First();
            Console.WriteLine(when);

            // Produces: 13 Aug 2013 2:00:00 p.m. +12:00 for 02:00:00
            #endregion
        }
예제 #2
0
 public void DividingEndOfTime()
 {
     var now = DateTimeOffset.MaxValue - TimeSpan.FromHours(1);
     var availableTime = new TimeRange(now, now.AddHours(1));
     var freeSlots = availableTime
         .Divide(TimeSpan.FromMinutes(15))
         .ToArray();
     Assert.AreEqual(4, freeSlots.Length);
     Assert.IsTrue(freeSlots.All(s => s.Duration == TimeSpan.FromMinutes(15)));
 }
예제 #3
0
        public void ContainmentEndofTime()
        {
            var now = DateTimeOffset.Now;
            var eot = DateTimeOffset.MaxValue;
            var start = now - TimeSpan.FromSeconds(10);
            var tick = TimeSpan.FromTicks(1);

            var range = new TimeRange(start);
            Assert.IsFalse(range.Contains(start - tick));
            Assert.IsTrue(range.Contains(start));
            Assert.IsTrue(range.Contains(start + tick));
            Assert.IsTrue(range.Contains(eot - tick));
            Assert.IsTrue(range.Contains(eot));
        }
예제 #4
0
        public void Containment()
        {
            var now = DateTimeOffset.Now;
            var start = now - TimeSpan.FromSeconds(10);
            var end = now + TimeSpan.FromSeconds(10);
            var tick = TimeSpan.FromTicks(1);
            var range = new TimeRange(start, end);

            Assert.IsFalse(range.Contains(start - tick));
            Assert.IsTrue(range.Contains(start));
            Assert.IsTrue(range.Contains(start + tick));

            Assert.IsTrue(range.Contains(end - tick));
            Assert.IsFalse(range.Contains(end));
            Assert.IsFalse(range.Contains(end + tick));
        }
예제 #5
0
        void Snippets()
        {
            #region Dividing
            var now = new DateTimeOffset(2013, 8, 13, 13, 0, 0, TimeSpan.FromHours(12));
            var availableTime = new TimeRange(now, now.AddHours(1));
            var freeSlots = availableTime.Divide(TimeSpan.FromMinutes(15));
            foreach (var freeSlot in freeSlots)
            {
                Console.WriteLine(freeSlot);
            }

            // Produces 4 15 minute time ranges.
            //
            // 13 Aug 2013 1:00:00 p.m. +12:00 for 00:15:00
            // 13 Aug 2013 1:15:00 p.m. +12:00 for 00:15:00
            // 13 Aug 2013 1:30:00 p.m. +12:00 for 00:15:00
            // 13 Aug 2013 1:45:00 p.m. +12:00 for 00:15:00
            #endregion
        }
예제 #6
0
        void Snippets2()
        {
            #region SubtractCollection
            var nz = TimeSpan.FromHours(12);
            var availability =
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 9, 0, 0, nz), TimeSpan.FromHours(3)); // 0900 - 1200
            var busy = new TimeRange[]
            {
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 9, 0, 0,  nz), TimeSpan.FromMinutes(30)), // 0900 - 0930
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 9, 0, 0,  nz), TimeSpan.FromHours(1)), // 0900 - 1000
                 new TimeRange(new DateTimeOffset(2013, 8, 13, 11, 15, 0,  nz), TimeSpan.FromMinutes(15)), // 1115 - 1130
            };
            var free = availability.Subtract(busy);
            foreach (var t in free)
                Console.WriteLine(t);

            // Produces the following free time
            // 13 Aug 2013 10:00:00 a.m. +12:00 for 01:15:00
            // 13 Aug 2013 11:30:00 a.m. +12:00 for 00:30:00
            #endregion
        }
예제 #7
0
 // TODO: maybe rename to Remove
 /// <summary>
 ///   Generates an ordered sequence of time ranges that excludes the specified <see cref="TimeRange"/>
 ///   from this <see cref="TimeRange"/>.
 /// </summary>
 /// <param name="other">
 ///   The <see cref="TimeRange"/> to exclude.
 /// </param>
 /// <returns>
 ///   An ordered sequence of time range.  The sequence can contain 0, 1 or 2 time ranges.
 /// </returns>
 /// <remarks>
 ///   This method is implemented by using deferred execution. The immediate return value is an object that stores all the information that is required 
 ///   to perform the action. The operation represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method 
 ///   directly or by using <c>foreach</c>.
 /// </remarks>      
 /// <example>
 ///   The following example determines the free time for a resource..
 /// 
 ///   <code title="Subtracting a Time Range" source="SepiaExamples\TimeRangeExample.cs" region="SubtractCollection" language="C#" />
 /// </example>
 public IEnumerable<TimeRange> Subtract(TimeRange other)
 {
     if (other.StartsOn <= this.StartsOn && other.EndsOn >= this.EndsOn)
         yield break;
     if (other.EndsOn <= this.StartsOn || this.EndsOn <= other.StartsOn)
     {
         yield return this;
         yield break;
     }
     if (other.StartsOn <= this.StartsOn && other.EndsOn < this.EndsOn)
     {
         yield return new TimeRange(other.EndsOn, this.EndsOn);
         yield break;
     }
     if (other.StartsOn < this.EndsOn && this.StartsOn != other.StartsOn)
         yield return new TimeRange(this.StartsOn, other.StartsOn);
     if (other.endsOn < this.EndsOn && other.EndsOn != this.EndsOn)
         yield return new TimeRange(other.EndsOn, this.EndsOn);
 }
예제 #8
0
 /// <summary>
 ///   Determines if the specified <see cref="TimeRange"/> overlaps this time range.
 /// </summary>
 /// <param name="that">The time to check for intersection.</param>
 /// <returns>
 ///   <b>true</b>, if <paramref name="that"/> intersects this time range; otherwise, <b>false</b>.
 /// </returns>
 /// <seealso href="http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap"/>
 public bool Intersects(TimeRange that)
 {
     return (this.StartsOn < that.EndsOn) && (that.StartsOn < this.EndsOn);
 }
예제 #9
0
        // TODO: maybe rename to split
        /// <summary>
        ///   Generates an ordered sequence of time ranges starting at this <see cref="StartsOn"/>
        ///   incrementing by the specified <see cref="TimeSpan"/> until the <see cref="EndsOn"/> is reached. 
        /// </summary>
        /// <param name="step">
        ///   The <see cref="TimeSpan"/> to increment by.
        /// </param>
        /// <returns>
        ///   An ordered sequence of time range.
        /// </returns>
        /// <exception cref="ArgumentException">
        ///   <paramref name="step"/> is less than or equal <see cref="TimeSpan.Zero"/>.
        /// </exception>
        /// <remarks>
        ///   This method is implemented by using deferred execution. The immediate return value is an object that stores all the information that is required 
        ///   to perform the action. The operation represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method 
        ///   directly or by using <c>foreach</c>.
        /// <para>
        ///   The sequence can, in theory, be infinite because each item is generated as needed.  The length of the sequence can be
        ///   controlled by using a <see cref="System.Linq"/> limiter; such as <see cref="System.Linq.Enumerable.Take{T}"/>.
        /// </para>
        /// <para>
        ///   The sequence is terminated on Overflow.
        /// </para>
        /// <para>
        ///   When <paramref name="step"/> does not divide evenly into the <see cref="Duration"/>, then the "last" time range is not returned.
        ///   In other words, only time ranges with a <see cref="Duration"/> equal to <paramref name="step"/> is returned.
        /// </para>
        /// </remarks>      
        /// <example>
        ///   The following example divides a <see cref="TimeRange"/> into 15 minutes slots.
        /// 
        ///   <code title="Dividing a Time Range" source="SepiaExamples\TimeRangeExample.cs" region="Dividing" language="C#" />
        /// </example>
        public IEnumerable<TimeRange> Divide(TimeSpan step)
        {
            Guard.Require(step > TimeSpan.Zero, "step", "Cannot step by a zero or negative number.");

            var next = startsOn;
            while (next < endsOn)
            {
                var value = new TimeRange(next, step);
                if (value.Duration != step || value.endsOn > endsOn)
                    break;
                yield return value;

                // Overflow ends the sequence.
                checked
                {
                    try
                    {
                        next += step;
                    }
                    catch (OverflowException)
                    {
                        break;
                    }
                }
            }
        }
예제 #10
0
 public void DividingNone()
 {
     var now = new DateTimeOffset(2013, 8, 13, 13, 0, 0, TimeSpan.FromHours(12));
     var availableTime = new TimeRange(now, now.AddMinutes(14));
     var freeSlots = availableTime
         .Divide(TimeSpan.FromMinutes(15))
         .ToArray();
     Assert.AreEqual(0, freeSlots.Length);
 }
예제 #11
0
        public void SubtractingAgain()
        {
            var nz = TimeSpan.FromHours(12);
            var duration = TimeSpan.FromMinutes(1);
            var a = new DateTimeOffset(2013, 8, 13, 9, 0, 0, nz);
            var b = a + duration;
            var c = b + duration;
            var d = c + duration;
            var e = d + duration;
            var f = e + duration;
            var g = f + duration;
            var h = g + duration;
            var availability = new TimeRange(c, f);

            var free = availability.Subtract(new TimeRange(a, b)).ToArray();
            Assert.AreEqual(1, free.Length);
            Assert.AreEqual(availability, free[0]);

            free = availability.Subtract(new TimeRange(b, c)).ToArray();
            Assert.AreEqual(1, free.Length);
            Assert.AreEqual(availability, free[0]);

            free = availability.Subtract(new TimeRange(f, g)).ToArray();
            Assert.AreEqual(1, free.Length);
            Assert.AreEqual(availability, free[0]);

            free = availability.Subtract(new TimeRange(g, h)).ToArray();
            Assert.AreEqual(1, free.Length);
            Assert.AreEqual(availability, free[0]);

            free = availability.Subtract(new TimeRange(b, g)).ToArray();
            Assert.AreEqual(0, free.Length);

            free = availability.Subtract(new TimeRange(d, e)).ToArray();
            Assert.AreEqual(2, free.Length);
            Assert.AreEqual(new TimeRange(c, d), free[0]);
            Assert.AreEqual(new TimeRange(e, f), free[1]);

            free = availability.Subtract(new TimeRange(b, d)).ToArray(); // fails
            Assert.AreEqual(1, free.Length);
            Assert.AreEqual(new TimeRange(d, f), free[0]);

            free = availability.Subtract(new TimeRange(e, g)).ToArray();
            Assert.AreEqual(1, free.Length);
            Assert.AreEqual(new TimeRange(c, e), free[0]);

            free = availability.Subtract(availability).ToArray();
            Assert.AreEqual(0, free.Length);

            free = availability.Subtract(new TimeRange(c, d)).ToArray();
            Assert.AreEqual(1, free.Length);
            Assert.AreEqual(new TimeRange(d, f), free[0]);

            free = availability.Subtract(new TimeRange(e, f)).ToArray();
            Assert.AreEqual(1, free.Length);
            Assert.AreEqual(new TimeRange(c, e), free[0]);
        }
예제 #12
0
        public void Subtracting()
        {
            var now = new DateTimeOffset(2013, 8, 13, 13, 0, 0, TimeSpan.FromHours(12));
            var tick = new TimeSpan(1);
            var time = new TimeRange(now, now.AddHours(1));
            var before = new TimeRange(now - TimeSpan.FromHours(1), time.StartsOn);
            var after = new TimeRange(time.EndsOn, TimeSpan.FromHours(1));
            var mid = new TimeRange(now.AddMinutes(15), TimeSpan.FromMinutes(30));

            // No intersection
            Assert.AreEqual(1, time.Subtract(before).Count());
            Assert.AreEqual(time, time.Subtract(before).First());
            Assert.AreEqual(1, time.Subtract(after).Count());
            Assert.AreEqual(time, time.Subtract(after).First());

            // Identity
            Assert.AreEqual(0, time.Subtract(time).Count());

            // Subsumes
            Assert.AreEqual(0, time.Subtract(new TimeRange(before.StartsOn, after.EndsOn)).Count());

            // Middle
            Assert.AreEqual(2, time.Subtract(mid).Count());
            Assert.IsTrue(time.Subtract(mid).Any(t => t.StartsOn == now && t.Duration == TimeSpan.FromMinutes(15)));
            Assert.IsTrue(time.Subtract(mid).Any(t => t.StartsOn == now.AddMinutes(45) && t.Duration == TimeSpan.FromMinutes(15)));
        }
예제 #13
0
        public void ParsingIso8061()
        {
            var nz = TimeSpan.FromHours(12);
            var utc = TimeSpan.Zero;
            var expectUtc = new TimeRange(new DateTimeOffset(2013, 8, 13, 9, 0, 0,  utc), TimeSpan.FromMinutes(30));
            var expectNz = new TimeRange(new DateTimeOffset(2013, 8, 13, 9, 0, 0,  nz), TimeSpan.FromMinutes(30));

            Assert.AreEqual(expectUtc, TimeRange.ParseIso8061("20130813T090000Z/20130813T093000Z"));
            Assert.AreEqual(expectNz, TimeRange.ParseIso8061("20130813T090000+1200/20130813T093000+1200"));
            Assert.AreEqual(expectUtc, TimeRange.ParseIso8061("20130813T090000Z/PT30M"));
            Assert.AreEqual(expectNz, TimeRange.ParseIso8061("20130813T090000+1200/PT30M"));

            Assert.AreEqual(expectUtc, TimeRange.ParseIso8061("2013-08-13T09:00:00Z/2013-08-13T09:30:00Z"));
            Assert.AreEqual(expectNz, TimeRange.ParseIso8061("2013-08-13T09:00:00+1200/2013-08-13T09:30:00+1200"));
            Assert.AreEqual(expectUtc, TimeRange.ParseIso8061("2013-08-13T09:00:00Z/PT30M"));
            Assert.AreEqual(expectNz, TimeRange.ParseIso8061("2013-08-13T09:00:00+1200/PT30M"));
        }
예제 #14
0
 public void DividingUneven()
 {
     var now = new DateTimeOffset(2013, 8, 13, 13, 0, 0, TimeSpan.FromHours(12));
     var availableTime = new TimeRange(now, now.AddMinutes(59));
     var freeSlots = availableTime
         .Divide(TimeSpan.FromMinutes(15))
         .ToArray();
     Assert.AreEqual(3, freeSlots.Length);
     Assert.IsTrue(freeSlots.All(s => s.Duration == TimeSpan.FromMinutes(15)));
 }