1 // Written in the D programming language
2 
3 /++
4 $(SCRIPT inhibitQuickIndex = 1;)
5 $(DIVC quickindex,
6 $(BOOKTABLE,
7 $(TR $(TH Category) $(TH Functions))
8 $(TR $(TD Main types) $(TD
9     $(LREF Interval)
10     $(LREF Direction)
11 ))
12 $(TR $(TD Special intervals) $(TD
13     $(LREF everyDayOfWeek)
14     $(LREF everyMonth)
15     $(LREF everyDuration)
16 ))
17 $(TR $(TD Special intervals) $(TD
18     $(LREF NegInfInterval)
19     $(LREF PosInfInterval)
20 ))
21 $(TR $(TD Underlying ranges) $(TD
22     $(LREF IntervalRange)
23     $(LREF NegInfIntervalRange)
24     $(LREF PosInfIntervalRange)
25 ))
26 $(TR $(TD Flags) $(TD
27     $(LREF PopFirst)
28 ))
29 ))
30 
31     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
32     Authors:   $(HTTP jmdavisprog.com, Jonathan M Davis)
33     Source:    $(PHOBOSSRC std/datetime/interval.d)
34 +/
35 module std.datetime.interval;
36 
37 import core.time : Duration, dur;
38 import std.datetime.date : AllowDayOverflow, DateTimeException, daysToDayOfWeek,
39                            DayOfWeek, isTimePoint, Month;
40 import std.exception : enforce;
41 import std.range.primitives : isOutputRange;
42 import std.traits : isIntegral;
43 import std.typecons : Flag;
44 
45 version (StdUnittest) import std.exception : assertThrown;
46 
47 
48 /++
49     Indicates a direction in time. One example of its use is $(LREF Interval)'s
50     $(LREF expand) function which uses it to indicate whether the interval
51     should be expanded backwards (into the past), forwards (into the future), or
52     both.
53   +/
54 enum Direction
55 {
56     /// Backward.
57     bwd,
58 
59     /// Forward.
60     fwd,
61 
62     /// Both backward and forward.
63     both
64 }
65 
66 
67 /++
68     Used to indicate whether `popFront` should be called immediately upon
69     creating a range. The idea is that for some functions used to generate a
70     range for an interval, `front` is not necessarily a time point which
71     would ever be generated by the range (e.g. if the range were every Sunday
72     within an interval, but the interval started on a Monday), so there needs
73     to be a way to deal with that. To get the first time point in the range to
74     match what the function generates, then use `PopFirst.yes` to indicate
75     that the range should have `popFront` called on it before the range is
76     returned so that `front` is a time point which the function would
77     generate. To let the first time point not match the generator function,
78     use `PopFront.no`.
79 
80     For instance, if the function used to generate a range of time points
81     generated successive Easters (i.e. you're iterating over all of the Easters
82     within the interval), the initial date probably isn't an Easter. Using
83     `PopFirst.yes` would tell the function which returned the range that
84     `popFront` was to be called so that front would then be an Easter - the
85     next one generated by the function (which when iterating forward would be
86     the Easter following the original `front`, while when iterating backward,
87     it would be the Easter prior to the original `front`). If
88     `PopFirst.no` were used, then `front` would remain the original time
89     point and it would not necessarily be a time point which would be generated
90     by the range-generating function (which in many cases is exactly what is
91     desired - e.g. if iterating over every day starting at the beginning of the
92     interval).
93 
94     If set to `PopFirst.no`, then popFront is not called before returning
95     the range.
96 
97     Otherwise, if set to `PopFirst.yes`, then popFront is called before
98     returning the range.
99   +/
100 alias PopFirst = Flag!"popFirst";
101 
102 
103 /++
104     Represents an interval of time.
105 
106     An `Interval` has a starting point and an end point. The interval of time
107     is therefore the time starting at the starting point up to, but not
108     including, the end point. e.g.
109 
110     $(BOOKTABLE,
111     $(TR $(TD [January 5th, 2010 - March 10th, 2010$(RPAREN)))
112     $(TR $(TD [05:00:30 - 12:00:00$(RPAREN)))
113     $(TR $(TD [1982-01-04T08:59:00 - 2010-07-04T12:00:00$(RPAREN)))
114     )
115 
116     A range can be obtained from an `Interval`, allowing iteration over
117     that interval, with the exact time points which are iterated over depending
118     on the function which generates the range.
119   +/
120 struct Interval(TP)
121 {
122 public:
123 
124     /++
125         Params:
126             begin = The time point which begins the interval.
127             end   = The time point which ends (but is not included in) the
128                     interval.
129 
130         Throws:
131             $(REF DateTimeException,std,datetime,date) if $(D_PARAM end) is
132             before $(D_PARAM begin).
133 
134         Example:
135         --------------------
136         Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
137         --------------------
138       +/
139     this(U)(scope const TP begin, scope const U end) pure
140         if (is(immutable TP == immutable U))
141     {
142         if (!_valid(begin, end))
143             throw new DateTimeException("Arguments would result in an invalid Interval.");
144         _begin = cast(TP) begin;
145         _end = cast(TP) end;
146     }
147 
148 
149     /++
150         Params:
151             begin    = The time point which begins the interval.
152             duration = The duration from the starting point to the end point.
153 
154         Throws:
155             $(REF DateTimeException,std,datetime,date) if the resulting
156             `end` is before `begin`.
157 
158         Example:
159         --------------------
160         assert(Interval!Date(Date(1996, 1, 2), dur!"days"(3)) ==
161                Interval!Date(Date(1996, 1, 2), Date(1996, 1, 5)));
162         --------------------
163       +/
164     this(D)(scope const TP begin, scope const D duration) pure
165         if (__traits(compiles, begin + duration))
166     {
167         _begin = cast(TP) begin;
168         _end = begin + duration;
169         if (!_valid(_begin, _end))
170             throw new DateTimeException("Arguments would result in an invalid Interval.");
171     }
172 
173 
174     /++
175         Params:
176             rhs = The $(LREF Interval) to assign to this one.
177       +/
178     ref Interval opAssign(const ref Interval rhs) pure nothrow
179     {
180         _begin = cast(TP) rhs._begin;
181         _end = cast(TP) rhs._end;
182         return this;
183     }
184 
185 
186     /++
187         Params:
188             rhs = The $(LREF Interval) to assign to this one.
189       +/
190     ref Interval opAssign(Interval rhs) pure nothrow
191     {
192         _begin = cast(TP) rhs._begin;
193         _end = cast(TP) rhs._end;
194         return this;
195     }
196 
197 
198     /++
199         The starting point of the interval. It is included in the interval.
200 
201         Example:
202         --------------------
203         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).begin ==
204                Date(1996, 1, 2));
205         --------------------
206       +/
207     @property TP begin() const pure nothrow
208     {
209         return cast(TP) _begin;
210     }
211 
212 
213     /++
214         The starting point of the interval. It is included in the interval.
215 
216         Params:
217             timePoint = The time point to set `begin` to.
218 
219         Throws:
220             $(REF DateTimeException,std,datetime,date) if the resulting
221             interval would be invalid.
222       +/
223     @property void begin(TP timePoint) pure
224     {
225         if (!_valid(timePoint, _end))
226             throw new DateTimeException("Arguments would result in an invalid Interval.");
227         _begin = timePoint;
228     }
229 
230 
231     /++
232         The end point of the interval. It is excluded from the interval.
233 
234         Example:
235         --------------------
236         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).end ==
237                Date(2012, 3, 1));
238         --------------------
239       +/
240     @property TP end() const pure nothrow
241     {
242         return cast(TP) _end;
243     }
244 
245 
246     /++
247         The end point of the interval. It is excluded from the interval.
248 
249         Params:
250             timePoint = The time point to set end to.
251 
252         Throws:
253             $(REF DateTimeException,std,datetime,date) if the resulting
254             interval would be invalid.
255       +/
256     @property void end(TP timePoint) pure
257     {
258         if (!_valid(_begin, timePoint))
259             throw new DateTimeException("Arguments would result in an invalid Interval.");
260         _end = timePoint;
261     }
262 
263 
264     /++
265         Returns the duration between `begin` and `end`.
266 
267         Example:
268         --------------------
269         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).length ==
270                dur!"days"(5903));
271         --------------------
272       +/
273     @property auto length() const pure nothrow
274     {
275         return _end - _begin;
276     }
277 
278 
279     /++
280         Whether the interval's length is 0, that is, whether $(D begin == end).
281 
282         Example:
283         --------------------
284         assert(Interval!Date(Date(1996, 1, 2), Date(1996, 1, 2)).empty);
285         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).empty);
286         --------------------
287       +/
288     @property bool empty() const pure nothrow
289     {
290         return _begin == _end;
291     }
292 
293 
294     /++
295         Whether the given time point is within this interval.
296 
297         Params:
298             timePoint = The time point to check for inclusion in this interval.
299 
300         Throws:
301             $(REF DateTimeException,std,datetime,date) if this interval is
302             empty.
303 
304         Example:
305         --------------------
306         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
307                     Date(1994, 12, 24)));
308 
309         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
310                     Date(2000, 1, 5)));
311         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
312                     Date(2012, 3, 1)));
313         --------------------
314       +/
315     bool contains(scope const TP timePoint) const pure
316     {
317         _enforceNotEmpty();
318         return timePoint >= _begin && timePoint < _end;
319     }
320 
321 
322     /++
323         Whether the given interval is completely within this interval.
324 
325         Params:
326             interval = The interval to check for inclusion in this interval.
327 
328         Throws:
329             $(REF DateTimeException,std,datetime,date) if either interval is
330             empty.
331 
332         Example:
333         --------------------
334         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
335                     Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
336 
337         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
338                     Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
339 
340         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
341                     Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
342         --------------------
343       +/
344     bool contains(scope const Interval interval) const pure
345     {
346         _enforceNotEmpty();
347         interval._enforceNotEmpty();
348         return interval._begin >= _begin &&
349                interval._begin < _end &&
350                interval._end <= _end;
351     }
352 
353 
354     /++
355         Whether the given interval is completely within this interval.
356 
357         Always returns false (unless this interval is empty), because an
358         interval going to positive infinity can never be contained in a finite
359         interval.
360 
361         Params:
362             interval = The interval to check for inclusion in this interval.
363 
364         Throws:
365             $(REF DateTimeException,std,datetime,date) if this interval is
366             empty.
367 
368         Example:
369         --------------------
370         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
371                     PosInfInterval!Date(Date(1999, 5, 4))));
372         --------------------
373       +/
374     bool contains(scope const PosInfInterval!TP interval) const pure
375     {
376         _enforceNotEmpty();
377         return false;
378     }
379 
380 
381     /++
382         Whether the given interval is completely within this interval.
383 
384         Always returns false (unless this interval is empty), because an
385         interval beginning at negative infinity can never be contained in a
386         finite interval.
387 
388         Params:
389             interval = The interval to check for inclusion in this interval.
390 
391         Throws:
392             $(REF DateTimeException,std,datetime,date) if this interval is
393             empty.
394 
395         Example:
396         --------------------
397         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
398                     NegInfInterval!Date(Date(1996, 5, 4))));
399         --------------------
400       +/
401     bool contains(scope const NegInfInterval!TP interval) const pure
402     {
403         _enforceNotEmpty();
404         return false;
405     }
406 
407 
408     /++
409         Whether this interval is before the given time point.
410 
411         Params:
412             timePoint = The time point to check whether this interval is before
413                         it.
414 
415         Throws:
416             $(REF DateTimeException,std,datetime,date) if this interval is
417             empty.
418 
419         Example:
420         --------------------
421         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
422                     Date(1994, 12, 24)));
423 
424         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
425                     Date(2000, 1, 5)));
426 
427         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
428                     Date(2012, 3, 1)));
429         --------------------
430       +/
431     bool isBefore(scope const TP timePoint) const pure
432     {
433         _enforceNotEmpty();
434         return _end <= timePoint;
435     }
436 
437 
438     /++
439         Whether this interval is before the given interval and does not
440         intersect with it.
441 
442         Params:
443             interval = The interval to check for against this interval.
444 
445         Throws:
446             $(REF DateTimeException,std,datetime,date) if either interval is
447             empty.
448 
449         Example:
450         --------------------
451         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
452                     Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
453 
454         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
455                     Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
456 
457         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
458                     Interval!Date(Date(2012, 3, 1), Date(2013, 5, 1))));
459         --------------------
460       +/
461     bool isBefore(scope const Interval interval) const pure
462     {
463         _enforceNotEmpty();
464         interval._enforceNotEmpty();
465         return _end <= interval._begin;
466     }
467 
468 
469     /++
470         Whether this interval is before the given interval and does not
471         intersect with it.
472 
473         Params:
474             interval = The interval to check for against this interval.
475 
476         Throws:
477             $(REF DateTimeException,std,datetime,date) if this interval is
478             empty.
479 
480         Example:
481         --------------------
482         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
483                     PosInfInterval!Date(Date(1999, 5, 4))));
484 
485         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
486                     PosInfInterval!Date(Date(2013, 3, 7))));
487         --------------------
488       +/
489     bool isBefore(scope const PosInfInterval!TP interval) const pure
490     {
491         _enforceNotEmpty();
492         return _end <= interval._begin;
493     }
494 
495 
496     /++
497         Whether this interval is before the given interval and does not
498         intersect with it.
499 
500         Always returns false (unless this interval is empty) because a finite
501         interval can never be before an interval beginning at negative infinity.
502 
503         Params:
504             interval = The interval to check for against this interval.
505 
506         Throws:
507             $(REF DateTimeException,std,datetime,date) if this interval is
508             empty.
509 
510         Example:
511         --------------------
512         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
513                     NegInfInterval!Date(Date(1996, 5, 4))));
514         --------------------
515       +/
516     bool isBefore(scope const NegInfInterval!TP interval) const pure
517     {
518         _enforceNotEmpty();
519         return false;
520     }
521 
522 
523     /++
524         Whether this interval is after the given time point.
525 
526         Params:
527             timePoint = The time point to check whether this interval is after
528                         it.
529 
530         Throws:
531             $(REF DateTimeException,std,datetime,date) if this interval is
532             empty.
533 
534         Example:
535         --------------------
536         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
537                     Date(1994, 12, 24)));
538 
539         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
540                     Date(2000, 1, 5)));
541 
542         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
543                     Date(2012, 3, 1)));
544         --------------------
545       +/
546     bool isAfter(scope const TP timePoint) const pure
547     {
548         _enforceNotEmpty();
549         return timePoint < _begin;
550     }
551 
552 
553     /++
554         Whether this interval is after the given interval and does not intersect
555         it.
556 
557         Params:
558             interval = The interval to check against this interval.
559 
560         Throws:
561             $(REF DateTimeException,std,datetime,date) if either interval is
562             empty.
563 
564         Example:
565         --------------------
566         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
567                     Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
568 
569         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
570                     Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
571 
572         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
573                     Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
574         --------------------
575       +/
576     bool isAfter(scope const Interval interval) const pure
577     {
578         _enforceNotEmpty();
579         interval._enforceNotEmpty();
580         return _begin >= interval._end;
581     }
582 
583 
584     /++
585         Whether this interval is after the given interval and does not intersect
586         it.
587 
588         Always returns false (unless this interval is empty) because a finite
589         interval can never be after an interval going to positive infinity.
590 
591         Params:
592             interval = The interval to check against this interval.
593 
594         Throws:
595             $(REF DateTimeException,std,datetime,date) if this interval is
596             empty.
597 
598         Example:
599         --------------------
600         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
601                     PosInfInterval!Date(Date(1999, 5, 4))));
602         --------------------
603       +/
604     bool isAfter(scope const PosInfInterval!TP interval) const pure
605     {
606         _enforceNotEmpty();
607         return false;
608     }
609 
610 
611     /++
612         Whether this interval is after the given interval and does not intersect
613         it.
614 
615         Params:
616             interval = The interval to check against this interval.
617 
618         Throws:
619             $(REF DateTimeException,std,datetime,date) if this interval is
620             empty.
621 
622         Example:
623         --------------------
624         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
625                     NegInfInterval!Date(Date(1996, 1, 2))));
626         --------------------
627       +/
628     bool isAfter(scope const NegInfInterval!TP interval) const pure
629     {
630         _enforceNotEmpty();
631         return _begin >= interval._end;
632     }
633 
634 
635     /++
636         Whether the given interval overlaps this interval.
637 
638         Params:
639             interval = The interval to check for intersection with this interval.
640 
641         Throws:
642             $(REF DateTimeException,std,datetime,date) if either interval is
643             empty.
644 
645         Example:
646         --------------------
647         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(
648                     Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
649 
650         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(
651                     Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
652 
653         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(
654                     Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
655         --------------------
656       +/
657     bool intersects(scope const Interval interval) const pure
658     {
659         _enforceNotEmpty();
660         interval._enforceNotEmpty();
661         return interval._begin < _end && interval._end > _begin;
662     }
663 
664 
665     /++
666         Whether the given interval overlaps this interval.
667 
668         Params:
669             interval = The interval to check for intersection with this interval.
670 
671         Throws:
672             $(REF DateTimeException,std,datetime,date) if this interval is
673             empty.
674 
675         Example:
676         --------------------
677         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(
678                     PosInfInterval!Date(Date(1999, 5, 4))));
679 
680         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(
681                     PosInfInterval!Date(Date(2012, 3, 1))));
682         --------------------
683       +/
684     bool intersects(scope const PosInfInterval!TP interval) const pure
685     {
686         _enforceNotEmpty();
687         return _end > interval._begin;
688     }
689 
690 
691     /++
692         Whether the given interval overlaps this interval.
693 
694         Params:
695             interval = The interval to check for intersection with this interval.
696 
697         Throws:
698             $(REF DateTimeException,std,datetime,date) if this interval is
699             empty.
700 
701         Example:
702         --------------------
703         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(
704                     NegInfInterval!Date(Date(1996, 1, 2))));
705 
706         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(
707                     NegInfInterval!Date(Date(2000, 1, 2))));
708         --------------------
709       +/
710     bool intersects(scope const NegInfInterval!TP interval) const pure
711     {
712         _enforceNotEmpty();
713         return _begin < interval._end;
714     }
715 
716 
717     /++
718         Returns the intersection of two intervals
719 
720         Params:
721             interval = The interval to intersect with this interval.
722 
723         Throws:
724             $(REF DateTimeException,std,datetime,date) if the two intervals do
725             not intersect or if either interval is empty.
726 
727         Example:
728         --------------------
729         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
730                     Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
731                Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2)));
732 
733         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
734                     Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) ==
735                Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17)));
736         --------------------
737       +/
738     Interval intersection(scope const Interval interval) const
739     {
740         import std.format : format;
741 
742         enforce(this.intersects(interval),
743                 new DateTimeException(format("%s and %s do not intersect.", this, interval)));
744 
745         auto begin = _begin > interval._begin ? _begin : interval._begin;
746         auto end = _end < interval._end ? _end : interval._end;
747 
748         return Interval(begin, end);
749     }
750 
751 
752     /++
753         Returns the intersection of two intervals
754 
755         Params:
756             interval = The interval to intersect with this interval.
757 
758         Throws:
759             $(REF DateTimeException,std,datetime,date) if the two intervals do
760             not intersect or if this interval is empty.
761 
762         Example:
763         --------------------
764         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
765                     PosInfInterval!Date(Date(1990, 7, 6))) ==
766                Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1)));
767 
768         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
769                     PosInfInterval!Date(Date(1999, 1, 12))) ==
770                Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1)));
771         --------------------
772       +/
773     Interval intersection(scope const PosInfInterval!TP interval) const
774     {
775         import std.format : format;
776 
777         enforce(this.intersects(interval),
778                 new DateTimeException(format("%s and %s do not intersect.", this, interval)));
779 
780         return Interval(_begin > interval._begin ? _begin : interval._begin, _end);
781     }
782 
783 
784     /++
785         Returns the intersection of two intervals
786 
787         Params:
788             interval = The interval to intersect with this interval.
789 
790         Throws:
791             $(REF DateTimeException,std,datetime,date) if the two intervals do
792             not intersect or if this interval is empty.
793 
794         Example:
795         --------------------
796         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
797                     NegInfInterval!Date(Date(1999, 7, 6))) ==
798                Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6)));
799 
800         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
801                     NegInfInterval!Date(Date(2013, 1, 12))) ==
802                Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1)));
803         --------------------
804       +/
805     Interval intersection(scope const NegInfInterval!TP interval) const
806     {
807         import std.format : format;
808 
809         enforce(this.intersects(interval),
810                 new DateTimeException(format("%s and %s do not intersect.", this, interval)));
811 
812         return Interval(_begin, _end < interval._end ? _end : interval._end);
813     }
814 
815 
816     /++
817         Whether the given interval is adjacent to this interval.
818 
819         Params:
820             interval = The interval to check whether its adjecent to this
821                        interval.
822 
823         Throws:
824             $(REF DateTimeException,std,datetime,date) if either interval is
825             empty.
826 
827         Example:
828         --------------------
829         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(
830                     Interval!Date(Date(1990, 7, 6), Date(1996, 1, 2))));
831 
832         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(
833                     Interval!Date(Date(2012, 3, 1), Date(2013, 9, 17))));
834 
835         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(
836                     Interval!Date(Date(1989, 3, 1), Date(2012, 3, 1))));
837         --------------------
838       +/
839     bool isAdjacent(scope const Interval interval) const pure
840     {
841         _enforceNotEmpty();
842         interval._enforceNotEmpty();
843         return _begin == interval._end || _end == interval._begin;
844     }
845 
846 
847     /++
848         Whether the given interval is adjacent to this interval.
849 
850         Params:
851             interval = The interval to check whether its adjecent to this
852                        interval.
853 
854         Throws:
855             $(REF DateTimeException,std,datetime,date) if this interval is
856             empty.
857 
858         Example:
859         --------------------
860         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(
861                     PosInfInterval!Date(Date(1999, 5, 4))));
862 
863         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(
864                     PosInfInterval!Date(Date(2012, 3, 1))));
865         --------------------
866       +/
867     bool isAdjacent(scope const PosInfInterval!TP interval) const pure
868     {
869         _enforceNotEmpty();
870         return _end == interval._begin;
871     }
872 
873 
874     /++
875         Whether the given interval is adjacent to this interval.
876 
877         Params:
878             interval = The interval to check whether its adjecent to this
879                        interval.
880 
881         Throws:
882             $(REF DateTimeException,std,datetime,date) if this interval is
883             empty.
884 
885         Example:
886         --------------------
887         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(
888                     NegInfInterval!Date(Date(1996, 1, 2))));
889 
890         assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(
891                     NegInfInterval!Date(Date(2000, 1, 2))));
892         --------------------
893       +/
894     bool isAdjacent(scope const NegInfInterval!TP interval) const pure
895     {
896         _enforceNotEmpty();
897         return _begin == interval._end;
898     }
899 
900 
901     /++
902         Returns the union of two intervals
903 
904         Params:
905             interval = The interval to merge with this interval.
906 
907         Throws:
908             $(REF DateTimeException,std,datetime,date) if the two intervals do
909             not intersect and are not adjacent or if either interval is empty.
910 
911         Example:
912         --------------------
913         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(
914                     Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
915                Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
916 
917         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(
918                     Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) ==
919                Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7)));
920         --------------------
921       +/
922     Interval merge(scope const Interval interval) const
923     {
924         import std.format : format;
925 
926         enforce(this.isAdjacent(interval) || this.intersects(interval),
927                 new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval)));
928 
929         auto begin = _begin < interval._begin ? _begin : interval._begin;
930         auto end = _end > interval._end ? _end : interval._end;
931 
932         return Interval(begin, end);
933     }
934 
935 
936     /++
937         Returns the union of two intervals
938 
939         Params:
940             interval = The interval to merge with this interval.
941 
942         Throws:
943             $(REF DateTimeException,std,datetime,date) if the two intervals do
944             not intersect and are not adjacent or if this interval is empty.
945 
946         Example:
947         --------------------
948         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(
949                     PosInfInterval!Date(Date(1990, 7, 6))) ==
950                PosInfInterval!Date(Date(1990, 7 , 6)));
951 
952         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(
953                     PosInfInterval!Date(Date(2012, 3, 1))) ==
954                PosInfInterval!Date(Date(1996, 1 , 2)));
955         --------------------
956       +/
957     PosInfInterval!TP merge(scope const PosInfInterval!TP interval) const
958     {
959         import std.format : format;
960 
961         enforce(this.isAdjacent(interval) || this.intersects(interval),
962                 new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval)));
963 
964         return PosInfInterval!TP(_begin < interval._begin ? _begin : interval._begin);
965     }
966 
967 
968     /++
969         Returns the union of two intervals
970 
971         Params:
972             interval = The interval to merge with this interval.
973 
974         Throws:
975             $(REF DateTimeException,std,datetime,date) if the two intervals do
976             not intersect and are not adjacent or if this interval is empty.
977 
978         Example:
979         --------------------
980         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(
981                     NegInfInterval!Date(Date(1996, 1, 2))) ==
982                NegInfInterval!Date(Date(2012, 3 , 1)));
983 
984         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(
985                     NegInfInterval!Date(Date(2013, 1, 12))) ==
986                NegInfInterval!Date(Date(2013, 1 , 12)));
987         --------------------
988       +/
989     NegInfInterval!TP merge(scope const NegInfInterval!TP interval) const
990     {
991         import std.format : format;
992 
993         enforce(this.isAdjacent(interval) || this.intersects(interval),
994                 new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval)));
995 
996         return NegInfInterval!TP(_end > interval._end ? _end : interval._end);
997     }
998 
999 
1000     /++
1001         Returns an interval that covers from the earliest time point of two
1002         intervals up to (but not including) the latest time point of two
1003         intervals.
1004 
1005         Params:
1006             interval = The interval to create a span together with this interval.
1007 
1008         Throws:
1009             $(REF DateTimeException,std,datetime,date) if either interval is
1010             empty.
1011 
1012         Example:
1013         --------------------
1014         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(
1015                     Interval!Date(Date(1990, 7, 6), Date(1991, 1, 8))) ==
1016                Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
1017 
1018         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(
1019                     Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) ==
1020                Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7)));
1021         --------------------
1022       +/
1023     Interval span(scope const Interval interval) const pure
1024     {
1025         _enforceNotEmpty();
1026         interval._enforceNotEmpty();
1027 
1028         auto begin = _begin < interval._begin ? _begin : interval._begin;
1029         auto end = _end > interval._end ? _end : interval._end;
1030 
1031         return Interval(begin, end);
1032     }
1033 
1034 
1035     /++
1036         Returns an interval that covers from the earliest time point of two
1037         intervals up to (but not including) the latest time point of two
1038         intervals.
1039 
1040         Params:
1041             interval = The interval to create a span together with this interval.
1042 
1043         Throws:
1044             $(REF DateTimeException,std,datetime,date) if this interval is
1045             empty.
1046 
1047         Example:
1048         --------------------
1049         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(
1050                     PosInfInterval!Date(Date(1990, 7, 6))) ==
1051                PosInfInterval!Date(Date(1990, 7 , 6)));
1052 
1053         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(
1054                     PosInfInterval!Date(Date(2050, 1, 1))) ==
1055                PosInfInterval!Date(Date(1996, 1 , 2)));
1056         --------------------
1057       +/
1058     PosInfInterval!TP span(scope const PosInfInterval!TP interval) const pure
1059     {
1060         _enforceNotEmpty();
1061         return PosInfInterval!TP(_begin < interval._begin ? _begin : interval._begin);
1062     }
1063 
1064 
1065     /++
1066         Returns an interval that covers from the earliest time point of two
1067         intervals up to (but not including) the latest time point of two
1068         intervals.
1069 
1070         Params:
1071             interval = The interval to create a span together with this interval.
1072 
1073         Throws:
1074             $(REF DateTimeException,std,datetime,date) if this interval is
1075             empty.
1076 
1077         Example:
1078         --------------------
1079         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(
1080                     NegInfInterval!Date(Date(1602, 5, 21))) ==
1081                NegInfInterval!Date(Date(2012, 3 , 1)));
1082 
1083         assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(
1084                     NegInfInterval!Date(Date(2013, 1, 12))) ==
1085                NegInfInterval!Date(Date(2013, 1 , 12)));
1086         --------------------
1087       +/
1088     NegInfInterval!TP span(scope const NegInfInterval!TP interval) const pure
1089     {
1090         _enforceNotEmpty();
1091         return NegInfInterval!TP(_end > interval._end ? _end : interval._end);
1092     }
1093 
1094 
1095     /++
1096         Shifts the interval forward or backwards in time by the given duration
1097         (a positive duration shifts the interval forward; a negative duration
1098         shifts it backward). Effectively, it does $(D begin += duration) and
1099         $(D end += duration).
1100 
1101         Params:
1102             duration = The duration to shift the interval by.
1103 
1104         Throws:
1105             $(REF DateTimeException,std,datetime,date) this interval is empty
1106             or if the resulting interval would be invalid.
1107 
1108         Example:
1109         --------------------
1110         auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5));
1111         auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5));
1112 
1113         interval1.shift(dur!"days"(50));
1114         assert(interval1 == Interval!Date(Date(1996, 2, 21), Date(2012, 5, 25)));
1115 
1116         interval2.shift(dur!"days"(-50));
1117         assert(interval2 == Interval!Date(Date(1995, 11, 13), Date(2012, 2, 15)));
1118         --------------------
1119       +/
1120     void shift(D)(D duration) pure
1121         if (__traits(compiles, begin + duration))
1122     {
1123         _enforceNotEmpty();
1124 
1125         auto begin = _begin + duration;
1126         auto end = _end + duration;
1127 
1128         if (!_valid(begin, end))
1129             throw new DateTimeException("Argument would result in an invalid Interval.");
1130 
1131         _begin = begin;
1132         _end = end;
1133     }
1134 
1135 
1136     static if (__traits(compiles, begin.add!"months"(1)) &&
1137                __traits(compiles, begin.add!"years"(1)))
1138     {
1139         /++
1140             Shifts the interval forward or backwards in time by the given number
1141             of years and/or months (a positive number of years and months shifts
1142             the interval forward; a negative number shifts it backward).
1143             It adds the years the given years and months to both begin and end.
1144             It effectively calls `add!"years"()` and then `add!"months"()`
1145             on begin and end with the given number of years and months.
1146 
1147             Params:
1148                 years         = The number of years to shift the interval by.
1149                 months        = The number of months to shift the interval by.
1150                 allowOverflow = Whether the days should be allowed to overflow
1151                                 on `begin` and `end`, causing their month
1152                                 to increment.
1153 
1154             Throws:
1155                 $(REF DateTimeException,std,datetime,date) if this interval is
1156                 empty or if the resulting interval would be invalid.
1157 
1158             Example:
1159             --------------------
1160             auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
1161             auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
1162 
1163             interval1.shift(2);
1164             assert(interval1 == Interval!Date(Date(1998, 1, 2), Date(2014, 3, 1)));
1165 
1166             interval2.shift(-2);
1167             assert(interval2 == Interval!Date(Date(1994, 1, 2), Date(2010, 3, 1)));
1168             --------------------
1169           +/
1170         void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
1171             if (isIntegral!T)
1172         {
1173             _enforceNotEmpty();
1174 
1175             auto begin = _begin;
1176             auto end = _end;
1177 
1178             begin.add!"years"(years, allowOverflow);
1179             begin.add!"months"(months, allowOverflow);
1180             end.add!"years"(years, allowOverflow);
1181             end.add!"months"(months, allowOverflow);
1182 
1183             enforce(_valid(begin, end), new DateTimeException("Argument would result in an invalid Interval."));
1184 
1185             _begin = begin;
1186             _end = end;
1187         }
1188     }
1189 
1190 
1191     /++
1192         Expands the interval forwards and/or backwards in time. Effectively,
1193         it does $(D begin -= duration) and/or $(D end += duration). Whether
1194         it expands forwards and/or backwards in time is determined by
1195         $(D_PARAM dir).
1196 
1197         Params:
1198             duration = The duration to expand the interval by.
1199             dir      = The direction in time to expand the interval.
1200 
1201         Throws:
1202             $(REF DateTimeException,std,datetime,date) this interval is empty
1203             or if the resulting interval would be invalid.
1204 
1205         Example:
1206         --------------------
1207         auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
1208         auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
1209 
1210         interval1.expand(2);
1211         assert(interval1 == Interval!Date(Date(1994, 1, 2), Date(2014, 3, 1)));
1212 
1213         interval2.expand(-2);
1214         assert(interval2 == Interval!Date(Date(1998, 1, 2), Date(2010, 3, 1)));
1215         --------------------
1216       +/
1217     void expand(D)(D duration, Direction dir = Direction.both) pure
1218         if (__traits(compiles, begin + duration))
1219     {
1220         _enforceNotEmpty();
1221 
1222         switch (dir)
1223         {
1224             case Direction.both:
1225             {
1226                 auto begin = _begin - duration;
1227                 auto end = _end + duration;
1228 
1229                 if (!_valid(begin, end))
1230                     throw new DateTimeException("Argument would result in an invalid Interval.");
1231 
1232                 _begin = begin;
1233                 _end = end;
1234 
1235                 return;
1236             }
1237             case Direction.fwd:
1238             {
1239                 auto end = _end + duration;
1240 
1241                 if (!_valid(_begin, end))
1242                     throw new DateTimeException("Argument would result in an invalid Interval.");
1243                 _end = end;
1244 
1245                 return;
1246             }
1247             case Direction.bwd:
1248             {
1249                 auto begin = _begin - duration;
1250 
1251                 if (!_valid(begin, _end))
1252                     throw new DateTimeException("Argument would result in an invalid Interval.");
1253                 _begin = begin;
1254 
1255                 return;
1256             }
1257             default:
1258                 assert(0, "Invalid Direction.");
1259         }
1260     }
1261 
1262     static if (__traits(compiles, begin.add!"months"(1)) &&
1263                __traits(compiles, begin.add!"years"(1)))
1264     {
1265         /++
1266             Expands the interval forwards and/or backwards in time. Effectively,
1267             it subtracts the given number of months/years from `begin` and
1268             adds them to `end`. Whether it expands forwards and/or backwards
1269             in time is determined by $(D_PARAM dir).
1270 
1271             Params:
1272                 years         = The number of years to expand the interval by.
1273                 months        = The number of months to expand the interval by.
1274                 allowOverflow = Whether the days should be allowed to overflow
1275                                 on `begin` and `end`, causing their month
1276                                 to increment.
1277                 dir           = The direction in time to expand the interval.
1278 
1279             Throws:
1280                 $(REF DateTimeException,std,datetime,date) if this interval is
1281                 empty or if the resulting interval would be invalid.
1282 
1283             Example:
1284             --------------------
1285             auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
1286             auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
1287 
1288             interval1.expand(2);
1289             assert(interval1 == Interval!Date(Date(1994, 1, 2), Date(2014, 3, 1)));
1290 
1291             interval2.expand(-2);
1292             assert(interval2 == Interval!Date(Date(1998, 1, 2), Date(2010, 3, 1)));
1293             --------------------
1294           +/
1295         void expand(T)(T years,
1296                        T months = 0,
1297                        AllowDayOverflow allowOverflow = AllowDayOverflow.yes,
1298                        Direction dir = Direction.both)
1299         if (isIntegral!T)
1300         {
1301             _enforceNotEmpty();
1302 
1303             switch (dir)
1304             {
1305                 case Direction.both:
1306                 {
1307                     auto begin = _begin;
1308                     auto end = _end;
1309 
1310                     begin.add!"years"(-years, allowOverflow);
1311                     begin.add!"months"(-months, allowOverflow);
1312                     end.add!"years"(years, allowOverflow);
1313                     end.add!"months"(months, allowOverflow);
1314 
1315                     enforce(_valid(begin, end), new DateTimeException("Argument would result in an invalid Interval."));
1316                     _begin = begin;
1317                     _end = end;
1318 
1319                     return;
1320                 }
1321                 case Direction.fwd:
1322                 {
1323                     auto end = _end;
1324 
1325                     end.add!"years"(years, allowOverflow);
1326                     end.add!"months"(months, allowOverflow);
1327 
1328                     enforce(_valid(_begin, end),
1329                             new DateTimeException("Argument would result in an invalid Interval."));
1330                     _end = end;
1331 
1332                     return;
1333                 }
1334                 case Direction.bwd:
1335                 {
1336                     auto begin = _begin;
1337 
1338                     begin.add!"years"(-years, allowOverflow);
1339                     begin.add!"months"(-months, allowOverflow);
1340 
1341                     enforce(_valid(begin, _end),
1342                             new DateTimeException("Argument would result in an invalid Interval."));
1343                     _begin = begin;
1344 
1345                     return;
1346                 }
1347                 default:
1348                     assert(0, "Invalid Direction.");
1349             }
1350         }
1351     }
1352 
1353 
1354     /++
1355         Returns a range which iterates forward over the interval, starting
1356         at `begin`, using $(D_PARAM func) to generate each successive time
1357         point.
1358 
1359         The range's `front` is the interval's `begin`. $(D_PARAM func) is
1360         used to generate the next `front` when `popFront` is called. If
1361         $(D_PARAM popFirst) is `PopFirst.yes`, then `popFront` is called
1362         before the range is returned (so that `front` is a time point which
1363         $(D_PARAM func) would generate).
1364 
1365         If $(D_PARAM func) ever generates a time point less than or equal to the
1366         current `front` of the range, then a
1367         $(REF DateTimeException,std,datetime,date) will be thrown. The range
1368         will be empty and iteration complete when $(D_PARAM func) generates a
1369         time point equal to or beyond the `end` of the interval.
1370 
1371         There are helper functions in this module which generate common
1372         delegates to pass to `fwdRange`. Their documentation starts with
1373         "Range-generating function," making them easily searchable.
1374 
1375         Params:
1376             func     = The function used to generate the time points of the
1377                        range over the interval.
1378             popFirst = Whether `popFront` should be called on the range
1379                        before returning it.
1380 
1381         Throws:
1382             $(REF DateTimeException,std,datetime,date) if this interval is
1383             empty.
1384 
1385         Warning:
1386             $(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func)
1387             would be a function pointer to a pure function, but forcing
1388             $(D_PARAM func) to be pure is far too restrictive to be useful, and
1389             in order to have the ease of use of having functions which generate
1390             functions to pass to `fwdRange`, $(D_PARAM func) must be a
1391             delegate.
1392 
1393             If $(D_PARAM func) retains state which changes as it is called, then
1394             some algorithms will not work correctly, because the range's
1395             `save` will have failed to have really saved the range's state.
1396             To avoid such bugs, don't pass a delegate which is
1397             not logically pure to `fwdRange`. If $(D_PARAM func) is given the
1398             same time point with two different calls, it must return the same
1399             result both times.
1400 
1401             Of course, none of the functions in this module have this problem,
1402             so it's only relevant if when creating a custom delegate.
1403 
1404         Example:
1405         --------------------
1406         auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9));
1407         auto func = delegate (scope const Date date) // For iterating over even-numbered days.
1408                     {
1409                         if ((date.day & 1) == 0)
1410                             return date + dur!"days"(2);
1411 
1412                         return date + dur!"days"(1);
1413                     };
1414         auto range = interval.fwdRange(func);
1415 
1416         // An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2).
1417         assert(range.front == Date(2010, 9, 1));
1418 
1419         range.popFront();
1420         assert(range.front == Date(2010, 9, 2));
1421 
1422         range.popFront();
1423         assert(range.front == Date(2010, 9, 4));
1424 
1425         range.popFront();
1426         assert(range.front == Date(2010, 9, 6));
1427 
1428         range.popFront();
1429         assert(range.front == Date(2010, 9, 8));
1430 
1431         range.popFront();
1432         assert(range.empty);
1433         --------------------
1434       +/
1435     IntervalRange!(TP, Direction.fwd) fwdRange(TP delegate(scope const TP) func, PopFirst popFirst = PopFirst.no) const
1436     {
1437         _enforceNotEmpty();
1438 
1439         auto range = IntervalRange!(TP, Direction.fwd)(this, func);
1440 
1441         if (popFirst == PopFirst.yes)
1442             range.popFront();
1443 
1444         return range;
1445     }
1446 
1447 
1448     /++
1449         Returns a range which iterates backwards over the interval, starting
1450         at `end`, using $(D_PARAM func) to generate each successive time
1451         point.
1452 
1453         The range's `front` is the interval's `end`. $(D_PARAM func) is
1454         used to generate the next `front` when `popFront` is called. If
1455         $(D_PARAM popFirst) is `PopFirst.yes`, then `popFront` is called
1456         before the range is returned (so that `front` is a time point which
1457         $(D_PARAM func) would generate).
1458 
1459         If $(D_PARAM func) ever generates a time point greater than or equal to
1460         the current `front` of the range, then a
1461         $(REF DateTimeException,std,datetime,date) will be thrown. The range
1462         will be empty and iteration complete when $(D_PARAM func) generates a
1463         time point equal to or less than the `begin` of the interval.
1464 
1465         There are helper functions in this module which generate common
1466         delegates to pass to `bwdRange`. Their documentation starts with
1467         "Range-generating function," making them easily searchable.
1468 
1469         Params:
1470             func     = The function used to generate the time points of the
1471                        range over the interval.
1472             popFirst = Whether `popFront` should be called on the range
1473                        before returning it.
1474 
1475         Throws:
1476             $(REF DateTimeException,std,datetime,date) if this interval is
1477             empty.
1478 
1479         Warning:
1480             $(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func)
1481             would be a function pointer to a pure function, but forcing
1482             $(D_PARAM func) to be pure is far too restrictive to be useful, and
1483             in order to have the ease of use of having functions which generate
1484             functions to pass to `fwdRange`, $(D_PARAM func) must be a
1485             delegate.
1486 
1487             If $(D_PARAM func) retains state which changes as it is called, then
1488             some algorithms will not work correctly, because the range's
1489             `save` will have failed to have really saved the range's state.
1490             To avoid such bugs, don't pass a delegate which is
1491             not logically pure to `fwdRange`. If $(D_PARAM func) is given the
1492             same time point with two different calls, it must return the same
1493             result both times.
1494 
1495             Of course, none of the functions in this module have this problem,
1496             so it's only relevant for custom delegates.
1497 
1498         Example:
1499         --------------------
1500         auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9));
1501         auto func = delegate (scope const Date date) // For iterating over even-numbered days.
1502                     {
1503                         if ((date.day & 1) == 0)
1504                             return date - dur!"days"(2);
1505 
1506                         return date - dur!"days"(1);
1507                     };
1508         auto range = interval.bwdRange(func);
1509 
1510         // An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8).
1511         assert(range.front == Date(2010, 9, 9));
1512 
1513         range.popFront();
1514         assert(range.front == Date(2010, 9, 8));
1515 
1516         range.popFront();
1517         assert(range.front == Date(2010, 9, 6));
1518 
1519         range.popFront();
1520         assert(range.front == Date(2010, 9, 4));
1521 
1522         range.popFront();
1523         assert(range.front == Date(2010, 9, 2));
1524 
1525         range.popFront();
1526         assert(range.empty);
1527         --------------------
1528       +/
1529     IntervalRange!(TP, Direction.bwd) bwdRange(TP delegate(scope const TP) func, PopFirst popFirst = PopFirst.no) const
1530     {
1531         _enforceNotEmpty();
1532 
1533         auto range = IntervalRange!(TP, Direction.bwd)(this, func);
1534 
1535         if (popFirst == PopFirst.yes)
1536             range.popFront();
1537 
1538         return range;
1539     }
1540 
1541     /++
1542         Converts this interval to a string.
1543         Params:
1544             w = A `char` accepting
1545             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
1546         Returns:
1547             A `string` when not using an output range; `void` otherwise.
1548       +/
1549     string toString() const @safe nothrow
1550     {
1551         import std.array : appender;
1552         auto app = appender!string();
1553         try
1554             toString(app);
1555         catch (Exception e)
1556             assert(0, "toString() threw.");
1557         return app.data;
1558     }
1559 
1560     /// ditto
1561     void toString(Writer)(ref Writer w) const
1562     if (isOutputRange!(Writer, char))
1563     {
1564         import std.range.primitives : put;
1565         put(w, '[');
1566         _begin.toString(w);
1567         put(w, " - ");
1568         _end.toString(w);
1569         put(w, ')');
1570     }
1571 
1572 private:
1573     /+
1574         Throws:
1575             $(REF DateTimeException,std,datetime,date) if this interval is
1576             empty.
1577       +/
1578     void _enforceNotEmpty(size_t line = __LINE__) const pure
1579     {
1580         if (empty)
1581             throw new DateTimeException("Invalid operation for an empty Interval.", __FILE__, line);
1582     }
1583 
1584 
1585     /+
1586         Whether the given values form a valid time interval.
1587 
1588         Params:
1589             begin = The starting point of the interval.
1590             end   = The end point of the interval.
1591      +/
1592     static bool _valid(scope const TP begin, scope const TP end) pure nothrow @trusted
1593     {
1594         return begin <= end;
1595     }
1596 
1597 
1598     pure invariant()
1599     {
1600         assert(_valid(_begin, _end), "Invariant Failure: begin is not before or equal to end.");
1601     }
1602 
1603 
1604     TP _begin;
1605     TP _end;
1606 }
1607 
1608 // Test Interval's constructors.
1609 @safe unittest
1610 {
1611     import std.datetime.date;
1612     import std.datetime.systime;
1613 
1614     assertThrown!DateTimeException(Interval!Date(Date(2010, 1, 1), Date(1, 1, 1)));
1615 
1616     Interval!Date(Date.init, Date.init);
1617     Interval!TimeOfDay(TimeOfDay.init, TimeOfDay.init);
1618     Interval!DateTime(DateTime.init, DateTime.init);
1619     Interval!SysTime(SysTime(0), SysTime(0));
1620 
1621     Interval!DateTime(DateTime.init, dur!"days"(7));
1622 
1623     // Verify Examples.
1624     Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
1625     assert(Interval!Date(Date(1996, 1, 2), dur!"weeks"(3)) == Interval!Date(Date(1996, 1, 2), Date(1996, 1, 23)));
1626     assert(Interval!Date(Date(1996, 1, 2), dur!"days"(3)) == Interval!Date(Date(1996, 1, 2), Date(1996, 1, 5)));
1627     assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"hours"(3)) ==
1628            Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 15, 0, 0)));
1629     assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"minutes"(3)) ==
1630            Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 12, 3, 0)));
1631     assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"seconds"(3)) ==
1632            Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 12, 0, 3)));
1633     assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"msecs"(3000)) ==
1634            Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 12, 0, 3)));
1635 }
1636 
1637 // Test Interval's begin.
1638 @safe unittest
1639 {
1640     import std.datetime.date;
1641 
1642     assert(Interval!Date(Date(1, 1, 1), Date(2010, 1, 1)).begin == Date(1, 1, 1));
1643     assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).begin == Date(2010, 1, 1));
1644     assert(Interval!Date(Date(1997, 12, 31), Date(1998, 1, 1)).begin == Date(1997, 12, 31));
1645 
1646     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1647     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1648     assert(cInterval.begin == Date(2010, 7, 4));
1649     assert(iInterval.begin == Date(2010, 7, 4));
1650 
1651     // Verify Examples.
1652     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).begin == Date(1996, 1, 2));
1653 }
1654 
1655 // Test Interval's end.
1656 @safe unittest
1657 {
1658     import std.datetime.date;
1659 
1660     assert(Interval!Date(Date(1, 1, 1), Date(2010, 1, 1)).end == Date(2010, 1, 1));
1661     assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).end == Date(2010, 1, 1));
1662     assert(Interval!Date(Date(1997, 12, 31), Date(1998, 1, 1)).end == Date(1998, 1, 1));
1663 
1664     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1665     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1666     assert(cInterval.end == Date(2012, 1, 7));
1667     assert(iInterval.end == Date(2012, 1, 7));
1668 
1669     // Verify Examples.
1670     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).end == Date(2012, 3, 1));
1671 }
1672 
1673 // Test Interval's length.
1674 @safe unittest
1675 {
1676     import std.datetime.date;
1677     import std.datetime.systime;
1678 
1679     assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).length == dur!"days"(0));
1680     assert(Interval!Date(Date(2010, 1, 1), Date(2010, 4, 1)).length == dur!"days"(90));
1681     assert(Interval!TimeOfDay(TimeOfDay(0, 30, 0), TimeOfDay(12, 22, 7)).length == dur!"seconds"(42_727));
1682     assert(Interval!DateTime(DateTime(2010, 1, 1, 0, 30, 0), DateTime(2010, 1, 2, 12, 22, 7)).length ==
1683            dur!"seconds"(129_127));
1684     assert(Interval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0)),SysTime(DateTime(2010, 1, 2, 12, 22, 7))).length ==
1685            dur!"seconds"(129_127));
1686 
1687     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1688     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1689     assert(cInterval.length != Duration.zero);
1690     assert(iInterval.length != Duration.zero);
1691 
1692     // Verify Examples.
1693     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).length == dur!"days"(5903));
1694 }
1695 
1696 // Test Interval's empty.
1697 @safe unittest
1698 {
1699     import std.datetime.date;
1700     import std.datetime.systime;
1701 
1702     assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).empty);
1703     assert(!Interval!Date(Date(2010, 1, 1), Date(2010, 4, 1)).empty);
1704     assert(!Interval!TimeOfDay(TimeOfDay(0, 30, 0), TimeOfDay(12, 22, 7)).empty);
1705     assert(!Interval!DateTime(DateTime(2010, 1, 1, 0, 30, 0), DateTime(2010, 1, 2, 12, 22, 7)).empty);
1706     assert(!Interval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0)), SysTime(DateTime(2010, 1, 2, 12, 22, 7))).empty);
1707 
1708     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1709     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1710     assert(!cInterval.empty);
1711     assert(!iInterval.empty);
1712 
1713     // Verify Examples.
1714     assert(Interval!Date(Date(1996, 1, 2), Date(1996, 1, 2)).empty);
1715     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).empty);
1716 }
1717 
1718 // Test Interval's contains(time point).
1719 @safe unittest
1720 {
1721     import std.datetime.date;
1722 
1723     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1724 
1725     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).contains(Date(2010, 7, 4)));
1726 
1727     assert(!interval.contains(Date(2009, 7, 4)));
1728     assert(!interval.contains(Date(2010, 7, 3)));
1729     assert(interval.contains(Date(2010, 7, 4)));
1730     assert(interval.contains(Date(2010, 7, 5)));
1731     assert(interval.contains(Date(2011, 7, 1)));
1732     assert(interval.contains(Date(2012, 1, 6)));
1733     assert(!interval.contains(Date(2012, 1, 7)));
1734     assert(!interval.contains(Date(2012, 1, 8)));
1735     assert(!interval.contains(Date(2013, 1, 7)));
1736 
1737     const cdate = Date(2010, 7, 6);
1738     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1739     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1740     assert(interval.contains(cdate));
1741     assert(cInterval.contains(cdate));
1742     assert(iInterval.contains(cdate));
1743 
1744     // Verify Examples.
1745     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(1994, 12, 24)));
1746     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(2000, 1, 5)));
1747     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(2012, 3, 1)));
1748 }
1749 
1750 // Test Interval's contains(Interval).
1751 @safe unittest
1752 {
1753     import std.datetime.date;
1754 
1755     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1756 
1757     assertThrown!DateTimeException(interval.contains(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
1758     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).contains(interval));
1759     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4),dur!"days"(0)).contains(
1760                                        Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
1761 
1762     assert(interval.contains(interval));
1763     assert(!interval.contains(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
1764     assert(!interval.contains(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
1765     assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
1766     assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
1767     assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
1768     assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
1769     assert(interval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
1770     assert(interval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
1771     assert(interval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
1772     assert(!interval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
1773     assert(!interval.contains(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
1774     assert(!interval.contains(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
1775 
1776     assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).contains(interval));
1777     assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).contains(interval));
1778     assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).contains(interval));
1779     assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).contains(interval));
1780     assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).contains(interval));
1781     assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).contains(interval));
1782     assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).contains(interval));
1783     assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).contains(interval));
1784     assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).contains(interval));
1785     assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).contains(interval));
1786     assert(!Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).contains(interval));
1787     assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).contains(interval));
1788 
1789     assert(!interval.contains(PosInfInterval!Date(Date(2010, 7, 3))));
1790     assert(!interval.contains(PosInfInterval!Date(Date(2010, 7, 4))));
1791     assert(!interval.contains(PosInfInterval!Date(Date(2010, 7, 5))));
1792     assert(!interval.contains(PosInfInterval!Date(Date(2012, 1, 6))));
1793     assert(!interval.contains(PosInfInterval!Date(Date(2012, 1, 7))));
1794     assert(!interval.contains(PosInfInterval!Date(Date(2012, 1, 8))));
1795 
1796     assert(!interval.contains(NegInfInterval!Date(Date(2010, 7, 3))));
1797     assert(!interval.contains(NegInfInterval!Date(Date(2010, 7, 4))));
1798     assert(!interval.contains(NegInfInterval!Date(Date(2010, 7, 5))));
1799     assert(!interval.contains(NegInfInterval!Date(Date(2012, 1, 6))));
1800     assert(!interval.contains(NegInfInterval!Date(Date(2012, 1, 7))));
1801     assert(!interval.contains(NegInfInterval!Date(Date(2012, 1, 8))));
1802 
1803     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1804     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1805     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
1806     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
1807     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
1808     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
1809     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
1810     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
1811     assert(interval.contains(interval));
1812     assert(interval.contains(cInterval));
1813     assert(interval.contains(iInterval));
1814     assert(!interval.contains(posInfInterval));
1815     assert(!interval.contains(cPosInfInterval));
1816     assert(!interval.contains(iPosInfInterval));
1817     assert(!interval.contains(negInfInterval));
1818     assert(!interval.contains(cNegInfInterval));
1819     assert(!interval.contains(iNegInfInterval));
1820     assert(cInterval.contains(interval));
1821     assert(cInterval.contains(cInterval));
1822     assert(cInterval.contains(iInterval));
1823     assert(!cInterval.contains(posInfInterval));
1824     assert(!cInterval.contains(cPosInfInterval));
1825     assert(!cInterval.contains(iPosInfInterval));
1826     assert(!cInterval.contains(negInfInterval));
1827     assert(!cInterval.contains(cNegInfInterval));
1828     assert(!cInterval.contains(iNegInfInterval));
1829     assert(iInterval.contains(interval));
1830     assert(iInterval.contains(cInterval));
1831     assert(iInterval.contains(iInterval));
1832     assert(!iInterval.contains(posInfInterval));
1833     assert(!iInterval.contains(cPosInfInterval));
1834     assert(!iInterval.contains(iPosInfInterval));
1835     assert(!iInterval.contains(negInfInterval));
1836     assert(!iInterval.contains(cNegInfInterval));
1837     assert(!iInterval.contains(iNegInfInterval));
1838 
1839     // Verify Examples.
1840     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
1841                Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
1842     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
1843                Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
1844     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
1845                Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
1846 
1847     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(PosInfInterval!Date(Date(1999, 5, 4))));
1848 
1849     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(1996, 5, 4))));
1850 }
1851 
1852 // Test Interval's isBefore(time point).
1853 @safe unittest
1854 {
1855     import std.datetime.date;
1856 
1857     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1858 
1859     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isBefore(Date(2010, 7, 4)));
1860 
1861     assert(!interval.isBefore(Date(2009, 7, 3)));
1862     assert(!interval.isBefore(Date(2010, 7, 3)));
1863     assert(!interval.isBefore(Date(2010, 7, 4)));
1864     assert(!interval.isBefore(Date(2010, 7, 5)));
1865     assert(!interval.isBefore(Date(2011, 7, 1)));
1866     assert(!interval.isBefore(Date(2012, 1, 6)));
1867     assert(interval.isBefore(Date(2012, 1, 7)));
1868     assert(interval.isBefore(Date(2012, 1, 8)));
1869     assert(interval.isBefore(Date(2013, 1, 7)));
1870 
1871     const cdate = Date(2010, 7, 6);
1872     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1873     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1874     assert(!interval.isBefore(cdate));
1875     assert(!cInterval.isBefore(cdate));
1876     assert(!iInterval.isBefore(cdate));
1877 
1878     // Verify Examples.
1879     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(1994, 12, 24)));
1880     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(2000, 1, 5)));
1881     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(2012, 3, 1)));
1882 }
1883 
1884 // Test Interval's isBefore(Interval).
1885 @safe unittest
1886 {
1887     import std.datetime.date;
1888 
1889     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1890 
1891     assertThrown!DateTimeException(interval.isBefore(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
1892     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isBefore(interval));
1893     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isBefore(
1894                                        Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
1895 
1896     assert(!interval.isBefore(interval));
1897     assert(!interval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
1898     assert(!interval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
1899     assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
1900     assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
1901     assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
1902     assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
1903     assert(!interval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
1904     assert(!interval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
1905     assert(!interval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
1906     assert(!interval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
1907     assert(interval.isBefore(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
1908     assert(interval.isBefore(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
1909 
1910     assert(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).isBefore(interval));
1911     assert(!Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).isBefore(interval));
1912     assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).isBefore(interval));
1913     assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).isBefore(interval));
1914     assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).isBefore(interval));
1915     assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).isBefore(interval));
1916     assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).isBefore(interval));
1917     assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).isBefore(interval));
1918     assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).isBefore(interval));
1919     assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).isBefore(interval));
1920     assert(!Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).isBefore(interval));
1921     assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).isBefore(interval));
1922 
1923     assert(!interval.isBefore(PosInfInterval!Date(Date(2010, 7, 3))));
1924     assert(!interval.isBefore(PosInfInterval!Date(Date(2010, 7, 4))));
1925     assert(!interval.isBefore(PosInfInterval!Date(Date(2010, 7, 5))));
1926     assert(!interval.isBefore(PosInfInterval!Date(Date(2012, 1, 6))));
1927     assert(interval.isBefore(PosInfInterval!Date(Date(2012, 1, 7))));
1928     assert(interval.isBefore(PosInfInterval!Date(Date(2012, 1, 8))));
1929 
1930     assert(!interval.isBefore(NegInfInterval!Date(Date(2010, 7, 3))));
1931     assert(!interval.isBefore(NegInfInterval!Date(Date(2010, 7, 4))));
1932     assert(!interval.isBefore(NegInfInterval!Date(Date(2010, 7, 5))));
1933     assert(!interval.isBefore(NegInfInterval!Date(Date(2012, 1, 6))));
1934     assert(!interval.isBefore(NegInfInterval!Date(Date(2012, 1, 7))));
1935     assert(!interval.isBefore(NegInfInterval!Date(Date(2012, 1, 8))));
1936 
1937     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1938     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1939     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
1940     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
1941     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
1942     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
1943     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
1944     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
1945     assert(!interval.isBefore(interval));
1946     assert(!interval.isBefore(cInterval));
1947     assert(!interval.isBefore(iInterval));
1948     assert(!interval.isBefore(posInfInterval));
1949     assert(!interval.isBefore(cPosInfInterval));
1950     assert(!interval.isBefore(iPosInfInterval));
1951     assert(!interval.isBefore(negInfInterval));
1952     assert(!interval.isBefore(cNegInfInterval));
1953     assert(!interval.isBefore(iNegInfInterval));
1954     assert(!cInterval.isBefore(interval));
1955     assert(!cInterval.isBefore(cInterval));
1956     assert(!cInterval.isBefore(iInterval));
1957     assert(!cInterval.isBefore(posInfInterval));
1958     assert(!cInterval.isBefore(cPosInfInterval));
1959     assert(!cInterval.isBefore(iPosInfInterval));
1960     assert(!cInterval.isBefore(negInfInterval));
1961     assert(!cInterval.isBefore(cNegInfInterval));
1962     assert(!cInterval.isBefore(iNegInfInterval));
1963     assert(!iInterval.isBefore(interval));
1964     assert(!iInterval.isBefore(cInterval));
1965     assert(!iInterval.isBefore(iInterval));
1966     assert(!iInterval.isBefore(posInfInterval));
1967     assert(!iInterval.isBefore(cPosInfInterval));
1968     assert(!iInterval.isBefore(iPosInfInterval));
1969     assert(!iInterval.isBefore(negInfInterval));
1970     assert(!iInterval.isBefore(cNegInfInterval));
1971     assert(!iInterval.isBefore(iNegInfInterval));
1972 
1973     // Verify Examples.
1974     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
1975                Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
1976     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
1977                Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
1978     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
1979                Interval!Date(Date(2012, 3, 1), Date(2013, 5, 1))));
1980 
1981     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(1999, 5, 4))));
1982     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(2013, 3, 7))));
1983 
1984     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(1996, 5, 4))));
1985 }
1986 
1987 // Test Interval's isAfter(time point).
1988 @safe unittest
1989 {
1990     import std.datetime.date;
1991 
1992     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
1993 
1994     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isAfter(Date(2010, 7, 4)));
1995 
1996     assert(interval.isAfter(Date(2009, 7, 4)));
1997     assert(interval.isAfter(Date(2010, 7, 3)));
1998     assert(!interval.isAfter(Date(2010, 7, 4)));
1999     assert(!interval.isAfter(Date(2010, 7, 5)));
2000     assert(!interval.isAfter(Date(2011, 7, 1)));
2001     assert(!interval.isAfter(Date(2012, 1, 6)));
2002     assert(!interval.isAfter(Date(2012, 1, 7)));
2003     assert(!interval.isAfter(Date(2012, 1, 8)));
2004     assert(!interval.isAfter(Date(2013, 1, 7)));
2005 
2006     const cdate = Date(2010, 7, 6);
2007     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2008     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2009     assert(!interval.isAfter(cdate));
2010     assert(!cInterval.isAfter(cdate));
2011     assert(!iInterval.isAfter(cdate));
2012 
2013     // Verify Examples.
2014     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(1994, 12, 24)));
2015     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(2000, 1, 5)));
2016     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(2012, 3, 1)));
2017 }
2018 
2019 // Test Interval's isAfter(Interval).
2020 @safe unittest
2021 {
2022     import std.datetime.date;
2023 
2024     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2025 
2026     assertThrown!DateTimeException(interval.isAfter(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2027     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isAfter(interval));
2028     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isAfter(
2029                                        Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2030 
2031     assert(!interval.isAfter(interval));
2032     assert(interval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
2033     assert(!interval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
2034     assert(interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
2035     assert(!interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
2036     assert(!interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
2037     assert(!interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
2038     assert(!interval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
2039     assert(!interval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
2040     assert(!interval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
2041     assert(!interval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
2042     assert(!interval.isAfter(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
2043     assert(!interval.isAfter(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
2044 
2045     assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).isAfter(interval));
2046     assert(!Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).isAfter(interval));
2047     assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).isAfter(interval));
2048     assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).isAfter(interval));
2049     assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).isAfter(interval));
2050     assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).isAfter(interval));
2051     assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).isAfter(interval));
2052     assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).isAfter(interval));
2053     assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).isAfter(interval));
2054     assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).isAfter(interval));
2055     assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).isAfter(interval));
2056     assert(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).isAfter(interval));
2057 
2058     assert(!interval.isAfter(PosInfInterval!Date(Date(2010, 7, 3))));
2059     assert(!interval.isAfter(PosInfInterval!Date(Date(2010, 7, 4))));
2060     assert(!interval.isAfter(PosInfInterval!Date(Date(2010, 7, 5))));
2061     assert(!interval.isAfter(PosInfInterval!Date(Date(2012, 1, 6))));
2062     assert(!interval.isAfter(PosInfInterval!Date(Date(2012, 1, 7))));
2063     assert(!interval.isAfter(PosInfInterval!Date(Date(2012, 1, 8))));
2064 
2065     assert(interval.isAfter(NegInfInterval!Date(Date(2010, 7, 3))));
2066     assert(interval.isAfter(NegInfInterval!Date(Date(2010, 7, 4))));
2067     assert(!interval.isAfter(NegInfInterval!Date(Date(2010, 7, 5))));
2068     assert(!interval.isAfter(NegInfInterval!Date(Date(2012, 1, 6))));
2069     assert(!interval.isAfter(NegInfInterval!Date(Date(2012, 1, 7))));
2070     assert(!interval.isAfter(NegInfInterval!Date(Date(2012, 1, 8))));
2071 
2072     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2073     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2074     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2075     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2076     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2077     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2078     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2079     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2080     assert(!interval.isAfter(interval));
2081     assert(!interval.isAfter(cInterval));
2082     assert(!interval.isAfter(iInterval));
2083     assert(!interval.isAfter(posInfInterval));
2084     assert(!interval.isAfter(cPosInfInterval));
2085     assert(!interval.isAfter(iPosInfInterval));
2086     assert(!interval.isAfter(negInfInterval));
2087     assert(!interval.isAfter(cNegInfInterval));
2088     assert(!interval.isAfter(iNegInfInterval));
2089     assert(!cInterval.isAfter(interval));
2090     assert(!cInterval.isAfter(cInterval));
2091     assert(!cInterval.isAfter(iInterval));
2092     assert(!cInterval.isAfter(posInfInterval));
2093     assert(!cInterval.isAfter(cPosInfInterval));
2094     assert(!cInterval.isAfter(iPosInfInterval));
2095     assert(!cInterval.isAfter(negInfInterval));
2096     assert(!cInterval.isAfter(cNegInfInterval));
2097     assert(!cInterval.isAfter(iNegInfInterval));
2098     assert(!iInterval.isAfter(interval));
2099     assert(!iInterval.isAfter(cInterval));
2100     assert(!iInterval.isAfter(iInterval));
2101     assert(!iInterval.isAfter(posInfInterval));
2102     assert(!iInterval.isAfter(cPosInfInterval));
2103     assert(!iInterval.isAfter(iPosInfInterval));
2104     assert(!iInterval.isAfter(negInfInterval));
2105     assert(!iInterval.isAfter(cNegInfInterval));
2106     assert(!iInterval.isAfter(iNegInfInterval));
2107 
2108     // Verify Examples.
2109     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
2110                Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
2111     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
2112                Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
2113     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
2114                Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
2115 
2116     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(1999, 5, 4))));
2117 
2118     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(1996, 1, 2))));
2119 }
2120 
2121 // Test Interval's intersects().
2122 @safe unittest
2123 {
2124     import std.datetime.date;
2125 
2126     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2127 
2128     assertThrown!DateTimeException(interval.intersects(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2129     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersects(interval));
2130     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersects(
2131                                        Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2132 
2133     assert(interval.intersects(interval));
2134     assert(!interval.intersects(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
2135     assert(interval.intersects(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
2136     assert(!interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
2137     assert(interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
2138     assert(interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
2139     assert(interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
2140     assert(interval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
2141     assert(interval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
2142     assert(interval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
2143     assert(interval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
2144     assert(!interval.intersects(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
2145     assert(!interval.intersects(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
2146 
2147     assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).intersects(interval));
2148     assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).intersects(interval));
2149     assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).intersects(interval));
2150     assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).intersects(interval));
2151     assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).intersects(interval));
2152     assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).intersects(interval));
2153     assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).intersects(interval));
2154     assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).intersects(interval));
2155     assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).intersects(interval));
2156     assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).intersects(interval));
2157     assert(!Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).intersects(interval));
2158     assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).intersects(interval));
2159 
2160     assert(interval.intersects(PosInfInterval!Date(Date(2010, 7, 3))));
2161     assert(interval.intersects(PosInfInterval!Date(Date(2010, 7, 4))));
2162     assert(interval.intersects(PosInfInterval!Date(Date(2010, 7, 5))));
2163     assert(interval.intersects(PosInfInterval!Date(Date(2012, 1, 6))));
2164     assert(!interval.intersects(PosInfInterval!Date(Date(2012, 1, 7))));
2165     assert(!interval.intersects(PosInfInterval!Date(Date(2012, 1, 8))));
2166 
2167     assert(!interval.intersects(NegInfInterval!Date(Date(2010, 7, 3))));
2168     assert(!interval.intersects(NegInfInterval!Date(Date(2010, 7, 4))));
2169     assert(interval.intersects(NegInfInterval!Date(Date(2010, 7, 5))));
2170     assert(interval.intersects(NegInfInterval!Date(Date(2012, 1, 6))));
2171     assert(interval.intersects(NegInfInterval!Date(Date(2012, 1, 7))));
2172     assert(interval.intersects(NegInfInterval!Date(Date(2012, 1, 8))));
2173 
2174     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2175     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2176     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2177     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2178     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2179     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2180     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2181     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2182     assert(interval.intersects(interval));
2183     assert(interval.intersects(cInterval));
2184     assert(interval.intersects(iInterval));
2185     assert(interval.intersects(posInfInterval));
2186     assert(interval.intersects(cPosInfInterval));
2187     assert(interval.intersects(iPosInfInterval));
2188     assert(interval.intersects(negInfInterval));
2189     assert(interval.intersects(cNegInfInterval));
2190     assert(interval.intersects(iNegInfInterval));
2191     assert(cInterval.intersects(interval));
2192     assert(cInterval.intersects(cInterval));
2193     assert(cInterval.intersects(iInterval));
2194     assert(cInterval.intersects(posInfInterval));
2195     assert(cInterval.intersects(cPosInfInterval));
2196     assert(cInterval.intersects(iPosInfInterval));
2197     assert(cInterval.intersects(negInfInterval));
2198     assert(cInterval.intersects(cNegInfInterval));
2199     assert(cInterval.intersects(iNegInfInterval));
2200     assert(iInterval.intersects(interval));
2201     assert(iInterval.intersects(cInterval));
2202     assert(iInterval.intersects(iInterval));
2203     assert(iInterval.intersects(posInfInterval));
2204     assert(iInterval.intersects(cPosInfInterval));
2205     assert(iInterval.intersects(iPosInfInterval));
2206     assert(iInterval.intersects(negInfInterval));
2207     assert(iInterval.intersects(cNegInfInterval));
2208     assert(iInterval.intersects(iNegInfInterval));
2209 
2210     // Verify Examples.
2211     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(
2212                Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
2213     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(
2214                Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
2215     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(
2216                Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
2217 
2218     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(1999, 5, 4))));
2219     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(2012, 3, 1))));
2220 
2221     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(1996, 1, 2))));
2222     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(2000, 1, 2))));
2223 }
2224 
2225 // Test Interval's intersection().
2226 @safe unittest
2227 {
2228     import std.datetime.date;
2229 
2230     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2231 
2232     assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2233     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersection(interval));
2234     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersection(
2235                                        Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2236 
2237     assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
2238     assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
2239     assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
2240     assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
2241 
2242     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).intersection(interval));
2243     assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).intersection(interval));
2244     assertThrown!DateTimeException(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).intersection(interval));
2245     assertThrown!DateTimeException(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).intersection(interval));
2246 
2247     assertThrown!DateTimeException(interval.intersection(PosInfInterval!Date(Date(2012, 1, 7))));
2248     assertThrown!DateTimeException(interval.intersection(PosInfInterval!Date(Date(2012, 1, 8))));
2249 
2250     assertThrown!DateTimeException(interval.intersection(NegInfInterval!Date(Date(2010, 7, 3))));
2251     assertThrown!DateTimeException(interval.intersection(NegInfInterval!Date(Date(2010, 7, 4))));
2252 
2253     assert(interval.intersection(interval) == interval);
2254     assert(interval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
2255            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2256     assert(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
2257            Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
2258     assert(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
2259            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2260     assert(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
2261            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2262     assert(interval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
2263            Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
2264     assert(interval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
2265            Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
2266     assert(interval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
2267            Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
2268     assert(interval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
2269            Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
2270 
2271     assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).intersection(interval) ==
2272            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2273     assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).intersection(interval) ==
2274            Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
2275     assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).intersection(interval) ==
2276            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2277     assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).intersection(interval) ==
2278            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2279     assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).intersection(interval) ==
2280            Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
2281     assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).intersection(interval) ==
2282            Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
2283     assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).intersection(interval) ==
2284            Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
2285     assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).intersection(interval) ==
2286            Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
2287 
2288     assert(interval.intersection(PosInfInterval!Date(Date(2010, 7, 3))) ==
2289            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2290     assert(interval.intersection(PosInfInterval!Date(Date(2010, 7, 4))) ==
2291            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2292     assert(interval.intersection(PosInfInterval!Date(Date(2010, 7, 5))) ==
2293            Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
2294     assert(interval.intersection(PosInfInterval!Date(Date(2012, 1, 6))) ==
2295            Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
2296 
2297     assert(interval.intersection(NegInfInterval!Date(Date(2010, 7, 5))) ==
2298            Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
2299     assert(interval.intersection(NegInfInterval!Date(Date(2012, 1, 6))) ==
2300            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 6)));
2301     assert(interval.intersection(NegInfInterval!Date(Date(2012, 1, 7))) ==
2302            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2303     assert(interval.intersection(NegInfInterval!Date(Date(2012, 1, 8))) ==
2304            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2305 
2306     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2307     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2308     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2309     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2310     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2311     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2312     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2313     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2314     assert(!interval.intersection(interval).empty);
2315     assert(!interval.intersection(cInterval).empty);
2316     assert(!interval.intersection(iInterval).empty);
2317     assert(!interval.intersection(posInfInterval).empty);
2318     assert(!interval.intersection(cPosInfInterval).empty);
2319     assert(!interval.intersection(iPosInfInterval).empty);
2320     assert(!interval.intersection(negInfInterval).empty);
2321     assert(!interval.intersection(cNegInfInterval).empty);
2322     assert(!interval.intersection(iNegInfInterval).empty);
2323     assert(!cInterval.intersection(interval).empty);
2324     assert(!cInterval.intersection(cInterval).empty);
2325     assert(!cInterval.intersection(iInterval).empty);
2326     assert(!cInterval.intersection(posInfInterval).empty);
2327     assert(!cInterval.intersection(cPosInfInterval).empty);
2328     assert(!cInterval.intersection(iPosInfInterval).empty);
2329     assert(!cInterval.intersection(negInfInterval).empty);
2330     assert(!cInterval.intersection(cNegInfInterval).empty);
2331     assert(!cInterval.intersection(iNegInfInterval).empty);
2332     assert(!iInterval.intersection(interval).empty);
2333     assert(!iInterval.intersection(cInterval).empty);
2334     assert(!iInterval.intersection(iInterval).empty);
2335     assert(!iInterval.intersection(posInfInterval).empty);
2336     assert(!iInterval.intersection(cPosInfInterval).empty);
2337     assert(!iInterval.intersection(iPosInfInterval).empty);
2338     assert(!iInterval.intersection(negInfInterval).empty);
2339     assert(!iInterval.intersection(cNegInfInterval).empty);
2340     assert(!iInterval.intersection(iNegInfInterval).empty);
2341 
2342     // Verify Examples.
2343     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
2344                Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
2345            Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2)));
2346     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
2347                Interval!Date(Date(1999, 1, 12),Date(2011, 9, 17))) ==
2348            Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17)));
2349 
2350     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
2351                PosInfInterval!Date(Date(1990, 7, 6))) ==
2352            Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1)));
2353     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
2354                PosInfInterval!Date(Date(1999, 1, 12))) ==
2355            Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1)));
2356 
2357     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
2358                NegInfInterval!Date(Date(1999, 7, 6))) ==
2359            Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6)));
2360     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(
2361                NegInfInterval!Date(Date(2013, 1, 12))) ==
2362            Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1)));
2363 }
2364 
2365 // Test Interval's isAdjacent().
2366 @safe unittest
2367 {
2368     import std.datetime.date;
2369 
2370     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2371 
2372     static void testInterval(scope const Interval!Date interval1, scope const Interval!Date interval2)
2373     {
2374         interval1.isAdjacent(interval2);
2375     }
2376 
2377     assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2378     assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), interval));
2379     assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)),
2380                                                 Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2381 
2382     assert(!interval.isAdjacent(interval));
2383     assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
2384     assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
2385     assert(interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
2386     assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
2387     assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
2388     assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
2389     assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
2390     assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
2391     assert(!interval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
2392     assert(!interval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
2393     assert(interval.isAdjacent(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
2394     assert(!interval.isAdjacent(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
2395 
2396     assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).isAdjacent(interval));
2397     assert(!Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).isAdjacent(interval));
2398     assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).isAdjacent(interval));
2399     assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).isAdjacent(interval));
2400     assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).isAdjacent(interval));
2401     assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).isAdjacent(interval));
2402     assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).isAdjacent(interval));
2403     assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).isAdjacent(interval));
2404     assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).isAdjacent(interval));
2405     assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).isAdjacent(interval));
2406     assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).isAdjacent(interval));
2407     assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).isAdjacent(interval));
2408 
2409     assert(!interval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 3))));
2410     assert(!interval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 4))));
2411     assert(!interval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 5))));
2412     assert(!interval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 6))));
2413     assert(interval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 7))));
2414     assert(!interval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 8))));
2415 
2416     assert(!interval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 3))));
2417     assert(interval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 4))));
2418     assert(!interval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 5))));
2419     assert(!interval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 6))));
2420     assert(!interval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 7))));
2421     assert(!interval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 8))));
2422 
2423     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2424     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2425     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2426     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2427     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2428     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2429     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2430     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2431     assert(!interval.isAdjacent(interval));
2432     assert(!interval.isAdjacent(cInterval));
2433     assert(!interval.isAdjacent(iInterval));
2434     assert(!interval.isAdjacent(posInfInterval));
2435     assert(!interval.isAdjacent(cPosInfInterval));
2436     assert(!interval.isAdjacent(iPosInfInterval));
2437     assert(!interval.isAdjacent(negInfInterval));
2438     assert(!interval.isAdjacent(cNegInfInterval));
2439     assert(!interval.isAdjacent(iNegInfInterval));
2440     assert(!cInterval.isAdjacent(interval));
2441     assert(!cInterval.isAdjacent(cInterval));
2442     assert(!cInterval.isAdjacent(iInterval));
2443     assert(!cInterval.isAdjacent(posInfInterval));
2444     assert(!cInterval.isAdjacent(cPosInfInterval));
2445     assert(!cInterval.isAdjacent(iPosInfInterval));
2446     assert(!cInterval.isAdjacent(negInfInterval));
2447     assert(!cInterval.isAdjacent(cNegInfInterval));
2448     assert(!cInterval.isAdjacent(iNegInfInterval));
2449     assert(!iInterval.isAdjacent(interval));
2450     assert(!iInterval.isAdjacent(cInterval));
2451     assert(!iInterval.isAdjacent(iInterval));
2452     assert(!iInterval.isAdjacent(posInfInterval));
2453     assert(!iInterval.isAdjacent(cPosInfInterval));
2454     assert(!iInterval.isAdjacent(iPosInfInterval));
2455     assert(!iInterval.isAdjacent(negInfInterval));
2456     assert(!iInterval.isAdjacent(cNegInfInterval));
2457     assert(!iInterval.isAdjacent(iNegInfInterval));
2458 
2459     // Verify Examples.
2460     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(
2461                Interval!Date(Date(1990, 7, 6), Date(1996, 1, 2))));
2462     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(
2463                Interval!Date(Date(2012, 3, 1), Date(2013, 9, 17))));
2464     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(
2465                Interval!Date(Date(1989, 3, 1), Date(2012, 3, 1))));
2466 
2467     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(1999, 5, 4))));
2468     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(2012, 3, 1))));
2469 
2470     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(1996, 1, 2))));
2471     assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)) .isAdjacent(NegInfInterval!Date(Date(2000, 1, 2))));
2472 }
2473 
2474 // Test Interval's merge().
2475 @safe unittest
2476 {
2477     import std.datetime.date;
2478 
2479     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2480 
2481     static void testInterval(I)(scope const Interval!Date interval1, scope const I interval2)
2482     {
2483         interval1.merge(interval2);
2484     }
2485 
2486     assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2487     assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), interval));
2488     assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)),
2489                                                 Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2490 
2491     assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
2492     assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
2493 
2494     assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)), interval));
2495     assertThrown!DateTimeException(testInterval(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)), interval));
2496 
2497     assertThrown!DateTimeException(testInterval(interval, PosInfInterval!Date(Date(2012, 1, 8))));
2498 
2499     assertThrown!DateTimeException(testInterval(interval, NegInfInterval!Date(Date(2010, 7, 3))));
2500 
2501     assert(interval.merge(interval) == interval);
2502     assert(interval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
2503            Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
2504     assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
2505            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2506     assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
2507            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2508     assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
2509            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2510     assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
2511            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
2512     assert(interval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
2513            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2514     assert(interval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
2515            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2516     assert(interval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
2517            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2518     assert(interval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
2519            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
2520     assert(interval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
2521            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
2522 
2523     assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).merge(interval) ==
2524            Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
2525     assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).merge(interval) ==
2526            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2527     assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).merge(interval) ==
2528            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2529     assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).merge(interval) ==
2530            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2531     assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).merge(interval) ==
2532            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
2533     assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).merge(interval) ==
2534            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2535     assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).merge(interval) ==
2536            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2537     assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).merge(interval) ==
2538            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2539     assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).merge(interval) ==
2540            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
2541     assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).merge(interval) ==
2542            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
2543 
2544     assert(interval.merge(PosInfInterval!Date(Date(2010, 7, 3))) ==
2545            PosInfInterval!Date(Date(2010, 7, 3)));
2546     assert(interval.merge(PosInfInterval!Date(Date(2010, 7, 4))) ==
2547            PosInfInterval!Date(Date(2010, 7, 4)));
2548     assert(interval.merge(PosInfInterval!Date(Date(2010, 7, 5))) ==
2549            PosInfInterval!Date(Date(2010, 7, 4)));
2550     assert(interval.merge(PosInfInterval!Date(Date(2012, 1, 6))) ==
2551            PosInfInterval!Date(Date(2010, 7, 4)));
2552     assert(interval.merge(PosInfInterval!Date(Date(2012, 1, 7))) ==
2553            PosInfInterval!Date(Date(2010, 7, 4)));
2554 
2555     assert(interval.merge(NegInfInterval!Date(Date(2010, 7, 4))) ==
2556            NegInfInterval!Date(Date(2012, 1, 7)));
2557     assert(interval.merge(NegInfInterval!Date(Date(2010, 7, 5))) ==
2558            NegInfInterval!Date(Date(2012, 1, 7)));
2559     assert(interval.merge(NegInfInterval!Date(Date(2012, 1, 6))) ==
2560            NegInfInterval!Date(Date(2012, 1, 7)));
2561     assert(interval.merge(NegInfInterval!Date(Date(2012, 1, 7))) ==
2562            NegInfInterval!Date(Date(2012, 1, 7)));
2563     assert(interval.merge(NegInfInterval!Date(Date(2012, 1, 8))) ==
2564            NegInfInterval!Date(Date(2012, 1, 8)));
2565 
2566     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2567     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2568     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2569     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2570     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2571     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2572     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2573     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2574     assert(!interval.merge(interval).empty);
2575     assert(!interval.merge(cInterval).empty);
2576     assert(!interval.merge(iInterval).empty);
2577     assert(!interval.merge(posInfInterval).empty);
2578     assert(!interval.merge(cPosInfInterval).empty);
2579     assert(!interval.merge(iPosInfInterval).empty);
2580     assert(!interval.merge(negInfInterval).empty);
2581     assert(!interval.merge(cNegInfInterval).empty);
2582     assert(!interval.merge(iNegInfInterval).empty);
2583     assert(!cInterval.merge(interval).empty);
2584     assert(!cInterval.merge(cInterval).empty);
2585     assert(!cInterval.merge(iInterval).empty);
2586     assert(!cInterval.merge(posInfInterval).empty);
2587     assert(!cInterval.merge(cPosInfInterval).empty);
2588     assert(!cInterval.merge(iPosInfInterval).empty);
2589     assert(!cInterval.merge(negInfInterval).empty);
2590     assert(!cInterval.merge(cNegInfInterval).empty);
2591     assert(!cInterval.merge(iNegInfInterval).empty);
2592     assert(!iInterval.merge(interval).empty);
2593     assert(!iInterval.merge(cInterval).empty);
2594     assert(!iInterval.merge(iInterval).empty);
2595     assert(!iInterval.merge(posInfInterval).empty);
2596     assert(!iInterval.merge(cPosInfInterval).empty);
2597     assert(!iInterval.merge(iPosInfInterval).empty);
2598     assert(!iInterval.merge(negInfInterval).empty);
2599     assert(!iInterval.merge(cNegInfInterval).empty);
2600     assert(!iInterval.merge(iNegInfInterval).empty);
2601 
2602     // Verify Examples.
2603     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
2604            Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
2605     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) ==
2606            Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7)));
2607 
2608     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(PosInfInterval!Date(Date(1990, 7, 6))) ==
2609            PosInfInterval!Date(Date(1990, 7 , 6)));
2610     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(PosInfInterval!Date(Date(2012, 3, 1))) ==
2611            PosInfInterval!Date(Date(1996, 1 , 2)));
2612 
2613     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(1996, 1, 2))) ==
2614            NegInfInterval!Date(Date(2012, 3 , 1)));
2615     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(2013, 1, 12))) ==
2616            NegInfInterval!Date(Date(2013, 1 , 12)));
2617 }
2618 
2619 // Test Interval's span().
2620 @safe unittest
2621 {
2622     import std.datetime.date;
2623 
2624     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2625 
2626     static void testInterval(scope const Interval!Date interval1, scope const Interval!Date interval2)
2627     {
2628         interval1.span(interval2);
2629     }
2630 
2631     assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2632     assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)),interval));
2633     assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)),
2634                                                 Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
2635 
2636     assert(interval.span(interval) == interval);
2637     assert(interval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) ==
2638            Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7)));
2639     assert(interval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
2640            Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
2641     assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
2642            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2643     assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
2644            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2645     assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
2646            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2647     assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
2648            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
2649     assert(interval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
2650            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2651     assert(interval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
2652            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2653     assert(interval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
2654            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2655     assert(interval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
2656            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
2657     assert(interval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
2658            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
2659     assert(interval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) ==
2660            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 9)));
2661 
2662     assert(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).span(interval) ==
2663            Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7)));
2664     assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).span(interval) ==
2665            Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
2666     assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).span(interval) ==
2667            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2668     assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).span(interval) ==
2669            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2670     assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).span(interval) ==
2671            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
2672     assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).span(interval) ==
2673            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
2674     assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).span(interval) ==
2675            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2676     assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).span(interval) ==
2677            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2678     assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).span(interval) ==
2679            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
2680     assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).span(interval) ==
2681            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
2682     assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).span(interval) ==
2683            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
2684     assert(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).span(interval) ==
2685            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 9)));
2686 
2687     assert(interval.span(PosInfInterval!Date(Date(2010, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 3)));
2688     assert(interval.span(PosInfInterval!Date(Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 4)));
2689     assert(interval.span(PosInfInterval!Date(Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 4)));
2690     assert(interval.span(PosInfInterval!Date(Date(2012, 1, 6))) == PosInfInterval!Date(Date(2010, 7, 4)));
2691     assert(interval.span(PosInfInterval!Date(Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4)));
2692     assert(interval.span(PosInfInterval!Date(Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 4)));
2693 
2694     assert(interval.span(NegInfInterval!Date(Date(2010, 7, 3))) == NegInfInterval!Date(Date(2012, 1, 7)));
2695     assert(interval.span(NegInfInterval!Date(Date(2010, 7, 4))) == NegInfInterval!Date(Date(2012, 1, 7)));
2696     assert(interval.span(NegInfInterval!Date(Date(2010, 7, 5))) == NegInfInterval!Date(Date(2012, 1, 7)));
2697     assert(interval.span(NegInfInterval!Date(Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 7)));
2698     assert(interval.span(NegInfInterval!Date(Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7)));
2699     assert(interval.span(NegInfInterval!Date(Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8)));
2700 
2701     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2702     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2703     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2704     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2705     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
2706     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2707     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2708     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
2709     assert(!interval.span(interval).empty);
2710     assert(!interval.span(cInterval).empty);
2711     assert(!interval.span(iInterval).empty);
2712     assert(!interval.span(posInfInterval).empty);
2713     assert(!interval.span(cPosInfInterval).empty);
2714     assert(!interval.span(iPosInfInterval).empty);
2715     assert(!interval.span(negInfInterval).empty);
2716     assert(!interval.span(cNegInfInterval).empty);
2717     assert(!interval.span(iNegInfInterval).empty);
2718     assert(!cInterval.span(interval).empty);
2719     assert(!cInterval.span(cInterval).empty);
2720     assert(!cInterval.span(iInterval).empty);
2721     assert(!cInterval.span(posInfInterval).empty);
2722     assert(!cInterval.span(cPosInfInterval).empty);
2723     assert(!cInterval.span(iPosInfInterval).empty);
2724     assert(!cInterval.span(negInfInterval).empty);
2725     assert(!cInterval.span(cNegInfInterval).empty);
2726     assert(!cInterval.span(iNegInfInterval).empty);
2727     assert(!iInterval.span(interval).empty);
2728     assert(!iInterval.span(cInterval).empty);
2729     assert(!iInterval.span(iInterval).empty);
2730     assert(!iInterval.span(posInfInterval).empty);
2731     assert(!iInterval.span(cPosInfInterval).empty);
2732     assert(!iInterval.span(iPosInfInterval).empty);
2733     assert(!iInterval.span(negInfInterval).empty);
2734     assert(!iInterval.span(cNegInfInterval).empty);
2735     assert(!iInterval.span(iNegInfInterval).empty);
2736 
2737     // Verify Examples.
2738     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(Interval!Date(Date(1990, 7, 6), Date(1991, 1, 8))) ==
2739            Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
2740     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) ==
2741            Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7)));
2742 
2743     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(PosInfInterval!Date(Date(1990, 7, 6))) ==
2744            PosInfInterval!Date(Date(1990, 7 , 6)));
2745     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(PosInfInterval!Date(Date(2050, 1, 1))) ==
2746            PosInfInterval!Date(Date(1996, 1 , 2)));
2747 
2748     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(NegInfInterval!Date(Date(1602, 5, 21))) ==
2749            NegInfInterval!Date(Date(2012, 3 , 1)));
2750     assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(NegInfInterval!Date(Date(2013, 1, 12))) ==
2751            NegInfInterval!Date(Date(2013, 1 , 12)));
2752 }
2753 
2754 // Test Interval's shift(duration).
2755 @safe unittest
2756 {
2757     import std.datetime.date;
2758 
2759     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2760 
2761     static void testIntervalFail(Interval!Date interval, scope const Duration duration)
2762     {
2763         interval.shift(duration);
2764     }
2765 
2766     assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), dur!"days"(1)));
2767 
2768     static void testInterval(I)(I interval, scope const Duration duration,
2769                                 scope const I expected, size_t line = __LINE__)
2770     {
2771         interval.shift(duration);
2772         assert(interval == expected);
2773     }
2774 
2775     testInterval(interval, dur!"days"(22), Interval!Date(Date(2010, 7, 26), Date(2012, 1, 29)));
2776     testInterval(interval, dur!"days"(-22), Interval!Date(Date(2010, 6, 12), Date(2011, 12, 16)));
2777 
2778     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2779     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2780     static assert(!__traits(compiles, cInterval.shift(dur!"days"(5))));
2781     static assert(!__traits(compiles, iInterval.shift(dur!"days"(5))));
2782 
2783     // Verify Examples.
2784     auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5));
2785     auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5));
2786 
2787     interval1.shift(dur!"days"(50));
2788     assert(interval1 == Interval!Date(Date(1996, 2, 21), Date(2012, 5, 25)));
2789 
2790     interval2.shift(dur!"days"(-50));
2791     assert(interval2 == Interval!Date(Date(1995, 11, 13), Date(2012, 2, 15)));
2792 }
2793 
2794 // Test Interval's shift(int, int, AllowDayOverflow).
2795 @safe unittest
2796 {
2797     import std.datetime.date;
2798 
2799     {
2800         auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2801 
2802         static void testIntervalFail(Interval!Date interval, int years, int months)
2803         {
2804             interval.shift(years, months);
2805         }
2806 
2807         assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), 1, 0));
2808 
2809         static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow,
2810                                     in I expected, size_t line = __LINE__)
2811         {
2812             interval.shift(years, months, allow);
2813             assert(interval == expected);
2814         }
2815 
2816         testInterval(interval, 5, 0, AllowDayOverflow.yes, Interval!Date(Date(2015, 7, 4), Date(2017, 1, 7)));
2817         testInterval(interval, -5, 0, AllowDayOverflow.yes, Interval!Date(Date(2005, 7, 4), Date(2007, 1, 7)));
2818 
2819         auto interval2 = Interval!Date(Date(2000, 1, 29), Date(2010, 5, 31));
2820 
2821         testInterval(interval2, 1, 1, AllowDayOverflow.yes, Interval!Date(Date(2001, 3, 1), Date(2011, 7, 1)));
2822         testInterval(interval2, 1, -1, AllowDayOverflow.yes, Interval!Date(Date(2000, 12, 29), Date(2011, 5, 1)));
2823         testInterval(interval2, -1, -1, AllowDayOverflow.yes, Interval!Date(Date(1998, 12, 29), Date(2009, 5, 1)));
2824         testInterval(interval2, -1, 1, AllowDayOverflow.yes, Interval!Date(Date(1999, 3, 1), Date(2009, 7, 1)));
2825 
2826         testInterval(interval2, 1, 1, AllowDayOverflow.no, Interval!Date(Date(2001, 2, 28), Date(2011, 6, 30)));
2827         testInterval(interval2, 1, -1, AllowDayOverflow.no, Interval!Date(Date(2000, 12, 29), Date(2011, 4, 30)));
2828         testInterval(interval2, -1, -1, AllowDayOverflow.no, Interval!Date(Date(1998, 12, 29), Date(2009, 4, 30)));
2829         testInterval(interval2, -1, 1, AllowDayOverflow.no, Interval!Date(Date(1999, 2, 28), Date(2009, 6, 30)));
2830     }
2831 
2832     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2833     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2834     static assert(!__traits(compiles, cInterval.shift(5)));
2835     static assert(!__traits(compiles, iInterval.shift(5)));
2836 
2837     // Verify Examples.
2838     auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
2839     auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
2840 
2841     interval1.shift(2);
2842     assert(interval1 == Interval!Date(Date(1998, 1, 2), Date(2014, 3, 1)));
2843 
2844     interval2.shift(-2);
2845     assert(interval2 == Interval!Date(Date(1994, 1, 2), Date(2010, 3, 1)));
2846 }
2847 
2848 // Test Interval's expand(Duration).
2849 @safe unittest
2850 {
2851     import std.datetime.date;
2852 
2853     auto interval = Interval!Date(Date(2000, 7, 4), Date(2012, 1, 7));
2854 
2855     static void testIntervalFail(I)(I interval, scope const Duration duration)
2856     {
2857         interval.expand(duration);
2858     }
2859 
2860     assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), dur!"days"(1)));
2861     assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)), dur!"days"(-5)));
2862 
2863     static void testInterval(I)(I interval, scope const Duration duration,
2864                                 scope const I expected, size_t line = __LINE__)
2865     {
2866         interval.expand(duration);
2867         assert(interval == expected);
2868     }
2869 
2870     testInterval(interval, dur!"days"(22), Interval!Date(Date(2000, 6, 12), Date(2012, 1, 29)));
2871     testInterval(interval, dur!"days"(-22), Interval!Date(Date(2000, 7, 26), Date(2011, 12, 16)));
2872 
2873     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2874     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2875     static assert(!__traits(compiles, cInterval.expand(dur!"days"(5))));
2876     static assert(!__traits(compiles, iInterval.expand(dur!"days"(5))));
2877 
2878     // Verify Examples.
2879     auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
2880     auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
2881 
2882     interval1.expand(dur!"days"(2));
2883     assert(interval1 == Interval!Date(Date(1995, 12, 31), Date(2012, 3, 3)));
2884 
2885     interval2.expand(dur!"days"(-2));
2886     assert(interval2 == Interval!Date(Date(1996, 1, 4), Date(2012, 2, 28)));
2887 }
2888 
2889 // Test Interval's expand(int, int, AllowDayOverflow, Direction)
2890 @safe unittest
2891 {
2892     import std.datetime.date;
2893 
2894     {
2895         auto interval = Interval!Date(Date(2000, 7, 4), Date(2012, 1, 7));
2896 
2897         static void testIntervalFail(Interval!Date interval, int years, int months)
2898         {
2899             interval.expand(years, months);
2900         }
2901 
2902         assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), 1, 0));
2903         assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)), -5, 0));
2904 
2905         static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, Direction dir,
2906                                     in I expected, size_t line = __LINE__)
2907         {
2908             interval.expand(years, months, allow, dir);
2909             assert(interval == expected);
2910         }
2911 
2912         testInterval(interval, 5, 0, AllowDayOverflow.yes, Direction.both,
2913                      Interval!Date(Date(1995, 7, 4), Date(2017, 1, 7)));
2914         testInterval(interval, -5, 0, AllowDayOverflow.yes, Direction.both,
2915                      Interval!Date(Date(2005, 7, 4), Date(2007, 1, 7)));
2916 
2917         testInterval(interval, 5, 0, AllowDayOverflow.yes, Direction.fwd,
2918                      Interval!Date(Date(2000, 7, 4), Date(2017, 1, 7)));
2919         testInterval(interval, -5, 0, AllowDayOverflow.yes, Direction.fwd,
2920                      Interval!Date(Date(2000, 7, 4), Date(2007, 1, 7)));
2921 
2922         testInterval(interval, 5, 0, AllowDayOverflow.yes, Direction.bwd,
2923                      Interval!Date(Date(1995, 7, 4), Date(2012, 1, 7)));
2924         testInterval(interval, -5, 0, AllowDayOverflow.yes, Direction.bwd,
2925                      Interval!Date(Date(2005, 7, 4), Date(2012, 1, 7)));
2926 
2927         auto interval2 = Interval!Date(Date(2000, 1, 29), Date(2010, 5, 31));
2928 
2929         testInterval(interval2, 1, 1, AllowDayOverflow.yes, Direction.both,
2930                      Interval!Date(Date(1998, 12, 29), Date(2011, 7, 1)));
2931         testInterval(interval2, 1, -1, AllowDayOverflow.yes, Direction.both,
2932                      Interval!Date(Date(1999, 3, 1), Date(2011, 5, 1)));
2933         testInterval(interval2, -1, -1, AllowDayOverflow.yes, Direction.both,
2934                      Interval!Date(Date(2001, 3, 1), Date(2009, 5, 1)));
2935         testInterval(interval2, -1, 1, AllowDayOverflow.yes, Direction.both,
2936                      Interval!Date(Date(2000, 12, 29), Date(2009, 7, 1)));
2937 
2938         testInterval(interval2, 1, 1, AllowDayOverflow.no, Direction.both,
2939                      Interval!Date(Date(1998, 12, 29), Date(2011, 6, 30)));
2940         testInterval(interval2, 1, -1, AllowDayOverflow.no, Direction.both,
2941                      Interval!Date(Date(1999, 2, 28), Date(2011, 4, 30)));
2942         testInterval(interval2, -1, -1, AllowDayOverflow.no, Direction.both,
2943                      Interval!Date(Date(2001, 2, 28), Date(2009, 4, 30)));
2944         testInterval(interval2, -1, 1, AllowDayOverflow.no, Direction.both,
2945                      Interval!Date(Date(2000, 12, 29), Date(2009, 6, 30)));
2946 
2947         testInterval(interval2, 1, 1, AllowDayOverflow.yes, Direction.fwd,
2948                      Interval!Date(Date(2000, 1, 29), Date(2011, 7, 1)));
2949         testInterval(interval2, 1, -1, AllowDayOverflow.yes, Direction.fwd,
2950                      Interval!Date(Date(2000, 1, 29), Date(2011, 5, 1)));
2951         testInterval(interval2, -1, -1, AllowDayOverflow.yes, Direction.fwd,
2952                      Interval!Date(Date(2000, 1, 29), Date(2009, 5, 1)));
2953         testInterval(interval2, -1, 1, AllowDayOverflow.yes, Direction.fwd,
2954                      Interval!Date(Date(2000, 1, 29), Date(2009, 7, 1)));
2955 
2956         testInterval(interval2, 1, 1, AllowDayOverflow.no, Direction.fwd,
2957                      Interval!Date(Date(2000, 1, 29), Date(2011, 6, 30)));
2958         testInterval(interval2, 1, -1, AllowDayOverflow.no, Direction.fwd,
2959                      Interval!Date(Date(2000, 1, 29), Date(2011, 4, 30)));
2960         testInterval(interval2, -1, -1, AllowDayOverflow.no, Direction.fwd,
2961                      Interval!Date(Date(2000, 1, 29), Date(2009, 4, 30)));
2962         testInterval(interval2, -1, 1, AllowDayOverflow.no, Direction.fwd,
2963                      Interval!Date(Date(2000, 1, 29), Date(2009, 6, 30)));
2964 
2965         testInterval(interval2, 1, 1, AllowDayOverflow.yes, Direction.bwd,
2966                      Interval!Date(Date(1998, 12, 29), Date(2010, 5, 31)));
2967         testInterval(interval2, 1, -1, AllowDayOverflow.yes, Direction.bwd,
2968                      Interval!Date(Date(1999, 3, 1), Date(2010, 5, 31)));
2969         testInterval(interval2, -1, -1, AllowDayOverflow.yes, Direction.bwd,
2970                      Interval!Date(Date(2001, 3, 1), Date(2010, 5, 31)));
2971         testInterval(interval2, -1, 1, AllowDayOverflow.yes, Direction.bwd,
2972                      Interval!Date(Date(2000, 12, 29), Date(2010, 5, 31)));
2973 
2974         testInterval(interval2, 1, 1, AllowDayOverflow.no, Direction.bwd,
2975                      Interval!Date(Date(1998, 12, 29), Date(2010, 5, 31)));
2976         testInterval(interval2, 1, -1, AllowDayOverflow.no, Direction.bwd,
2977                      Interval!Date(Date(1999, 2, 28), Date(2010, 5, 31)));
2978         testInterval(interval2, -1, -1, AllowDayOverflow.no, Direction.bwd,
2979                      Interval!Date(Date(2001, 2, 28), Date(2010, 5, 31)));
2980         testInterval(interval2, -1, 1, AllowDayOverflow.no, Direction.bwd,
2981                      Interval!Date(Date(2000, 12, 29), Date(2010, 5, 31)));
2982     }
2983 
2984     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2985     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
2986     static assert(!__traits(compiles, cInterval.expand(5)));
2987     static assert(!__traits(compiles, iInterval.expand(5)));
2988 
2989     // Verify Examples.
2990     auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
2991     auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
2992 
2993     interval1.expand(2);
2994     assert(interval1 == Interval!Date(Date(1994, 1, 2), Date(2014, 3, 1)));
2995 
2996     interval2.expand(-2);
2997     assert(interval2 == Interval!Date(Date(1998, 1, 2), Date(2010, 3, 1)));
2998 }
2999 
3000 // Test Interval's fwdRange.
3001 @system unittest
3002 {
3003     import std.datetime.date;
3004 
3005     {
3006         auto interval = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21));
3007 
3008         static void testInterval1(Interval!Date interval)
3009         {
3010             interval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
3011         }
3012 
3013         assertThrown!DateTimeException(testInterval1(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
3014 
3015         static void testInterval2(Interval!Date interval)
3016         {
3017             interval.fwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).popFront();
3018         }
3019 
3020         assertThrown!DateTimeException(testInterval2(interval));
3021 
3022         assert(!interval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty);
3023         assert(interval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri), PopFirst.yes).empty);
3024 
3025         assert(Interval!Date(Date(2010, 9, 12), Date(2010, 10, 1)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).front ==
3026                Date(2010, 9, 12));
3027 
3028         assert(Interval!Date(Date(2010, 9, 12), Date(2010, 10, 1)).fwdRange(
3029                    everyDayOfWeek!Date(DayOfWeek.fri), PopFirst.yes).front == Date(2010, 9, 17));
3030     }
3031 
3032     // Verify Examples.
3033     {
3034         auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9));
3035         auto func = delegate (scope const Date date)
3036                     {
3037                         if ((date.day & 1) == 0)
3038                             return date + dur!"days"(2);
3039                         return date + dur!"days"(1);
3040                     };
3041         auto range = interval.fwdRange(func);
3042 
3043         // An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2).
3044         assert(range.front == Date(2010, 9, 1));
3045 
3046         range.popFront();
3047         assert(range.front == Date(2010, 9, 2));
3048 
3049         range.popFront();
3050         assert(range.front == Date(2010, 9, 4));
3051 
3052         range.popFront();
3053         assert(range.front == Date(2010, 9, 6));
3054 
3055         range.popFront();
3056         assert(range.front == Date(2010, 9, 8));
3057 
3058         range.popFront();
3059         assert(range.empty);
3060     }
3061 
3062     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
3063     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
3064     assert(!cInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty);
3065     assert(!iInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty);
3066 }
3067 
3068 // Test Interval's bwdRange.
3069 @system unittest
3070 {
3071     import std.datetime.date;
3072 
3073     {
3074         auto interval = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21));
3075 
3076         static void testInterval1(Interval!Date interval)
3077         {
3078             interval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
3079         }
3080 
3081         assertThrown!DateTimeException(testInterval1(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
3082 
3083         static void testInterval2(Interval!Date interval)
3084         {
3085             interval.bwdRange(everyDayOfWeek!(Date, Direction.fwd)(DayOfWeek.fri)).popFront();
3086         }
3087 
3088         assertThrown!DateTimeException(testInterval2(interval));
3089 
3090         assert(!interval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).empty);
3091         assert(interval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri), PopFirst.yes).empty);
3092 
3093         assert(Interval!Date(Date(2010, 9, 19), Date(2010, 10, 1)).bwdRange(
3094                    everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).front == Date(2010, 10, 1));
3095 
3096         assert(Interval!Date(Date(2010, 9, 19), Date(2010, 10, 1)).bwdRange(
3097                    everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri), PopFirst.yes).front == Date(2010, 9, 24));
3098     }
3099 
3100     // Verify Examples.
3101     {
3102         auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9));
3103         auto func = delegate (scope const Date date)
3104                     {
3105                         if ((date.day & 1) == 0)
3106                             return date - dur!"days"(2);
3107                         return date - dur!"days"(1);
3108                     };
3109         auto range = interval.bwdRange(func);
3110 
3111         // An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8).
3112         assert(range.front == Date(2010, 9, 9));
3113 
3114         range.popFront();
3115         assert(range.front == Date(2010, 9, 8));
3116 
3117         range.popFront();
3118         assert(range.front == Date(2010, 9, 6));
3119 
3120         range.popFront();
3121         assert(range.front == Date(2010, 9, 4));
3122 
3123         range.popFront();
3124         assert(range.front == Date(2010, 9, 2));
3125 
3126         range.popFront();
3127         assert(range.empty);
3128     }
3129 
3130     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
3131     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
3132     assert(!cInterval.bwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty);
3133     assert(!iInterval.bwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty);
3134 }
3135 
3136 // Test Interval's toString().
3137 @safe unittest
3138 {
3139     import std.datetime.date;
3140 
3141     assert(Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).toString() == "[2010-Jul-04 - 2012-Jan-07)");
3142 
3143     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
3144     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
3145     assert(cInterval.toString());
3146     assert(iInterval.toString());
3147 }
3148 
3149 
3150 /++
3151     Represents an interval of time which has positive infinity as its end point.
3152 
3153     Any ranges which iterate over a `PosInfInterval` are infinite. So, the
3154     main purpose of using `PosInfInterval` is to create an infinite range
3155     which starts at a fixed point in time and goes to positive infinity.
3156   +/
3157 struct PosInfInterval(TP)
3158 {
3159 public:
3160 
3161     /++
3162         Params:
3163             begin = The time point which begins the interval.
3164 
3165         Example:
3166 --------------------
3167 auto interval = PosInfInterval!Date(Date(1996, 1, 2));
3168 --------------------
3169       +/
3170     this(scope const TP begin) pure nothrow
3171     {
3172         _begin = cast(TP) begin;
3173     }
3174 
3175 
3176     /++
3177         Params:
3178             rhs = The `PosInfInterval` to assign to this one.
3179       +/
3180     ref PosInfInterval opAssign(const ref PosInfInterval rhs) pure nothrow
3181     {
3182         _begin = cast(TP) rhs._begin;
3183         return this;
3184     }
3185 
3186 
3187     /++
3188         Params:
3189             rhs = The `PosInfInterval` to assign to this one.
3190       +/
3191     ref PosInfInterval opAssign(PosInfInterval rhs) pure nothrow
3192     {
3193         _begin = cast(TP) rhs._begin;
3194         return this;
3195     }
3196 
3197 
3198     /++
3199         The starting point of the interval. It is included in the interval.
3200 
3201         Example:
3202 --------------------
3203 assert(PosInfInterval!Date(Date(1996, 1, 2)).begin == Date(1996, 1, 2));
3204 --------------------
3205       +/
3206     @property TP begin() const pure nothrow
3207     {
3208         return cast(TP)_begin;
3209     }
3210 
3211 
3212     /++
3213         The starting point of the interval. It is included in the interval.
3214 
3215         Params:
3216             timePoint = The time point to set `begin` to.
3217       +/
3218     @property void begin(TP timePoint) pure nothrow
3219     {
3220         _begin = timePoint;
3221     }
3222 
3223 
3224     /++
3225         Whether the interval's length is 0. Always returns false.
3226 
3227         Example:
3228 --------------------
3229 assert(!PosInfInterval!Date(Date(1996, 1, 2)).empty);
3230 --------------------
3231       +/
3232     enum bool empty = false;
3233 
3234 
3235     /++
3236         Whether the given time point is within this interval.
3237 
3238         Params:
3239             timePoint = The time point to check for inclusion in this interval.
3240 
3241         Example:
3242 --------------------
3243 assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(1994, 12, 24)));
3244 assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(2000, 1, 5)));
3245 --------------------
3246       +/
3247     bool contains(TP timePoint) const pure nothrow
3248     {
3249         return timePoint >= _begin;
3250     }
3251 
3252 
3253     /++
3254         Whether the given interval is completely within this interval.
3255 
3256         Params:
3257             interval = The interval to check for inclusion in this interval.
3258 
3259         Throws:
3260             $(REF DateTimeException,std,datetime,date) if the given interval
3261             is empty.
3262 
3263         Example:
3264 --------------------
3265 assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(
3266             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
3267 
3268 assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(
3269             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
3270 
3271 assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(
3272             Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
3273 --------------------
3274       +/
3275     bool contains(scope const Interval!TP interval) const pure
3276     {
3277         interval._enforceNotEmpty();
3278         return interval._begin >= _begin;
3279     }
3280 
3281 
3282     /++
3283         Whether the given interval is completely within this interval.
3284 
3285         Params:
3286             interval = The interval to check for inclusion in this interval.
3287 
3288         Example:
3289 --------------------
3290 assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(
3291             PosInfInterval!Date(Date(1999, 5, 4))));
3292 
3293 assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(
3294             PosInfInterval!Date(Date(1995, 7, 2))));
3295 --------------------
3296       +/
3297     bool contains(scope const PosInfInterval interval) const pure nothrow
3298     {
3299         return interval._begin >= _begin;
3300     }
3301 
3302 
3303     /++
3304         Whether the given interval is completely within this interval.
3305 
3306         Always returns false because an interval going to positive infinity
3307         can never contain an interval beginning at negative infinity.
3308 
3309         Params:
3310             interval = The interval to check for inclusion in this interval.
3311 
3312         Example:
3313 --------------------
3314 assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(
3315             NegInfInterval!Date(Date(1996, 5, 4))));
3316 --------------------
3317       +/
3318     bool contains(scope const NegInfInterval!TP interval) const pure nothrow
3319     {
3320         return false;
3321     }
3322 
3323 
3324     /++
3325         Whether this interval is before the given time point.
3326 
3327         Always returns false because an interval going to positive infinity
3328         can never be before any time point.
3329 
3330         Params:
3331             timePoint = The time point to check whether this interval is before
3332                         it.
3333 
3334         Example:
3335 --------------------
3336 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(1994, 12, 24)));
3337 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(2000, 1, 5)));
3338 --------------------
3339       +/
3340     bool isBefore(scope const TP timePoint) const pure nothrow
3341     {
3342         return false;
3343     }
3344 
3345 
3346     /++
3347         Whether this interval is before the given interval and does not
3348         intersect it.
3349 
3350         Always returns false (unless the given interval is empty) because an
3351         interval going to positive infinity can never be before any other
3352         interval.
3353 
3354         Params:
3355             interval = The interval to check for against this interval.
3356 
3357         Throws:
3358             $(REF DateTimeException,std,datetime,date) if the given interval
3359             is empty.
3360 
3361         Example:
3362 --------------------
3363 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(
3364             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
3365 
3366 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(
3367             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
3368 --------------------
3369       +/
3370     bool isBefore(scope const Interval!TP interval) const pure
3371     {
3372         interval._enforceNotEmpty();
3373         return false;
3374     }
3375 
3376 
3377     /++
3378         Whether this interval is before the given interval and does not
3379         intersect it.
3380 
3381         Always returns false because an interval going to positive infinity can
3382         never be before any other interval.
3383 
3384         Params:
3385             interval = The interval to check for against this interval.
3386 
3387         Example:
3388 --------------------
3389 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(
3390             PosInfInterval!Date(Date(1992, 5, 4))));
3391 
3392 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(
3393             PosInfInterval!Date(Date(2013, 3, 7))));
3394 --------------------
3395       +/
3396     bool isBefore(scope const PosInfInterval interval) const pure nothrow
3397     {
3398         return false;
3399     }
3400 
3401 
3402     /++
3403         Whether this interval is before the given interval and does not
3404         intersect it.
3405 
3406         Always returns false because an interval going to positive infinity can
3407         never be before any other interval.
3408 
3409         Params:
3410             interval = The interval to check for against this interval.
3411 
3412         Example:
3413 --------------------
3414 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(
3415             NegInfInterval!Date(Date(1996, 5, 4))));
3416 --------------------
3417       +/
3418     bool isBefore(scope const NegInfInterval!TP interval) const pure nothrow
3419     {
3420         return false;
3421     }
3422 
3423 
3424     /++
3425         Whether this interval is after the given time point.
3426 
3427         Params:
3428             timePoint = The time point to check whether this interval is after
3429                         it.
3430 
3431         Example:
3432 --------------------
3433 assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(1994, 12, 24)));
3434 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(2000, 1, 5)));
3435 --------------------
3436       +/
3437     bool isAfter(scope const TP timePoint) const pure nothrow
3438     {
3439         return timePoint < _begin;
3440     }
3441 
3442 
3443     /++
3444         Whether this interval is after the given interval and does not intersect
3445         it.
3446 
3447         Params:
3448             interval = The interval to check against this interval.
3449 
3450         Throws:
3451             $(REF DateTimeException,std,datetime,date) if the given interval
3452             is empty.
3453 
3454         Example:
3455 --------------------
3456 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(
3457             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
3458 
3459 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(
3460             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
3461 
3462 assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(
3463             Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
3464 --------------------
3465       +/
3466     bool isAfter(scope const Interval!TP interval) const pure
3467     {
3468         interval._enforceNotEmpty();
3469         return _begin >= interval._end;
3470     }
3471 
3472 
3473     /++
3474         Whether this interval is after the given interval and does not intersect
3475         it.
3476 
3477         Always returns false because an interval going to positive infinity can
3478         never be after another interval going to positive infinity.
3479 
3480         Params:
3481             interval = The interval to check against this interval.
3482 
3483         Example:
3484 --------------------
3485 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(
3486             PosInfInterval!Date(Date(1990, 1, 7))));
3487 
3488 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(
3489             PosInfInterval!Date(Date(1999, 5, 4))));
3490 --------------------
3491       +/
3492     bool isAfter(scope const PosInfInterval interval) const pure nothrow
3493     {
3494         return false;
3495     }
3496 
3497 
3498     /++
3499         Whether this interval is after the given interval and does not intersect
3500         it.
3501 
3502         Params:
3503             interval = The interval to check against this interval.
3504 
3505         Example:
3506 --------------------
3507 assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(
3508             NegInfInterval!Date(Date(1996, 1, 2))));
3509 
3510 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(
3511             NegInfInterval!Date(Date(2000, 7, 1))));
3512 --------------------
3513       +/
3514     bool isAfter(scope const NegInfInterval!TP interval) const pure nothrow
3515     {
3516         return _begin >= interval._end;
3517     }
3518 
3519 
3520     /++
3521         Whether the given interval overlaps this interval.
3522 
3523         Params:
3524             interval = The interval to check for intersection with this interval.
3525 
3526         Throws:
3527             $(REF DateTimeException,std,datetime,date) if the given interval
3528             is empty.
3529 
3530         Example:
3531 --------------------
3532 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(
3533             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
3534 
3535 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(
3536             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
3537 
3538 assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects(
3539             Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
3540 --------------------
3541       +/
3542     bool intersects(scope const Interval!TP interval) const pure
3543     {
3544         interval._enforceNotEmpty();
3545         return interval._end > _begin;
3546     }
3547 
3548 
3549     /++
3550         Whether the given interval overlaps this interval.
3551 
3552         Always returns true because two intervals going to positive infinity
3553         always overlap.
3554 
3555         Params:
3556             interval = The interval to check for intersection with this
3557                        interval.
3558 
3559         Example:
3560 --------------------
3561 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(
3562             PosInfInterval!Date(Date(1990, 1, 7))));
3563 
3564 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(
3565             PosInfInterval!Date(Date(1999, 5, 4))));
3566 --------------------
3567       +/
3568     bool intersects(scope const PosInfInterval interval) const pure nothrow
3569     {
3570         return true;
3571     }
3572 
3573 
3574     /++
3575         Whether the given interval overlaps this interval.
3576 
3577         Params:
3578             interval = The interval to check for intersection with this
3579                        interval.
3580 
3581         Example:
3582 --------------------
3583 assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects(
3584             NegInfInterval!Date(Date(1996, 1, 2))));
3585 
3586 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(
3587             NegInfInterval!Date(Date(2000, 7, 1))));
3588 --------------------
3589       +/
3590     bool intersects(scope const NegInfInterval!TP interval) const pure nothrow
3591     {
3592         return _begin < interval._end;
3593     }
3594 
3595 
3596     /++
3597         Returns the intersection of two intervals
3598 
3599         Params:
3600             interval = The interval to intersect with this interval.
3601 
3602         Throws:
3603             $(REF DateTimeException,std,datetime,date) if the two intervals do
3604             not intersect or if the given interval is empty.
3605 
3606         Example:
3607 --------------------
3608 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(
3609             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
3610        Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2)));
3611 
3612 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(
3613             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) ==
3614        Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17)));
3615 --------------------
3616       +/
3617     Interval!TP intersection(scope const Interval!TP interval) const
3618     {
3619         import std.format : format;
3620 
3621         enforce(this.intersects(interval),
3622                 new DateTimeException(format("%s and %s do not intersect.", this, interval)));
3623 
3624         auto begin = _begin > interval._begin ? _begin : interval._begin;
3625 
3626         return Interval!TP(begin, interval._end);
3627     }
3628 
3629 
3630     /++
3631         Returns the intersection of two intervals
3632 
3633         Params:
3634             interval = The interval to intersect with this interval.
3635 
3636         Example:
3637 --------------------
3638 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(
3639             PosInfInterval!Date(Date(1990, 7, 6))) ==
3640        PosInfInterval!Date(Date(1996, 1 , 2)));
3641 
3642 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(
3643             PosInfInterval!Date(Date(1999, 1, 12))) ==
3644        PosInfInterval!Date(Date(1999, 1 , 12)));
3645 --------------------
3646       +/
3647     PosInfInterval intersection(scope const PosInfInterval interval) const pure nothrow
3648     {
3649         return PosInfInterval(_begin < interval._begin ? interval._begin : _begin);
3650     }
3651 
3652 
3653     /++
3654         Returns the intersection of two intervals
3655 
3656         Params:
3657             interval = The interval to intersect with this interval.
3658 
3659         Throws:
3660             $(REF DateTimeException,std,datetime,date) if the two intervals do
3661             not intersect.
3662 
3663         Example:
3664 --------------------
3665 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(
3666             NegInfInterval!Date(Date(1999, 7, 6))) ==
3667        Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6)));
3668 
3669 assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(
3670             NegInfInterval!Date(Date(2013, 1, 12))) ==
3671        Interval!Date(Date(1996, 1 , 2), Date(2013, 1, 12)));
3672 --------------------
3673       +/
3674     Interval!TP intersection(scope const NegInfInterval!TP interval) const
3675     {
3676         import std.format : format;
3677 
3678         enforce(this.intersects(interval),
3679                 new DateTimeException(format("%s and %s do not intersect.", this, interval)));
3680 
3681         return Interval!TP(_begin, interval._end);
3682     }
3683 
3684 
3685     /++
3686         Whether the given interval is adjacent to this interval.
3687 
3688         Params:
3689             interval = The interval to check whether its adjecent to this
3690                        interval.
3691 
3692         Throws:
3693             $(REF DateTimeException,std,datetime,date) if the given interval
3694             is empty.
3695 
3696         Example:
3697 --------------------
3698 assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(
3699             Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
3700 
3701 assert(!PosInfInterval!Date(Date(1999, 1, 12)).isAdjacent(
3702             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
3703 --------------------
3704       +/
3705     bool isAdjacent(scope const Interval!TP interval) const pure
3706     {
3707         interval._enforceNotEmpty();
3708         return _begin == interval._end;
3709     }
3710 
3711 
3712     /++
3713         Whether the given interval is adjacent to this interval.
3714 
3715         Always returns false because two intervals going to positive infinity
3716         can never be adjacent to one another.
3717 
3718         Params:
3719             interval = The interval to check whether its adjecent to this
3720                        interval.
3721 
3722         Example:
3723 --------------------
3724 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(
3725             PosInfInterval!Date(Date(1990, 1, 7))));
3726 
3727 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(
3728             PosInfInterval!Date(Date(1996, 1, 2))));
3729 --------------------
3730       +/
3731     bool isAdjacent(scope const PosInfInterval interval) const pure nothrow
3732     {
3733         return false;
3734     }
3735 
3736 
3737     /++
3738         Whether the given interval is adjacent to this interval.
3739 
3740         Params:
3741             interval = The interval to check whether its adjecent to this
3742                        interval.
3743 
3744         Example:
3745 --------------------
3746 assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(
3747             NegInfInterval!Date(Date(1996, 1, 2))));
3748 
3749 assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(
3750             NegInfInterval!Date(Date(2000, 7, 1))));
3751 --------------------
3752       +/
3753     bool isAdjacent(scope const NegInfInterval!TP interval) const pure nothrow
3754     {
3755         return _begin == interval._end;
3756     }
3757 
3758 
3759     /++
3760         Returns the union of two intervals
3761 
3762         Params:
3763             interval = The interval to merge with this interval.
3764 
3765         Throws:
3766             $(REF DateTimeException,std,datetime,date) if the two intervals do
3767             not intersect and are not adjacent or if the given interval is
3768             empty.
3769 
3770         Note:
3771             There is no overload for `merge` which takes a
3772             `NegInfInterval`, because an interval
3773             going from negative infinity to positive infinity
3774             is not possible.
3775 
3776         Example:
3777 --------------------
3778 assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(
3779             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
3780        PosInfInterval!Date(Date(1990, 7 , 6)));
3781 
3782 assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(
3783             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) ==
3784        PosInfInterval!Date(Date(1996, 1 , 2)));
3785 --------------------
3786       +/
3787     PosInfInterval merge(scope const Interval!TP interval) const
3788     {
3789         import std.format : format;
3790 
3791         enforce(this.isAdjacent(interval) || this.intersects(interval),
3792                 new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval)));
3793 
3794         return PosInfInterval(_begin < interval._begin ? _begin : interval._begin);
3795     }
3796 
3797 
3798     /++
3799         Returns the union of two intervals
3800 
3801         Params:
3802             interval = The interval to merge with this interval.
3803 
3804         Note:
3805             There is no overload for `merge` which takes a
3806             `NegInfInterval`, because an interval
3807             going from negative infinity to positive infinity
3808             is not possible.
3809 
3810         Example:
3811 --------------------
3812 assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(
3813             PosInfInterval!Date(Date(1990, 7, 6))) ==
3814        PosInfInterval!Date(Date(1990, 7 , 6)));
3815 
3816 assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(
3817             PosInfInterval!Date(Date(1999, 1, 12))) ==
3818        PosInfInterval!Date(Date(1996, 1 , 2)));
3819 --------------------
3820       +/
3821     PosInfInterval merge(scope const PosInfInterval interval) const pure nothrow
3822     {
3823         return PosInfInterval(_begin < interval._begin ? _begin : interval._begin);
3824     }
3825 
3826 
3827     /++
3828         Returns an interval that covers from the earliest time point of two
3829         intervals up to (but not including) the latest time point of two
3830         intervals.
3831 
3832         Params:
3833             interval = The interval to create a span together with this
3834                        interval.
3835 
3836         Throws:
3837             $(REF DateTimeException,std,datetime,date) if the given interval
3838             is empty.
3839 
3840         Note:
3841             There is no overload for `span` which takes a
3842             `NegInfInterval`, because an interval
3843             going from negative infinity to positive infinity
3844             is not possible.
3845 
3846         Example:
3847 --------------------
3848 assert(PosInfInterval!Date(Date(1996, 1, 2)).span(
3849             Interval!Date(Date(500, 8, 9), Date(1602, 1, 31))) ==
3850        PosInfInterval!Date(Date(500, 8, 9)));
3851 
3852 assert(PosInfInterval!Date(Date(1996, 1, 2)).span(
3853             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
3854        PosInfInterval!Date(Date(1990, 7 , 6)));
3855 
3856 assert(PosInfInterval!Date(Date(1996, 1, 2)).span(
3857             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) ==
3858        PosInfInterval!Date(Date(1996, 1 , 2)));
3859 --------------------
3860       +/
3861     PosInfInterval span(scope const Interval!TP interval) const pure
3862     {
3863         interval._enforceNotEmpty();
3864         return PosInfInterval(_begin < interval._begin ? _begin : interval._begin);
3865     }
3866 
3867 
3868     /++
3869         Returns an interval that covers from the earliest time point of two
3870         intervals up to (but not including) the latest time point of two
3871         intervals.
3872 
3873         Params:
3874             interval = The interval to create a span together with this
3875                        interval.
3876 
3877         Note:
3878             There is no overload for `span` which takes a
3879             `NegInfInterval`, because an interval
3880             going from negative infinity to positive infinity
3881             is not possible.
3882 
3883         Example:
3884 --------------------
3885 assert(PosInfInterval!Date(Date(1996, 1, 2)).span(
3886             PosInfInterval!Date(Date(1990, 7, 6))) ==
3887        PosInfInterval!Date(Date(1990, 7 , 6)));
3888 
3889 assert(PosInfInterval!Date(Date(1996, 1, 2)).span(
3890             PosInfInterval!Date(Date(1999, 1, 12))) ==
3891        PosInfInterval!Date(Date(1996, 1 , 2)));
3892 --------------------
3893       +/
3894     PosInfInterval span(scope const PosInfInterval interval) const pure nothrow
3895     {
3896         return PosInfInterval(_begin < interval._begin ? _begin : interval._begin);
3897     }
3898 
3899 
3900     /++
3901         Shifts the `begin` of this interval forward or backwards in time by
3902         the given duration (a positive duration shifts the interval forward; a
3903         negative duration shifts it backward). Effectively, it does
3904         $(D begin += duration).
3905 
3906         Params:
3907             duration = The duration to shift the interval by.
3908 
3909         Example:
3910 --------------------
3911 auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
3912 auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
3913 
3914 interval1.shift(dur!"days"(50));
3915 assert(interval1 == PosInfInterval!Date(Date(1996, 2, 21)));
3916 
3917 interval2.shift(dur!"days"(-50));
3918 assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13)));
3919 --------------------
3920       +/
3921     void shift(D)(D duration) pure nothrow
3922         if (__traits(compiles, begin + duration))
3923     {
3924         _begin += duration;
3925     }
3926 
3927 
3928     static if (__traits(compiles, begin.add!"months"(1)) &&
3929                __traits(compiles, begin.add!"years"(1)))
3930     {
3931         /++
3932             Shifts the `begin` of this interval forward or backwards in time
3933             by the given number of years and/or months (a positive number of
3934             years and months shifts the interval forward; a negative number
3935             shifts it backward). It adds the years the given years and months to
3936             `begin`. It effectively calls `add!"years"()` and then
3937             `add!"months"()` on `begin` with the given number of years and
3938             months.
3939 
3940             Params:
3941                 years         = The number of years to shift the interval by.
3942                 months        = The number of months to shift the interval by.
3943                 allowOverflow = Whether the days should be allowed to overflow
3944                                 on `begin`, causing its month to increment.
3945 
3946             Throws:
3947                 $(REF DateTimeException,std,datetime,date) if this interval is
3948                 empty or if the resulting interval would be invalid.
3949 
3950             Example:
3951 --------------------
3952 auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
3953 auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
3954 
3955 interval1.shift(dur!"days"(50));
3956 assert(interval1 == PosInfInterval!Date(Date(1996, 2, 21)));
3957 
3958 interval2.shift(dur!"days"(-50));
3959 assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13)));
3960 --------------------
3961           +/
3962         void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
3963             if (isIntegral!T)
3964         {
3965             auto begin = _begin;
3966 
3967             begin.add!"years"(years, allowOverflow);
3968             begin.add!"months"(months, allowOverflow);
3969 
3970             _begin = begin;
3971         }
3972     }
3973 
3974 
3975     /++
3976         Expands the interval backwards in time. Effectively, it does
3977         $(D begin -= duration).
3978 
3979         Params:
3980             duration = The duration to expand the interval by.
3981 
3982         Example:
3983 --------------------
3984 auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
3985 auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
3986 
3987 interval1.expand(dur!"days"(2));
3988 assert(interval1 == PosInfInterval!Date(Date(1995, 12, 31)));
3989 
3990 interval2.expand(dur!"days"(-2));
3991 assert(interval2 == PosInfInterval!Date(Date(1996, 1, 4)));
3992 --------------------
3993       +/
3994     void expand(D)(D duration) pure nothrow
3995         if (__traits(compiles, begin + duration))
3996     {
3997         _begin -= duration;
3998     }
3999 
4000 
4001     static if (__traits(compiles, begin.add!"months"(1)) &&
4002                __traits(compiles, begin.add!"years"(1)))
4003     {
4004         /++
4005             Expands the interval forwards and/or backwards in time. Effectively,
4006             it subtracts the given number of months/years from `begin`.
4007 
4008             Params:
4009                 years         = The number of years to expand the interval by.
4010                 months        = The number of months to expand the interval by.
4011                 allowOverflow = Whether the days should be allowed to overflow
4012                                 on `begin`, causing its month to increment.
4013 
4014             Throws:
4015                 $(REF DateTimeException,std,datetime,date) if this interval is
4016                 empty or if the resulting interval would be invalid.
4017 
4018             Example:
4019 --------------------
4020 auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
4021 auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
4022 
4023 interval1.expand(2);
4024 assert(interval1 == PosInfInterval!Date(Date(1994, 1, 2)));
4025 
4026 interval2.expand(-2);
4027 assert(interval2 == PosInfInterval!Date(Date(1998, 1, 2)));
4028 --------------------
4029           +/
4030         void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
4031             if (isIntegral!T)
4032         {
4033             auto begin = _begin;
4034 
4035             begin.add!"years"(-years, allowOverflow);
4036             begin.add!"months"(-months, allowOverflow);
4037 
4038             _begin = begin;
4039         }
4040     }
4041 
4042 
4043     /++
4044         Returns a range which iterates forward over the interval, starting
4045         at `begin`, using $(D_PARAM func) to generate each successive time
4046         point.
4047 
4048         The range's `front` is the interval's `begin`. $(D_PARAM func) is
4049         used to generate the next `front` when `popFront` is called. If
4050         $(D_PARAM popFirst) is `PopFirst.yes`, then `popFront` is called
4051         before the range is returned (so that `front` is a time point which
4052         $(D_PARAM func) would generate).
4053 
4054         If $(D_PARAM func) ever generates a time point less than or equal to the
4055         current `front` of the range, then a
4056         $(REF DateTimeException,std,datetime,date) will be thrown.
4057 
4058         There are helper functions in this module which generate common
4059         delegates to pass to `fwdRange`. Their documentation starts with
4060         "Range-generating function," to make them easily searchable.
4061 
4062         Params:
4063             func     = The function used to generate the time points of the
4064                        range over the interval.
4065             popFirst = Whether `popFront` should be called on the range
4066                        before returning it.
4067 
4068         Throws:
4069             $(REF DateTimeException,std,datetime,date) if this interval is
4070             empty.
4071 
4072         Warning:
4073             $(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func)
4074             would be a function pointer to a pure function, but forcing
4075             $(D_PARAM func) to be pure is far too restrictive to be useful, and
4076             in order to have the ease of use of having functions which generate
4077             functions to pass to `fwdRange`, $(D_PARAM func) must be a
4078             delegate.
4079 
4080             If $(D_PARAM func) retains state which changes as it is called, then
4081             some algorithms will not work correctly, because the range's
4082             `save` will have failed to have really saved the range's state.
4083             To avoid such bugs, don't pass a delegate which is
4084             not logically pure to `fwdRange`. If $(D_PARAM func) is given the
4085             same time point with two different calls, it must return the same
4086             result both times.
4087 
4088             Of course, none of the functions in this module have this problem,
4089             so it's only relevant for custom delegates.
4090 
4091         Example:
4092 --------------------
4093 auto interval = PosInfInterval!Date(Date(2010, 9, 1));
4094 auto func = delegate (scope const Date date) //For iterating over even-numbered days.
4095             {
4096                 if ((date.day & 1) == 0)
4097                     return date + dur!"days"(2);
4098 
4099                 return date + dur!"days"(1);
4100             };
4101 auto range = interval.fwdRange(func);
4102 
4103 //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2).
4104 assert(range.front == Date(2010, 9, 1));
4105 
4106 range.popFront();
4107 assert(range.front == Date(2010, 9, 2));
4108 
4109 range.popFront();
4110 assert(range.front == Date(2010, 9, 4));
4111 
4112 range.popFront();
4113 assert(range.front == Date(2010, 9, 6));
4114 
4115 range.popFront();
4116 assert(range.front == Date(2010, 9, 8));
4117 
4118 range.popFront();
4119 assert(!range.empty);
4120 --------------------
4121       +/
4122     PosInfIntervalRange!(TP) fwdRange(TP delegate(scope const TP) func, PopFirst popFirst = PopFirst.no) const
4123     {
4124         auto range = PosInfIntervalRange!(TP)(this, func);
4125 
4126         if (popFirst == PopFirst.yes)
4127             range.popFront();
4128 
4129         return range;
4130     }
4131 
4132 
4133     /+
4134         Converts this interval to a string.
4135       +/
4136     // Due to bug https://issues.dlang.org/show_bug.cgi?id=3715 , we can't
4137     // have versions of toString() with extra modifiers,
4138     // so we define one version with modifiers and one without.
4139     string toString()
4140     {
4141         return _toStringImpl();
4142     }
4143 
4144 
4145     /++
4146         Converts this interval to a string.
4147       +/
4148     // Due to bug https://issues.dlang.org/show_bug.cgi?id=3715 , we can't
4149     // have versions of toString() with extra modifiers,
4150     // so we define one version with modifiers and one without.
4151     string toString() const nothrow
4152     {
4153         return _toStringImpl();
4154     }
4155 
4156 private:
4157 
4158     /+
4159         Since we have two versions of toString(), we have _toStringImpl()
4160         so that they can share implementations.
4161       +/
4162     string _toStringImpl() const nothrow
4163     {
4164         import std.format : format;
4165         try
4166             return format("[%s - ∞)", _begin);
4167         catch (Exception e)
4168             assert(0, "format() threw.");
4169     }
4170 
4171 
4172     TP _begin;
4173 }
4174 
4175 //Test PosInfInterval's constructor.
4176 @safe unittest
4177 {
4178     import std.datetime.date;
4179     import std.datetime.systime;
4180 
4181     PosInfInterval!Date(Date.init);
4182     PosInfInterval!TimeOfDay(TimeOfDay.init);
4183     PosInfInterval!DateTime(DateTime.init);
4184     PosInfInterval!SysTime(SysTime(0));
4185 
4186     //Verify Examples.
4187     auto interval = PosInfInterval!Date(Date(1996, 1, 2));
4188 }
4189 
4190 //Test PosInfInterval's begin.
4191 @safe unittest
4192 {
4193     import std.datetime.date;
4194 
4195     assert(PosInfInterval!Date(Date(1, 1, 1)).begin == Date(1, 1, 1));
4196     assert(PosInfInterval!Date(Date(2010, 1, 1)).begin == Date(2010, 1, 1));
4197     assert(PosInfInterval!Date(Date(1997, 12, 31)).begin == Date(1997, 12, 31));
4198 
4199     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4200     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4201     assert(cPosInfInterval.begin != Date.init);
4202     assert(iPosInfInterval.begin != Date.init);
4203 
4204     //Verify Examples.
4205     assert(PosInfInterval!Date(Date(1996, 1, 2)).begin == Date(1996, 1, 2));
4206 }
4207 
4208 //Test PosInfInterval's empty.
4209 @safe unittest
4210 {
4211     import std.datetime.date;
4212     import std.datetime.systime;
4213 
4214     assert(!PosInfInterval!Date(Date(2010, 1, 1)).empty);
4215     assert(!PosInfInterval!TimeOfDay(TimeOfDay(0, 30, 0)).empty);
4216     assert(!PosInfInterval!DateTime(DateTime(2010, 1, 1, 0, 30, 0)).empty);
4217     assert(!PosInfInterval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0))).empty);
4218 
4219     const cPosInfInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4220     immutable iPosInfInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4221     assert(!cPosInfInterval.empty);
4222     assert(!iPosInfInterval.empty);
4223 
4224     //Verify Examples.
4225     assert(!PosInfInterval!Date(Date(1996, 1, 2)).empty);
4226 }
4227 
4228 //Test PosInfInterval's contains(time point).
4229 @safe unittest
4230 {
4231     import std.datetime.date;
4232 
4233     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4234 
4235     assert(!posInfInterval.contains(Date(2009, 7, 4)));
4236     assert(!posInfInterval.contains(Date(2010, 7, 3)));
4237     assert(posInfInterval.contains(Date(2010, 7, 4)));
4238     assert(posInfInterval.contains(Date(2010, 7, 5)));
4239     assert(posInfInterval.contains(Date(2011, 7, 1)));
4240     assert(posInfInterval.contains(Date(2012, 1, 6)));
4241     assert(posInfInterval.contains(Date(2012, 1, 7)));
4242     assert(posInfInterval.contains(Date(2012, 1, 8)));
4243     assert(posInfInterval.contains(Date(2013, 1, 7)));
4244 
4245     const cdate = Date(2010, 7, 6);
4246     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4247     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4248     assert(posInfInterval.contains(cdate));
4249     assert(cPosInfInterval.contains(cdate));
4250     assert(iPosInfInterval.contains(cdate));
4251 
4252     //Verify Examples.
4253     assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(1994, 12, 24)));
4254     assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(2000, 1, 5)));
4255 }
4256 
4257 //Test PosInfInterval's contains(Interval).
4258 @safe unittest
4259 {
4260     import std.datetime.date;
4261 
4262     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4263 
4264     static void testInterval(scope const PosInfInterval!Date posInfInterval, scope const Interval!Date interval)
4265     {
4266         posInfInterval.contains(interval);
4267     }
4268 
4269     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
4270 
4271     assert(posInfInterval.contains(posInfInterval));
4272     assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
4273     assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
4274     assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
4275     assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
4276     assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
4277     assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
4278     assert(posInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
4279     assert(posInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
4280     assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
4281     assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
4282     assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
4283     assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
4284 
4285     assert(!posInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 3))));
4286     assert(posInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 4))));
4287     assert(posInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 5))));
4288     assert(posInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 6))));
4289     assert(posInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 7))));
4290     assert(posInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 8))));
4291 
4292     assert(PosInfInterval!Date(Date(2010, 7, 3)).contains(posInfInterval));
4293     assert(PosInfInterval!Date(Date(2010, 7, 4)).contains(posInfInterval));
4294     assert(!PosInfInterval!Date(Date(2010, 7, 5)).contains(posInfInterval));
4295     assert(!PosInfInterval!Date(Date(2012, 1, 6)).contains(posInfInterval));
4296     assert(!PosInfInterval!Date(Date(2012, 1, 7)).contains(posInfInterval));
4297     assert(!PosInfInterval!Date(Date(2012, 1, 8)).contains(posInfInterval));
4298 
4299     assert(!posInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 3))));
4300     assert(!posInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 4))));
4301     assert(!posInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 5))));
4302     assert(!posInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 6))));
4303     assert(!posInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 7))));
4304     assert(!posInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 8))));
4305 
4306     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4307     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4308     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4309     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4310     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4311     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4312     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4313     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4314     assert(posInfInterval.contains(interval));
4315     assert(posInfInterval.contains(cInterval));
4316     assert(posInfInterval.contains(iInterval));
4317     assert(posInfInterval.contains(posInfInterval));
4318     assert(posInfInterval.contains(cPosInfInterval));
4319     assert(posInfInterval.contains(iPosInfInterval));
4320     assert(!posInfInterval.contains(negInfInterval));
4321     assert(!posInfInterval.contains(cNegInfInterval));
4322     assert(!posInfInterval.contains(iNegInfInterval));
4323     assert(cPosInfInterval.contains(interval));
4324     assert(cPosInfInterval.contains(cInterval));
4325     assert(cPosInfInterval.contains(iInterval));
4326     assert(cPosInfInterval.contains(posInfInterval));
4327     assert(cPosInfInterval.contains(cPosInfInterval));
4328     assert(cPosInfInterval.contains(iPosInfInterval));
4329     assert(!cPosInfInterval.contains(negInfInterval));
4330     assert(!cPosInfInterval.contains(cNegInfInterval));
4331     assert(!cPosInfInterval.contains(iNegInfInterval));
4332     assert(iPosInfInterval.contains(interval));
4333     assert(iPosInfInterval.contains(cInterval));
4334     assert(iPosInfInterval.contains(iInterval));
4335     assert(iPosInfInterval.contains(posInfInterval));
4336     assert(iPosInfInterval.contains(cPosInfInterval));
4337     assert(iPosInfInterval.contains(iPosInfInterval));
4338     assert(!iPosInfInterval.contains(negInfInterval));
4339     assert(!iPosInfInterval.contains(cNegInfInterval));
4340     assert(!iPosInfInterval.contains(iNegInfInterval));
4341 
4342     //Verify Examples.
4343     assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
4344     assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
4345     assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
4346 
4347     assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(PosInfInterval!Date(Date(1999, 5, 4))));
4348     assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(PosInfInterval!Date(Date(1995, 7, 2))));
4349 
4350     assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(NegInfInterval!Date(Date(1996, 5, 4))));
4351 }
4352 
4353 //Test PosInfInterval's isBefore(time point).
4354 @safe unittest
4355 {
4356     import std.datetime.date;
4357 
4358     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4359 
4360     assert(!posInfInterval.isBefore(Date(2009, 7, 3)));
4361     assert(!posInfInterval.isBefore(Date(2010, 7, 3)));
4362     assert(!posInfInterval.isBefore(Date(2010, 7, 4)));
4363     assert(!posInfInterval.isBefore(Date(2010, 7, 5)));
4364     assert(!posInfInterval.isBefore(Date(2011, 7, 1)));
4365     assert(!posInfInterval.isBefore(Date(2012, 1, 6)));
4366     assert(!posInfInterval.isBefore(Date(2012, 1, 7)));
4367     assert(!posInfInterval.isBefore(Date(2012, 1, 8)));
4368     assert(!posInfInterval.isBefore(Date(2013, 1, 7)));
4369 
4370     const cdate = Date(2010, 7, 6);
4371     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4372     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4373     assert(!posInfInterval.isBefore(cdate));
4374     assert(!cPosInfInterval.isBefore(cdate));
4375     assert(!iPosInfInterval.isBefore(cdate));
4376 
4377     //Verify Examples.
4378     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(1994, 12, 24)));
4379     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(2000, 1, 5)));
4380 }
4381 
4382 //Test PosInfInterval's isBefore(Interval).
4383 @safe unittest
4384 {
4385     import std.datetime.date;
4386 
4387     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4388 
4389     static void testInterval(scope const PosInfInterval!Date posInfInterval, scope const Interval!Date interval)
4390     {
4391         posInfInterval.isBefore(interval);
4392     }
4393 
4394     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
4395 
4396     assert(!posInfInterval.isBefore(posInfInterval));
4397     assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
4398     assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
4399     assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
4400     assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
4401     assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
4402     assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
4403     assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
4404     assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
4405     assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
4406     assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
4407     assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
4408     assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
4409 
4410     assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 3))));
4411     assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 4))));
4412     assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 5))));
4413     assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 6))));
4414     assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 7))));
4415     assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 8))));
4416 
4417     assert(!PosInfInterval!Date(Date(2010, 7, 3)).isBefore(posInfInterval));
4418     assert(!PosInfInterval!Date(Date(2010, 7, 4)).isBefore(posInfInterval));
4419     assert(!PosInfInterval!Date(Date(2010, 7, 5)).isBefore(posInfInterval));
4420     assert(!PosInfInterval!Date(Date(2012, 1, 6)).isBefore(posInfInterval));
4421     assert(!PosInfInterval!Date(Date(2012, 1, 7)).isBefore(posInfInterval));
4422     assert(!PosInfInterval!Date(Date(2012, 1, 8)).isBefore(posInfInterval));
4423 
4424     assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 3))));
4425     assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 4))));
4426     assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 5))));
4427     assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 6))));
4428     assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 7))));
4429     assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 8))));
4430 
4431     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4432     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4433     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4434     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4435     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4436     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4437     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4438     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4439     assert(!posInfInterval.isBefore(interval));
4440     assert(!posInfInterval.isBefore(cInterval));
4441     assert(!posInfInterval.isBefore(iInterval));
4442     assert(!posInfInterval.isBefore(posInfInterval));
4443     assert(!posInfInterval.isBefore(cPosInfInterval));
4444     assert(!posInfInterval.isBefore(iPosInfInterval));
4445     assert(!posInfInterval.isBefore(negInfInterval));
4446     assert(!posInfInterval.isBefore(cNegInfInterval));
4447     assert(!posInfInterval.isBefore(iNegInfInterval));
4448     assert(!cPosInfInterval.isBefore(interval));
4449     assert(!cPosInfInterval.isBefore(cInterval));
4450     assert(!cPosInfInterval.isBefore(iInterval));
4451     assert(!cPosInfInterval.isBefore(posInfInterval));
4452     assert(!cPosInfInterval.isBefore(cPosInfInterval));
4453     assert(!cPosInfInterval.isBefore(iPosInfInterval));
4454     assert(!cPosInfInterval.isBefore(negInfInterval));
4455     assert(!cPosInfInterval.isBefore(cNegInfInterval));
4456     assert(!cPosInfInterval.isBefore(iNegInfInterval));
4457     assert(!iPosInfInterval.isBefore(interval));
4458     assert(!iPosInfInterval.isBefore(cInterval));
4459     assert(!iPosInfInterval.isBefore(iInterval));
4460     assert(!iPosInfInterval.isBefore(posInfInterval));
4461     assert(!iPosInfInterval.isBefore(cPosInfInterval));
4462     assert(!iPosInfInterval.isBefore(iPosInfInterval));
4463     assert(!iPosInfInterval.isBefore(negInfInterval));
4464     assert(!iPosInfInterval.isBefore(cNegInfInterval));
4465     assert(!iPosInfInterval.isBefore(iNegInfInterval));
4466 
4467     //Verify Examples.
4468     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
4469     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
4470 
4471     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(PosInfInterval!Date(Date(1992, 5, 4))));
4472     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(PosInfInterval!Date(Date(2013, 3, 7))));
4473 
4474     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(NegInfInterval!Date(Date(1996, 5, 4))));
4475 }
4476 
4477 //Test PosInfInterval's isAfter(time point).
4478 @safe unittest
4479 {
4480     import std.datetime.date;
4481 
4482     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4483 
4484     assert(posInfInterval.isAfter(Date(2009, 7, 3)));
4485     assert(posInfInterval.isAfter(Date(2010, 7, 3)));
4486     assert(!posInfInterval.isAfter(Date(2010, 7, 4)));
4487     assert(!posInfInterval.isAfter(Date(2010, 7, 5)));
4488     assert(!posInfInterval.isAfter(Date(2011, 7, 1)));
4489     assert(!posInfInterval.isAfter(Date(2012, 1, 6)));
4490     assert(!posInfInterval.isAfter(Date(2012, 1, 7)));
4491     assert(!posInfInterval.isAfter(Date(2012, 1, 8)));
4492     assert(!posInfInterval.isAfter(Date(2013, 1, 7)));
4493 
4494     const cdate = Date(2010, 7, 6);
4495     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4496     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4497     assert(!posInfInterval.isAfter(cdate));
4498     assert(!cPosInfInterval.isAfter(cdate));
4499     assert(!iPosInfInterval.isAfter(cdate));
4500 
4501     //Verify Examples.
4502     assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(1994, 12, 24)));
4503     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(2000, 1, 5)));
4504 }
4505 
4506 //Test PosInfInterval's isAfter(Interval).
4507 @safe unittest
4508 {
4509     import std.datetime.date;
4510 
4511     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4512 
4513     static void testInterval(scope const PosInfInterval!Date posInfInterval, scope const Interval!Date interval)
4514     {
4515         posInfInterval.isAfter(interval);
4516     }
4517 
4518     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
4519 
4520     assert(!posInfInterval.isAfter(posInfInterval));
4521     assert(posInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
4522     assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
4523     assert(posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
4524     assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
4525     assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
4526     assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
4527     assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
4528     assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
4529     assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
4530     assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
4531     assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
4532     assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
4533 
4534     assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 3))));
4535     assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 4))));
4536     assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 5))));
4537     assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 6))));
4538     assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 7))));
4539     assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 8))));
4540 
4541     assert(!PosInfInterval!Date(Date(2010, 7, 3)).isAfter(posInfInterval));
4542     assert(!PosInfInterval!Date(Date(2010, 7, 4)).isAfter(posInfInterval));
4543     assert(!PosInfInterval!Date(Date(2010, 7, 5)).isAfter(posInfInterval));
4544     assert(!PosInfInterval!Date(Date(2012, 1, 6)).isAfter(posInfInterval));
4545     assert(!PosInfInterval!Date(Date(2012, 1, 7)).isAfter(posInfInterval));
4546     assert(!PosInfInterval!Date(Date(2012, 1, 8)).isAfter(posInfInterval));
4547 
4548     assert(posInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 3))));
4549     assert(posInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 4))));
4550     assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 5))));
4551     assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 6))));
4552     assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 7))));
4553     assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 8))));
4554 
4555     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4556     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4557     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4558     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4559     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4560     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4561     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4562     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4563     assert(!posInfInterval.isAfter(interval));
4564     assert(!posInfInterval.isAfter(cInterval));
4565     assert(!posInfInterval.isAfter(iInterval));
4566     assert(!posInfInterval.isAfter(posInfInterval));
4567     assert(!posInfInterval.isAfter(cPosInfInterval));
4568     assert(!posInfInterval.isAfter(iPosInfInterval));
4569     assert(!posInfInterval.isAfter(negInfInterval));
4570     assert(!posInfInterval.isAfter(cNegInfInterval));
4571     assert(!posInfInterval.isAfter(iNegInfInterval));
4572     assert(!cPosInfInterval.isAfter(interval));
4573     assert(!cPosInfInterval.isAfter(cInterval));
4574     assert(!cPosInfInterval.isAfter(iInterval));
4575     assert(!cPosInfInterval.isAfter(posInfInterval));
4576     assert(!cPosInfInterval.isAfter(cPosInfInterval));
4577     assert(!cPosInfInterval.isAfter(iPosInfInterval));
4578     assert(!cPosInfInterval.isAfter(negInfInterval));
4579     assert(!cPosInfInterval.isAfter(cNegInfInterval));
4580     assert(!cPosInfInterval.isAfter(iNegInfInterval));
4581     assert(!iPosInfInterval.isAfter(interval));
4582     assert(!iPosInfInterval.isAfter(cInterval));
4583     assert(!iPosInfInterval.isAfter(iInterval));
4584     assert(!iPosInfInterval.isAfter(posInfInterval));
4585     assert(!iPosInfInterval.isAfter(cPosInfInterval));
4586     assert(!iPosInfInterval.isAfter(iPosInfInterval));
4587     assert(!iPosInfInterval.isAfter(negInfInterval));
4588     assert(!iPosInfInterval.isAfter(cNegInfInterval));
4589     assert(!iPosInfInterval.isAfter(iNegInfInterval));
4590 
4591     //Verify Examples.
4592     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
4593     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
4594     assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
4595 
4596     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(PosInfInterval!Date(Date(1990, 1, 7))));
4597     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(PosInfInterval!Date(Date(1999, 5, 4))));
4598 
4599     assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(NegInfInterval!Date(Date(1996, 1, 2))));
4600     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(NegInfInterval!Date(Date(2000, 7, 1))));
4601 }
4602 
4603 //Test PosInfInterval's intersects().
4604 @safe unittest
4605 {
4606     import std.datetime.date;
4607 
4608     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4609 
4610     static void testInterval(scope const PosInfInterval!Date posInfInterval, scope const Interval!Date interval)
4611     {
4612         posInfInterval.intersects(interval);
4613     }
4614 
4615     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
4616 
4617     assert(posInfInterval.intersects(posInfInterval));
4618     assert(!posInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
4619     assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
4620     assert(!posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
4621     assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
4622     assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
4623     assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
4624     assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
4625     assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
4626     assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
4627     assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
4628     assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
4629     assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
4630 
4631     assert(posInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 3))));
4632     assert(posInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 4))));
4633     assert(posInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 5))));
4634     assert(posInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 6))));
4635     assert(posInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 7))));
4636     assert(posInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 8))));
4637 
4638     assert(PosInfInterval!Date(Date(2010, 7, 3)).intersects(posInfInterval));
4639     assert(PosInfInterval!Date(Date(2010, 7, 4)).intersects(posInfInterval));
4640     assert(PosInfInterval!Date(Date(2010, 7, 5)).intersects(posInfInterval));
4641     assert(PosInfInterval!Date(Date(2012, 1, 6)).intersects(posInfInterval));
4642     assert(PosInfInterval!Date(Date(2012, 1, 7)).intersects(posInfInterval));
4643     assert(PosInfInterval!Date(Date(2012, 1, 8)).intersects(posInfInterval));
4644 
4645     assert(!posInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 3))));
4646     assert(!posInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 4))));
4647     assert(posInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 5))));
4648     assert(posInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 6))));
4649     assert(posInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 7))));
4650     assert(posInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 8))));
4651 
4652     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4653     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4654     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4655     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4656     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4657     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4658     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4659     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4660     assert(posInfInterval.intersects(interval));
4661     assert(posInfInterval.intersects(cInterval));
4662     assert(posInfInterval.intersects(iInterval));
4663     assert(posInfInterval.intersects(posInfInterval));
4664     assert(posInfInterval.intersects(cPosInfInterval));
4665     assert(posInfInterval.intersects(iPosInfInterval));
4666     assert(posInfInterval.intersects(negInfInterval));
4667     assert(posInfInterval.intersects(cNegInfInterval));
4668     assert(posInfInterval.intersects(iNegInfInterval));
4669     assert(cPosInfInterval.intersects(interval));
4670     assert(cPosInfInterval.intersects(cInterval));
4671     assert(cPosInfInterval.intersects(iInterval));
4672     assert(cPosInfInterval.intersects(posInfInterval));
4673     assert(cPosInfInterval.intersects(cPosInfInterval));
4674     assert(cPosInfInterval.intersects(iPosInfInterval));
4675     assert(cPosInfInterval.intersects(negInfInterval));
4676     assert(cPosInfInterval.intersects(cNegInfInterval));
4677     assert(cPosInfInterval.intersects(iNegInfInterval));
4678     assert(iPosInfInterval.intersects(interval));
4679     assert(iPosInfInterval.intersects(cInterval));
4680     assert(iPosInfInterval.intersects(iInterval));
4681     assert(iPosInfInterval.intersects(posInfInterval));
4682     assert(iPosInfInterval.intersects(cPosInfInterval));
4683     assert(iPosInfInterval.intersects(iPosInfInterval));
4684     assert(iPosInfInterval.intersects(negInfInterval));
4685     assert(iPosInfInterval.intersects(cNegInfInterval));
4686     assert(iPosInfInterval.intersects(iNegInfInterval));
4687 
4688     //Verify Examples.
4689     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
4690     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
4691     assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
4692 
4693     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(PosInfInterval!Date(Date(1990, 1, 7))));
4694     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(PosInfInterval!Date(Date(1999, 5, 4))));
4695 
4696     assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects(NegInfInterval!Date(Date(1996, 1, 2))));
4697     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(NegInfInterval!Date(Date(2000, 7, 1))));
4698 }
4699 
4700 //Test PosInfInterval's intersection().
4701 @safe unittest
4702 {
4703     import std.datetime.date;
4704 
4705     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4706 
4707     static void testInterval(I, J)(scope const I interval1, scope const J interval2)
4708     {
4709         interval1.intersection(interval2);
4710     }
4711 
4712     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
4713 
4714     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
4715     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
4716 
4717     assertThrown!DateTimeException(testInterval(posInfInterval, NegInfInterval!Date(Date(2010, 7, 3))));
4718     assertThrown!DateTimeException(testInterval(posInfInterval, NegInfInterval!Date(Date(2010, 7, 4))));
4719 
4720     assert(posInfInterval.intersection(posInfInterval) == posInfInterval);
4721     assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
4722            Interval!Date(Date(2010, 7, 4), Date(2013, 7, 3)));
4723     assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
4724            Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
4725     assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
4726            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
4727     assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
4728            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
4729     assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
4730            Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
4731     assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
4732            Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
4733     assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
4734            Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
4735     assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
4736            Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)));
4737     assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
4738            Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)));
4739     assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) ==
4740            Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)));
4741 
4742     assert(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 4)));
4743     assert(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 4)));
4744     assert(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 5)));
4745     assert(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 6))) == PosInfInterval!Date(Date(2012, 1, 6)));
4746     assert(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 7))) == PosInfInterval!Date(Date(2012, 1, 7)));
4747     assert(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 8))) == PosInfInterval!Date(Date(2012, 1, 8)));
4748 
4749     assert(PosInfInterval!Date(Date(2010, 7, 3)).intersection(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
4750     assert(PosInfInterval!Date(Date(2010, 7, 4)).intersection(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
4751     assert(PosInfInterval!Date(Date(2010, 7, 5)).intersection(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 5)));
4752     assert(PosInfInterval!Date(Date(2012, 1, 6)).intersection(posInfInterval) == PosInfInterval!Date(Date(2012, 1, 6)));
4753     assert(PosInfInterval!Date(Date(2012, 1, 7)).intersection(posInfInterval) == PosInfInterval!Date(Date(2012, 1, 7)));
4754     assert(PosInfInterval!Date(Date(2012, 1, 8)).intersection(posInfInterval) == PosInfInterval!Date(Date(2012, 1, 8)));
4755 
4756     assert(posInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 5))) ==
4757            Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
4758     assert(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 6))) ==
4759            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 6)));
4760     assert(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 7))) ==
4761            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
4762     assert(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 8))) ==
4763            Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
4764 
4765     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4766     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4767     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4768     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4769     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4770     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4771     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4772     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4773     assert(!posInfInterval.intersection(interval).empty);
4774     assert(!posInfInterval.intersection(cInterval).empty);
4775     assert(!posInfInterval.intersection(iInterval).empty);
4776     assert(!posInfInterval.intersection(posInfInterval).empty);
4777     assert(!posInfInterval.intersection(cPosInfInterval).empty);
4778     assert(!posInfInterval.intersection(iPosInfInterval).empty);
4779     assert(!posInfInterval.intersection(negInfInterval).empty);
4780     assert(!posInfInterval.intersection(cNegInfInterval).empty);
4781     assert(!posInfInterval.intersection(iNegInfInterval).empty);
4782     assert(!cPosInfInterval.intersection(interval).empty);
4783     assert(!cPosInfInterval.intersection(cInterval).empty);
4784     assert(!cPosInfInterval.intersection(iInterval).empty);
4785     assert(!cPosInfInterval.intersection(posInfInterval).empty);
4786     assert(!cPosInfInterval.intersection(cPosInfInterval).empty);
4787     assert(!cPosInfInterval.intersection(iPosInfInterval).empty);
4788     assert(!cPosInfInterval.intersection(negInfInterval).empty);
4789     assert(!cPosInfInterval.intersection(cNegInfInterval).empty);
4790     assert(!cPosInfInterval.intersection(iNegInfInterval).empty);
4791     assert(!iPosInfInterval.intersection(interval).empty);
4792     assert(!iPosInfInterval.intersection(cInterval).empty);
4793     assert(!iPosInfInterval.intersection(iInterval).empty);
4794     assert(!iPosInfInterval.intersection(posInfInterval).empty);
4795     assert(!iPosInfInterval.intersection(cPosInfInterval).empty);
4796     assert(!iPosInfInterval.intersection(iPosInfInterval).empty);
4797     assert(!iPosInfInterval.intersection(negInfInterval).empty);
4798     assert(!iPosInfInterval.intersection(cNegInfInterval).empty);
4799     assert(!iPosInfInterval.intersection(iNegInfInterval).empty);
4800 
4801     //Verify Examples.
4802     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
4803            Interval!Date(Date(1996, 1, 2), Date(2000, 8, 2)));
4804     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) ==
4805            Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17)));
4806 
4807     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) ==
4808            PosInfInterval!Date(Date(1996, 1, 2)));
4809     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) ==
4810            PosInfInterval!Date(Date(1999, 1, 12)));
4811 
4812     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) ==
4813            Interval!Date(Date(1996, 1, 2), Date(1999, 7, 6)));
4814     assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) ==
4815            Interval!Date(Date(1996, 1, 2), Date(2013, 1, 12)));
4816 }
4817 
4818 //Test PosInfInterval's isAdjacent().
4819 @safe unittest
4820 {
4821     import std.datetime.date;
4822 
4823     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4824 
4825     static void testInterval(scope const PosInfInterval!Date posInfInterval, scope const Interval!Date interval)
4826     {
4827         posInfInterval.isAdjacent(interval);
4828     }
4829 
4830     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
4831 
4832     assert(!posInfInterval.isAdjacent(posInfInterval));
4833     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
4834     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
4835     assert(posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
4836     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
4837     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
4838     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
4839     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
4840     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
4841     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
4842     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
4843     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
4844     assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
4845 
4846     assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 3))));
4847     assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 4))));
4848     assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 5))));
4849     assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 6))));
4850     assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 7))));
4851     assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 8))));
4852 
4853     assert(!PosInfInterval!Date(Date(2010, 7, 3)).isAdjacent(posInfInterval));
4854     assert(!PosInfInterval!Date(Date(2010, 7, 4)).isAdjacent(posInfInterval));
4855     assert(!PosInfInterval!Date(Date(2010, 7, 5)).isAdjacent(posInfInterval));
4856     assert(!PosInfInterval!Date(Date(2012, 1, 6)).isAdjacent(posInfInterval));
4857     assert(!PosInfInterval!Date(Date(2012, 1, 7)).isAdjacent(posInfInterval));
4858     assert(!PosInfInterval!Date(Date(2012, 1, 8)).isAdjacent(posInfInterval));
4859 
4860     assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 3))));
4861     assert(posInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 4))));
4862     assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 5))));
4863     assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 6))));
4864     assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 7))));
4865     assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 8))));
4866 
4867     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4868     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4869     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4870     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4871     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4872     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4873     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4874     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4875     assert(!posInfInterval.isAdjacent(interval));
4876     assert(!posInfInterval.isAdjacent(cInterval));
4877     assert(!posInfInterval.isAdjacent(iInterval));
4878     assert(!posInfInterval.isAdjacent(posInfInterval));
4879     assert(!posInfInterval.isAdjacent(cPosInfInterval));
4880     assert(!posInfInterval.isAdjacent(iPosInfInterval));
4881     assert(!posInfInterval.isAdjacent(negInfInterval));
4882     assert(!posInfInterval.isAdjacent(cNegInfInterval));
4883     assert(!posInfInterval.isAdjacent(iNegInfInterval));
4884     assert(!cPosInfInterval.isAdjacent(interval));
4885     assert(!cPosInfInterval.isAdjacent(cInterval));
4886     assert(!cPosInfInterval.isAdjacent(iInterval));
4887     assert(!cPosInfInterval.isAdjacent(posInfInterval));
4888     assert(!cPosInfInterval.isAdjacent(cPosInfInterval));
4889     assert(!cPosInfInterval.isAdjacent(iPosInfInterval));
4890     assert(!cPosInfInterval.isAdjacent(negInfInterval));
4891     assert(!cPosInfInterval.isAdjacent(cNegInfInterval));
4892     assert(!cPosInfInterval.isAdjacent(iNegInfInterval));
4893     assert(!iPosInfInterval.isAdjacent(interval));
4894     assert(!iPosInfInterval.isAdjacent(cInterval));
4895     assert(!iPosInfInterval.isAdjacent(iInterval));
4896     assert(!iPosInfInterval.isAdjacent(posInfInterval));
4897     assert(!iPosInfInterval.isAdjacent(cPosInfInterval));
4898     assert(!iPosInfInterval.isAdjacent(iPosInfInterval));
4899     assert(!iPosInfInterval.isAdjacent(negInfInterval));
4900     assert(!iPosInfInterval.isAdjacent(cNegInfInterval));
4901     assert(!iPosInfInterval.isAdjacent(iNegInfInterval));
4902 
4903     //Verify Examples.
4904     assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
4905     assert(!PosInfInterval!Date(Date(1999, 1, 12)).isAdjacent(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
4906 
4907     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(PosInfInterval!Date(Date(1990, 1, 7))));
4908     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(PosInfInterval!Date(Date(1996, 1, 2))));
4909 
4910     assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(NegInfInterval!Date(Date(1996, 1, 2))));
4911     assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(NegInfInterval!Date(Date(2000, 7, 1))));
4912 }
4913 
4914 //Test PosInfInterval's merge().
4915 @safe unittest
4916 {
4917     import std.datetime.date;
4918 
4919     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4920 
4921     static void testInterval(scope const PosInfInterval!Date posInfInterval, scope const Interval!Date interval)
4922     {
4923         posInfInterval.merge(interval);
4924     }
4925 
4926     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
4927 
4928     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
4929 
4930     assert(posInfInterval.merge(posInfInterval) == posInfInterval);
4931     assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
4932            PosInfInterval!Date(Date(2010, 7, 1)));
4933     assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
4934            PosInfInterval!Date(Date(2010, 7, 3)));
4935     assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
4936            PosInfInterval!Date(Date(2010, 7, 3)));
4937     assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
4938            PosInfInterval!Date(Date(2010, 7, 3)));
4939     assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
4940            PosInfInterval!Date(Date(2010, 7, 3)));
4941     assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
4942            PosInfInterval!Date(Date(2010, 7, 4)));
4943     assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
4944            PosInfInterval!Date(Date(2010, 7, 4)));
4945     assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
4946            PosInfInterval!Date(Date(2010, 7, 4)));
4947     assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
4948            PosInfInterval!Date(Date(2010, 7, 4)));
4949     assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
4950            PosInfInterval!Date(Date(2010, 7, 4)));
4951     assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) ==
4952            PosInfInterval!Date(Date(2010, 7, 4)));
4953 
4954     assert(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 3)));
4955     assert(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 4)));
4956     assert(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 4)));
4957     assert(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 6))) == PosInfInterval!Date(Date(2010, 7, 4)));
4958     assert(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4)));
4959     assert(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 4)));
4960 
4961     assert(PosInfInterval!Date(Date(2010, 7, 3)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 3)));
4962     assert(PosInfInterval!Date(Date(2010, 7, 4)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
4963     assert(PosInfInterval!Date(Date(2010, 7, 5)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
4964     assert(PosInfInterval!Date(Date(2012, 1, 6)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
4965     assert(PosInfInterval!Date(Date(2012, 1, 7)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
4966     assert(PosInfInterval!Date(Date(2012, 1, 8)).merge(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
4967 
4968     static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 3)))));
4969     static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 4)))));
4970     static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 5)))));
4971     static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 6)))));
4972     static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 7)))));
4973     static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 8)))));
4974 
4975     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4976     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4977     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
4978     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4979     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
4980     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4981     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4982     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
4983     assert(!posInfInterval.merge(interval).empty);
4984     assert(!posInfInterval.merge(cInterval).empty);
4985     assert(!posInfInterval.merge(iInterval).empty);
4986     assert(!posInfInterval.merge(posInfInterval).empty);
4987     assert(!posInfInterval.merge(cPosInfInterval).empty);
4988     assert(!posInfInterval.merge(iPosInfInterval).empty);
4989     static assert(!__traits(compiles, posInfInterval.merge(negInfInterval)));
4990     static assert(!__traits(compiles, posInfInterval.merge(cNegInfInterval)));
4991     static assert(!__traits(compiles, posInfInterval.merge(iNegInfInterval)));
4992     assert(!cPosInfInterval.merge(interval).empty);
4993     assert(!cPosInfInterval.merge(cInterval).empty);
4994     assert(!cPosInfInterval.merge(iInterval).empty);
4995     assert(!cPosInfInterval.merge(posInfInterval).empty);
4996     assert(!cPosInfInterval.merge(cPosInfInterval).empty);
4997     assert(!cPosInfInterval.merge(iPosInfInterval).empty);
4998     static assert(!__traits(compiles, cPosInfInterval.merge(negInfInterval)));
4999     static assert(!__traits(compiles, cPosInfInterval.merge(cNegInfInterval)));
5000     static assert(!__traits(compiles, cPosInfInterval.merge(iNegInfInterval)));
5001     assert(!iPosInfInterval.merge(interval).empty);
5002     assert(!iPosInfInterval.merge(cInterval).empty);
5003     assert(!iPosInfInterval.merge(iInterval).empty);
5004     assert(!iPosInfInterval.merge(posInfInterval).empty);
5005     assert(!iPosInfInterval.merge(cPosInfInterval).empty);
5006     assert(!iPosInfInterval.merge(iPosInfInterval).empty);
5007     static assert(!__traits(compiles, iPosInfInterval.merge(negInfInterval)));
5008     static assert(!__traits(compiles, iPosInfInterval.merge(cNegInfInterval)));
5009     static assert(!__traits(compiles, iPosInfInterval.merge(iNegInfInterval)));
5010 
5011     //Verify Examples.
5012     assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
5013            PosInfInterval!Date(Date(1990, 7, 6)));
5014     assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) ==
5015            PosInfInterval!Date(Date(1996, 1, 2)));
5016 
5017     assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(PosInfInterval!Date(Date(1990, 7, 6))) ==
5018            PosInfInterval!Date(Date(1990, 7, 6)));
5019     assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(PosInfInterval!Date(Date(1999, 1, 12))) ==
5020            PosInfInterval!Date(Date(1996, 1, 2)));
5021 }
5022 
5023 //Test PosInfInterval's span().
5024 @safe unittest
5025 {
5026     import std.datetime.date;
5027 
5028     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5029 
5030     static void testInterval(scope const PosInfInterval!Date posInfInterval, scope const Interval!Date interval)
5031     {
5032         posInfInterval.span(interval);
5033     }
5034 
5035     assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
5036 
5037     assert(posInfInterval.span(posInfInterval) == posInfInterval);
5038     assert(posInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) ==
5039            PosInfInterval!Date(Date(2010, 7, 1)));
5040     assert(posInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
5041            PosInfInterval!Date(Date(2010, 7, 1)));
5042     assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
5043            PosInfInterval!Date(Date(2010, 7, 3)));
5044     assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
5045            PosInfInterval!Date(Date(2010, 7, 3)));
5046     assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
5047            PosInfInterval!Date(Date(2010, 7, 3)));
5048     assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
5049            PosInfInterval!Date(Date(2010, 7, 3)));
5050     assert(posInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
5051            PosInfInterval!Date(Date(2010, 7, 4)));
5052     assert(posInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
5053            PosInfInterval!Date(Date(2010, 7, 4)));
5054     assert(posInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
5055            PosInfInterval!Date(Date(2010, 7, 4)));
5056     assert(posInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
5057            PosInfInterval!Date(Date(2010, 7, 4)));
5058     assert(posInfInterval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
5059            PosInfInterval!Date(Date(2010, 7, 4)));
5060     assert(posInfInterval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) ==
5061            PosInfInterval!Date(Date(2010, 7, 4)));
5062 
5063     assert(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 3))) == PosInfInterval!Date(Date(2010, 7, 3)));
5064     assert(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 4))) == PosInfInterval!Date(Date(2010, 7, 4)));
5065     assert(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 5))) == PosInfInterval!Date(Date(2010, 7, 4)));
5066     assert(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 6))) == PosInfInterval!Date(Date(2010, 7, 4)));
5067     assert(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 7))) == PosInfInterval!Date(Date(2010, 7, 4)));
5068     assert(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 8))) == PosInfInterval!Date(Date(2010, 7, 4)));
5069 
5070     assert(PosInfInterval!Date(Date(2010, 7, 3)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 3)));
5071     assert(PosInfInterval!Date(Date(2010, 7, 4)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
5072     assert(PosInfInterval!Date(Date(2010, 7, 5)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
5073     assert(PosInfInterval!Date(Date(2012, 1, 6)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
5074     assert(PosInfInterval!Date(Date(2012, 1, 7)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
5075     assert(PosInfInterval!Date(Date(2012, 1, 8)).span(posInfInterval) == PosInfInterval!Date(Date(2010, 7, 4)));
5076 
5077     static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2010, 7, 3)))));
5078     static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2010, 7, 4)))));
5079     static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2010, 7, 5)))));
5080     static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2012, 1, 6)))));
5081     static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2012, 1, 7)))));
5082     static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2012, 1, 8)))));
5083 
5084     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
5085     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
5086     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
5087     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5088     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5089     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
5090     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
5091     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
5092     assert(!posInfInterval.span(interval).empty);
5093     assert(!posInfInterval.span(cInterval).empty);
5094     assert(!posInfInterval.span(iInterval).empty);
5095     assert(!posInfInterval.span(posInfInterval).empty);
5096     assert(!posInfInterval.span(cPosInfInterval).empty);
5097     assert(!posInfInterval.span(iPosInfInterval).empty);
5098     static assert(!__traits(compiles, posInfInterval.span(negInfInterval)));
5099     static assert(!__traits(compiles, posInfInterval.span(cNegInfInterval)));
5100     static assert(!__traits(compiles, posInfInterval.span(iNegInfInterval)));
5101     assert(!cPosInfInterval.span(interval).empty);
5102     assert(!cPosInfInterval.span(cInterval).empty);
5103     assert(!cPosInfInterval.span(iInterval).empty);
5104     assert(!cPosInfInterval.span(posInfInterval).empty);
5105     assert(!cPosInfInterval.span(cPosInfInterval).empty);
5106     assert(!cPosInfInterval.span(iPosInfInterval).empty);
5107     static assert(!__traits(compiles, cPosInfInterval.span(negInfInterval)));
5108     static assert(!__traits(compiles, cPosInfInterval.span(cNegInfInterval)));
5109     static assert(!__traits(compiles, cPosInfInterval.span(iNegInfInterval)));
5110     assert(!iPosInfInterval.span(interval).empty);
5111     assert(!iPosInfInterval.span(cInterval).empty);
5112     assert(!iPosInfInterval.span(iInterval).empty);
5113     assert(!iPosInfInterval.span(posInfInterval).empty);
5114     assert(!iPosInfInterval.span(cPosInfInterval).empty);
5115     assert(!iPosInfInterval.span(iPosInfInterval).empty);
5116     static assert(!__traits(compiles, iPosInfInterval.span(negInfInterval)));
5117     static assert(!__traits(compiles, iPosInfInterval.span(cNegInfInterval)));
5118     static assert(!__traits(compiles, iPosInfInterval.span(iNegInfInterval)));
5119 
5120     //Verify Examples.
5121     assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(500, 8, 9), Date(1602, 1, 31))) ==
5122            PosInfInterval!Date(Date(500, 8, 9)));
5123     assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
5124            PosInfInterval!Date(Date(1990, 7, 6)));
5125     assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) ==
5126            PosInfInterval!Date(Date(1996, 1, 2)));
5127 
5128     assert(PosInfInterval!Date(Date(1996, 1, 2)).span(PosInfInterval!Date(Date(1990, 7, 6))) ==
5129            PosInfInterval!Date(Date(1990, 7, 6)));
5130     assert(PosInfInterval!Date(Date(1996, 1, 2)).span(PosInfInterval!Date(Date(1999, 1, 12))) ==
5131            PosInfInterval!Date(Date(1996, 1, 2)));
5132 }
5133 
5134 //Test PosInfInterval's shift().
5135 @safe unittest
5136 {
5137     import std.datetime.date;
5138 
5139     auto interval = PosInfInterval!Date(Date(2010, 7, 4));
5140 
5141     static void testInterval(I)(I interval, scope const Duration duration,
5142                                 scope const I expected, size_t line = __LINE__)
5143     {
5144         interval.shift(duration);
5145         assert(interval == expected);
5146     }
5147 
5148     testInterval(interval, dur!"days"(22), PosInfInterval!Date(Date(2010, 7, 26)));
5149     testInterval(interval, dur!"days"(-22), PosInfInterval!Date(Date(2010, 6, 12)));
5150 
5151     const cInterval = PosInfInterval!Date(Date(2010, 7, 4));
5152     immutable iInterval = PosInfInterval!Date(Date(2010, 7, 4));
5153     static assert(!__traits(compiles, cInterval.shift(dur!"days"(5))));
5154     static assert(!__traits(compiles, iInterval.shift(dur!"days"(5))));
5155 
5156     //Verify Examples.
5157     auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
5158     auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
5159 
5160     interval1.shift(dur!"days"(50));
5161     assert(interval1 == PosInfInterval!Date(Date(1996, 2, 21)));
5162 
5163     interval2.shift(dur!"days"(-50));
5164     assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13)));
5165 }
5166 
5167 //Test PosInfInterval's shift(int, int, AllowDayOverflow).
5168 @safe unittest
5169 {
5170     import std.datetime.date;
5171 
5172     {
5173         auto interval = PosInfInterval!Date(Date(2010, 7, 4));
5174 
5175         static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow,
5176                                     in I expected, size_t line = __LINE__)
5177         {
5178             interval.shift(years, months, allow);
5179             assert(interval == expected);
5180         }
5181 
5182         testInterval(interval, 5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(2015, 7, 4)));
5183         testInterval(interval, -5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(2005, 7, 4)));
5184 
5185         auto interval2 = PosInfInterval!Date(Date(2000, 1, 29));
5186 
5187         testInterval(interval2, 1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2001, 3, 1)));
5188         testInterval(interval2, 1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2000, 12, 29)));
5189         testInterval(interval2, -1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1998, 12, 29)));
5190         testInterval(interval2, -1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1999, 3, 1)));
5191 
5192         testInterval(interval2, 1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(2001, 2, 28)));
5193         testInterval(interval2, 1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(2000, 12, 29)));
5194         testInterval(interval2, -1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(1998, 12, 29)));
5195         testInterval(interval2, -1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(1999, 2, 28)));
5196     }
5197 
5198     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5199     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5200     static assert(!__traits(compiles, cPosInfInterval.shift(1)));
5201     static assert(!__traits(compiles, iPosInfInterval.shift(1)));
5202 
5203     //Verify Examples.
5204     auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
5205     auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
5206 
5207     interval1.shift(2);
5208     assert(interval1 == PosInfInterval!Date(Date(1998, 1, 2)));
5209 
5210     interval2.shift(-2);
5211     assert(interval2 == PosInfInterval!Date(Date(1994, 1, 2)));
5212 }
5213 
5214 //Test PosInfInterval's expand().
5215 @safe unittest
5216 {
5217     import std.datetime.date;
5218 
5219     auto interval = PosInfInterval!Date(Date(2000, 7, 4));
5220 
5221     static void testInterval(I)(I interval, scope const Duration duration,
5222                                 scope const I expected, size_t line = __LINE__)
5223     {
5224         interval.expand(duration);
5225         assert(interval == expected);
5226     }
5227 
5228     testInterval(interval, dur!"days"(22), PosInfInterval!Date(Date(2000, 6, 12)));
5229     testInterval(interval, dur!"days"(-22), PosInfInterval!Date(Date(2000, 7, 26)));
5230 
5231     const cInterval = PosInfInterval!Date(Date(2010, 7, 4));
5232     immutable iInterval = PosInfInterval!Date(Date(2010, 7, 4));
5233     static assert(!__traits(compiles, cInterval.expand(dur!"days"(5))));
5234     static assert(!__traits(compiles, iInterval.expand(dur!"days"(5))));
5235 
5236     //Verify Examples.
5237     auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
5238     auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
5239 
5240     interval1.expand(dur!"days"(2));
5241     assert(interval1 == PosInfInterval!Date(Date(1995, 12, 31)));
5242 
5243     interval2.expand(dur!"days"(-2));
5244     assert(interval2 == PosInfInterval!Date(Date(1996, 1, 4)));
5245 }
5246 
5247 //Test PosInfInterval's expand(int, int, AllowDayOverflow).
5248 @safe unittest
5249 {
5250     import std.datetime.date;
5251 
5252     {
5253         auto interval = PosInfInterval!Date(Date(2000, 7, 4));
5254 
5255         static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow,
5256                                     in I expected, size_t line = __LINE__)
5257         {
5258             interval.expand(years, months, allow);
5259             assert(interval == expected);
5260         }
5261 
5262         testInterval(interval, 5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(1995, 7, 4)));
5263         testInterval(interval, -5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(2005, 7, 4)));
5264 
5265         auto interval2 = PosInfInterval!Date(Date(2000, 1, 29));
5266 
5267         testInterval(interval2, 1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1998, 12, 29)));
5268         testInterval(interval2, 1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1999, 3, 1)));
5269         testInterval(interval2, -1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2001, 3, 1)));
5270         testInterval(interval2, -1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2000, 12, 29)));
5271 
5272         testInterval(interval2, 1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(1998, 12, 29)));
5273         testInterval(interval2, 1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(1999, 2, 28)));
5274         testInterval(interval2, -1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(2001, 2, 28)));
5275         testInterval(interval2, -1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(2000, 12, 29)));
5276     }
5277 
5278     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5279     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5280     static assert(!__traits(compiles, cPosInfInterval.expand(1)));
5281     static assert(!__traits(compiles, iPosInfInterval.expand(1)));
5282 
5283     //Verify Examples.
5284     auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
5285     auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
5286 
5287     interval1.expand(2);
5288     assert(interval1 == PosInfInterval!Date(Date(1994, 1, 2)));
5289 
5290     interval2.expand(-2);
5291     assert(interval2 == PosInfInterval!Date(Date(1998, 1, 2)));
5292 }
5293 
5294 //Test PosInfInterval's fwdRange().
5295 @system unittest
5296 {
5297     import std.datetime.date;
5298 
5299     auto posInfInterval = PosInfInterval!Date(Date(2010, 9, 19));
5300 
5301     static void testInterval(PosInfInterval!Date posInfInterval)
5302     {
5303         posInfInterval.fwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).popFront();
5304     }
5305 
5306     assertThrown!DateTimeException(testInterval(posInfInterval));
5307 
5308     assert(PosInfInterval!Date(Date(2010, 9, 12)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).front ==
5309            Date(2010, 9, 12));
5310 
5311     assert(PosInfInterval!Date(Date(2010, 9, 12)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri), PopFirst.yes).front ==
5312            Date(2010, 9, 17));
5313 
5314     //Verify Examples.
5315     auto interval = PosInfInterval!Date(Date(2010, 9, 1));
5316     auto func = delegate (scope const Date date)
5317                 {
5318                     if ((date.day & 1) == 0)
5319                         return date + dur!"days"(2);
5320                     return date + dur!"days"(1);
5321                 };
5322     auto range = interval.fwdRange(func);
5323 
5324     assert(range.front == Date(2010, 9, 1)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2).
5325 
5326     range.popFront();
5327     assert(range.front == Date(2010, 9, 2));
5328 
5329     range.popFront();
5330     assert(range.front == Date(2010, 9, 4));
5331 
5332     range.popFront();
5333     assert(range.front == Date(2010, 9, 6));
5334 
5335     range.popFront();
5336     assert(range.front == Date(2010, 9, 8));
5337 
5338     range.popFront();
5339     assert(!range.empty);
5340 
5341     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5342     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5343     assert(!cPosInfInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty);
5344     assert(!iPosInfInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty);
5345 }
5346 
5347 //Test PosInfInterval's toString().
5348 @safe unittest
5349 {
5350     import std.datetime.date;
5351     assert(PosInfInterval!Date(Date(2010, 7, 4)).toString() == "[2010-Jul-04 - ∞)");
5352 
5353     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5354     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
5355     assert(cPosInfInterval.toString());
5356     assert(iPosInfInterval.toString());
5357 }
5358 
5359 
5360 /++
5361     Represents an interval of time which has negative infinity as its starting
5362     point.
5363 
5364     Any ranges which iterate over a `NegInfInterval` are infinite. So, the
5365     main purpose of using `NegInfInterval` is to create an infinite range
5366     which starts at negative infinity and goes to a fixed end point.
5367     Iterate over it in reverse.
5368   +/
5369 struct NegInfInterval(TP)
5370 {
5371 public:
5372 
5373     /++
5374         Params:
5375             end = The time point which ends the interval.
5376 
5377         Example:
5378 --------------------
5379 auto interval = PosInfInterval!Date(Date(1996, 1, 2));
5380 --------------------
5381       +/
5382     this(scope const TP end) pure nothrow
5383     {
5384         _end = cast(TP) end;
5385     }
5386 
5387 
5388     /++
5389         Params:
5390             rhs = The `NegInfInterval` to assign to this one.
5391       +/
5392     ref NegInfInterval opAssign(const ref NegInfInterval rhs) pure nothrow
5393     {
5394         _end = cast(TP) rhs._end;
5395         return this;
5396     }
5397 
5398 
5399     /++
5400         Params:
5401             rhs = The `NegInfInterval` to assign to this one.
5402       +/
5403     ref NegInfInterval opAssign(NegInfInterval rhs) pure nothrow
5404     {
5405         _end = cast(TP) rhs._end;
5406         return this;
5407     }
5408 
5409 
5410     /++
5411         The end point of the interval. It is excluded from the interval.
5412 
5413         Example:
5414 --------------------
5415 assert(NegInfInterval!Date(Date(2012, 3, 1)).end == Date(2012, 3, 1));
5416 --------------------
5417       +/
5418     @property TP end() const pure nothrow
5419     {
5420         return cast(TP)_end;
5421     }
5422 
5423 
5424     /++
5425         The end point of the interval. It is excluded from the interval.
5426 
5427         Params:
5428             timePoint = The time point to set end to.
5429       +/
5430     @property void end(TP timePoint) pure nothrow
5431     {
5432         _end = timePoint;
5433     }
5434 
5435 
5436     /++
5437         Whether the interval's length is 0. Always returns false.
5438 
5439         Example:
5440 --------------------
5441 assert(!NegInfInterval!Date(Date(1996, 1, 2)).empty);
5442 --------------------
5443       +/
5444     enum bool empty = false;
5445 
5446 
5447     /++
5448         Whether the given time point is within this interval.
5449 
5450         Params:
5451             timePoint = The time point to check for inclusion in this interval.
5452 
5453         Example:
5454 --------------------
5455 assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(1994, 12, 24)));
5456 assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2000, 1, 5)));
5457 assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2012, 3, 1)));
5458 --------------------
5459       +/
5460     bool contains(TP timePoint) const pure nothrow
5461     {
5462         return timePoint < _end;
5463     }
5464 
5465 
5466     /++
5467         Whether the given interval is completely within this interval.
5468 
5469         Params:
5470             interval = The interval to check for inclusion in this interval.
5471 
5472         Throws:
5473             $(REF DateTimeException,std,datetime,date) if the given interval
5474             is empty.
5475 
5476         Example:
5477 --------------------
5478 assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(
5479             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
5480 
5481 assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(
5482             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
5483 
5484 assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(
5485             Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
5486 --------------------
5487       +/
5488     bool contains(scope const Interval!TP interval) const pure
5489     {
5490         interval._enforceNotEmpty();
5491         return interval._end <= _end;
5492     }
5493 
5494 
5495     /++
5496         Whether the given interval is completely within this interval.
5497 
5498         Always returns false because an interval beginning at negative
5499         infinity can never contain an interval going to positive infinity.
5500 
5501         Params:
5502             interval = The interval to check for inclusion in this interval.
5503 
5504         Example:
5505 --------------------
5506 assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(
5507             PosInfInterval!Date(Date(1999, 5, 4))));
5508 --------------------
5509       +/
5510     bool contains(scope const PosInfInterval!TP interval) const pure nothrow
5511     {
5512         return false;
5513     }
5514 
5515 
5516     /++
5517         Whether the given interval is completely within this interval.
5518 
5519         Params:
5520             interval = The interval to check for inclusion in this interval.
5521 
5522         Example:
5523 --------------------
5524 assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(
5525             NegInfInterval!Date(Date(1996, 5, 4))));
5526 
5527 assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(
5528             NegInfInterval!Date(Date(2013, 7, 9))));
5529 --------------------
5530       +/
5531     bool contains(scope const NegInfInterval interval) const pure nothrow
5532     {
5533         return interval._end <= _end;
5534     }
5535 
5536 
5537     /++
5538         Whether this interval is before the given time point.
5539 
5540         Params:
5541             timePoint = The time point to check whether this interval is
5542                         before it.
5543 
5544         Example:
5545 --------------------
5546 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(1994, 12, 24)));
5547 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2000, 1, 5)));
5548 assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2012, 3, 1)));
5549 --------------------
5550       +/
5551     bool isBefore(scope const TP timePoint) const pure nothrow
5552     {
5553         return timePoint >= _end;
5554     }
5555 
5556 
5557     /++
5558         Whether this interval is before the given interval and does not
5559         intersect it.
5560 
5561         Params:
5562             interval = The interval to check for against this interval.
5563 
5564         Throws:
5565             $(REF DateTimeException,std,datetime,date) if the given interval
5566             is empty
5567 
5568         Example:
5569 --------------------
5570 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(
5571             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
5572 
5573 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(
5574             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
5575 
5576 assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(
5577             Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
5578 --------------------
5579       +/
5580     bool isBefore(scope const Interval!TP interval) const pure
5581     {
5582         interval._enforceNotEmpty();
5583         return _end <= interval._begin;
5584     }
5585 
5586 
5587     /++
5588         Whether this interval is before the given interval and does not
5589         intersect it.
5590 
5591         Params:
5592             interval = The interval to check for against this interval.
5593 
5594         Example:
5595 --------------------
5596 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(
5597             PosInfInterval!Date(Date(1999, 5, 4))));
5598 
5599 assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(
5600             PosInfInterval!Date(Date(2012, 3, 1))));
5601 --------------------
5602       +/
5603     bool isBefore(scope const PosInfInterval!TP interval) const pure nothrow
5604     {
5605         return _end <= interval._begin;
5606     }
5607 
5608 
5609     /++
5610         Whether this interval is before the given interval and does not
5611         intersect it.
5612 
5613         Always returns false because an interval beginning at negative
5614         infinity can never be before another interval beginning at negative
5615         infinity.
5616 
5617         Params:
5618             interval = The interval to check for against this interval.
5619 
5620         Example:
5621 --------------------
5622 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(
5623             NegInfInterval!Date(Date(1996, 5, 4))));
5624 
5625 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(
5626             NegInfInterval!Date(Date(2013, 7, 9))));
5627 --------------------
5628       +/
5629     bool isBefore(scope const NegInfInterval interval) const pure nothrow
5630     {
5631         return false;
5632     }
5633 
5634 
5635     /++
5636         Whether this interval is after the given time point.
5637 
5638         Always returns false because an interval beginning at negative infinity
5639         can never be after any time point.
5640 
5641         Params:
5642             timePoint = The time point to check whether this interval is after
5643                         it.
5644 
5645         Example:
5646 --------------------
5647 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(1994, 12, 24)));
5648 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2000, 1, 5)));
5649 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2012, 3, 1)));
5650 --------------------
5651       +/
5652     bool isAfter(scope const TP timePoint) const pure nothrow
5653     {
5654         return false;
5655     }
5656 
5657 
5658     /++
5659         Whether this interval is after the given interval and does not
5660         intersect it.
5661 
5662         Always returns false (unless the given interval is empty) because an
5663         interval beginning at negative infinity can never be after any other
5664         interval.
5665 
5666         Params:
5667             interval = The interval to check against this interval.
5668 
5669         Throws:
5670             $(REF DateTimeException,std,datetime,date) if the given interval
5671             is empty.
5672 
5673         Example:
5674 --------------------
5675 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(
5676             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
5677 
5678 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(
5679             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
5680 
5681 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(
5682             Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
5683 --------------------
5684       +/
5685     bool isAfter(scope const Interval!TP interval) const pure
5686     {
5687         interval._enforceNotEmpty();
5688         return false;
5689     }
5690 
5691 
5692     /++
5693         Whether this interval is after the given interval and does not intersect
5694         it.
5695 
5696         Always returns false because an interval beginning at negative infinity
5697         can never be after any other interval.
5698 
5699         Params:
5700             interval = The interval to check against this interval.
5701 
5702         Example:
5703 --------------------
5704 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(
5705             PosInfInterval!Date(Date(1999, 5, 4))));
5706 
5707 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(
5708             PosInfInterval!Date(Date(2012, 3, 1))));
5709 --------------------
5710       +/
5711     bool isAfter(scope const PosInfInterval!TP interval) const pure nothrow
5712     {
5713         return false;
5714     }
5715 
5716 
5717     /++
5718         Whether this interval is after the given interval and does not intersect
5719         it.
5720 
5721         Always returns false because an interval beginning at negative infinity
5722         can never be after any other interval.
5723 
5724         Params:
5725             interval = The interval to check against this interval.
5726 
5727         Example:
5728 --------------------
5729 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(
5730             NegInfInterval!Date(Date(1996, 5, 4))));
5731 
5732 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(
5733             NegInfInterval!Date(Date(2013, 7, 9))));
5734 --------------------
5735       +/
5736     bool isAfter(scope const NegInfInterval interval) const pure nothrow
5737     {
5738         return false;
5739     }
5740 
5741 
5742     /++
5743         Whether the given interval overlaps this interval.
5744 
5745         Params:
5746             interval = The interval to check for intersection with this interval.
5747 
5748         Throws:
5749             $(REF DateTimeException,std,datetime,date) if the given interval
5750             is empty.
5751 
5752         Example:
5753 --------------------
5754 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(
5755             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
5756 
5757 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(
5758             Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
5759 
5760 assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects(
5761             Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
5762 --------------------
5763       +/
5764     bool intersects(scope const Interval!TP interval) const pure
5765     {
5766         interval._enforceNotEmpty();
5767         return interval._begin < _end;
5768     }
5769 
5770 
5771     /++
5772         Whether the given interval overlaps this interval.
5773 
5774         Params:
5775             interval = The interval to check for intersection with this
5776                        interval.
5777 
5778         Example:
5779 --------------------
5780 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(
5781             PosInfInterval!Date(Date(1999, 5, 4))));
5782 
5783 assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects(
5784             PosInfInterval!Date(Date(2012, 3, 1))));
5785 --------------------
5786       +/
5787     bool intersects(scope const PosInfInterval!TP interval) const pure nothrow
5788     {
5789         return interval._begin < _end;
5790     }
5791 
5792 
5793     /++
5794         Whether the given interval overlaps this interval.
5795 
5796         Always returns true because two intervals beginning at negative infinity
5797         always overlap.
5798 
5799         Params:
5800             interval = The interval to check for intersection with this interval.
5801 
5802         Example:
5803 --------------------
5804 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(
5805             NegInfInterval!Date(Date(1996, 5, 4))));
5806 
5807 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(
5808             NegInfInterval!Date(Date(2013, 7, 9))));
5809 --------------------
5810       +/
5811     bool intersects(scope const NegInfInterval!TP interval) const pure nothrow
5812     {
5813         return true;
5814     }
5815 
5816 
5817     /++
5818         Returns the intersection of two intervals
5819 
5820         Params:
5821             interval = The interval to intersect with this interval.
5822 
5823         Throws:
5824             $(REF DateTimeException,std,datetime,date) if the two intervals do
5825             not intersect or if the given interval is empty.
5826 
5827         Example:
5828 --------------------
5829 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(
5830             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
5831        Interval!Date(Date(1990, 7 , 6), Date(2000, 8, 2)));
5832 
5833 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(
5834             Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) ==
5835        Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1)));
5836 --------------------
5837       +/
5838     Interval!TP intersection(scope const Interval!TP interval) const
5839     {
5840         import std.format : format;
5841 
5842         enforce(this.intersects(interval),
5843                 new DateTimeException(format("%s and %s do not intersect.", this, interval)));
5844 
5845         auto end = _end < interval._end ? _end : interval._end;
5846 
5847         return Interval!TP(interval._begin, end);
5848     }
5849 
5850 
5851     /++
5852         Returns the intersection of two intervals
5853 
5854         Params:
5855             interval = The interval to intersect with this interval.
5856 
5857         Throws:
5858             $(REF DateTimeException,std,datetime,date) if the two intervals do
5859             not intersect.
5860 
5861         Example:
5862 --------------------
5863 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(
5864             PosInfInterval!Date(Date(1990, 7, 6))) ==
5865        Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
5866 
5867 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(
5868             PosInfInterval!Date(Date(1999, 1, 12))) ==
5869        Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1)));
5870 --------------------
5871       +/
5872     Interval!TP intersection(scope const PosInfInterval!TP interval) const
5873     {
5874         import std.format : format;
5875 
5876         enforce(this.intersects(interval),
5877                 new DateTimeException(format("%s and %s do not intersect.", this, interval)));
5878 
5879         return Interval!TP(interval._begin, _end);
5880     }
5881 
5882 
5883     /++
5884         Returns the intersection of two intervals
5885 
5886         Params:
5887             interval = The interval to intersect with this interval.
5888 
5889         Example:
5890 --------------------
5891 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(
5892             NegInfInterval!Date(Date(1999, 7, 6))) ==
5893        NegInfInterval!Date(Date(1999, 7 , 6)));
5894 
5895 assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(
5896             NegInfInterval!Date(Date(2013, 1, 12))) ==
5897        NegInfInterval!Date(Date(2012, 3 , 1)));
5898 --------------------
5899       +/
5900     NegInfInterval intersection(scope const NegInfInterval interval) const nothrow
5901     {
5902         return NegInfInterval(_end < interval._end ? _end : interval._end);
5903     }
5904 
5905 
5906     /++
5907         Whether the given interval is adjacent to this interval.
5908 
5909         Params:
5910             interval = The interval to check whether its adjecent to this
5911                        interval.
5912 
5913         Throws:
5914             $(REF DateTimeException,std,datetime,date) if the given interval
5915             is empty.
5916 
5917         Example:
5918 --------------------
5919 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(
5920             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
5921 
5922 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(
5923             Interval!Date(Date(1999, 1, 12), Date(2012, 3, 1))));
5924 
5925 assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(
5926             Interval!Date(Date(2012, 3, 1), Date(2019, 2, 2))));
5927 
5928 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(
5929             Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
5930 --------------------
5931       +/
5932     bool isAdjacent(scope const Interval!TP interval) const pure
5933     {
5934         interval._enforceNotEmpty();
5935         return interval._begin == _end;
5936     }
5937 
5938 
5939     /++
5940         Whether the given interval is adjacent to this interval.
5941 
5942         Params:
5943             interval = The interval to check whether its adjecent to this
5944                        interval.
5945 
5946         Example:
5947 --------------------
5948 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(
5949             PosInfInterval!Date(Date(1999, 5, 4))));
5950 
5951 assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(
5952             PosInfInterval!Date(Date(2012, 3, 1))));
5953 --------------------
5954       +/
5955     bool isAdjacent(scope const PosInfInterval!TP interval) const pure nothrow
5956     {
5957         return interval._begin == _end;
5958     }
5959 
5960 
5961     /++
5962         Whether the given interval is adjacent to this interval.
5963 
5964         Always returns false because two intervals beginning at negative
5965         infinity can never be adjacent to one another.
5966 
5967         Params:
5968             interval = The interval to check whether its adjecent to this
5969                        interval.
5970 
5971         Example:
5972 --------------------
5973 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(
5974             NegInfInterval!Date(Date(1996, 5, 4))));
5975 
5976 assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(
5977             NegInfInterval!Date(Date(2012, 3, 1))));
5978 --------------------
5979       +/
5980     bool isAdjacent(scope const NegInfInterval interval) const pure nothrow
5981     {
5982         return false;
5983     }
5984 
5985 
5986     /++
5987         Returns the union of two intervals
5988 
5989         Params:
5990             interval = The interval to merge with this interval.
5991 
5992         Throws:
5993             $(REF DateTimeException,std,datetime,date) if the two intervals do
5994             not intersect and are not adjacent or if the given interval is empty.
5995 
5996         Note:
5997             There is no overload for `merge` which takes a
5998             `PosInfInterval`, because an interval
5999             going from negative infinity to positive infinity
6000             is not possible.
6001 
6002         Example:
6003 --------------------
6004 assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(
6005             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
6006        NegInfInterval!Date(Date(2012, 3 , 1)));
6007 
6008 assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(
6009             Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) ==
6010        NegInfInterval!Date(Date(2015, 9 , 2)));
6011 --------------------
6012       +/
6013     NegInfInterval merge(scope const Interval!TP interval) const
6014     {
6015         import std.format : format;
6016 
6017         enforce(this.isAdjacent(interval) || this.intersects(interval),
6018                 new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval)));
6019 
6020         return NegInfInterval(_end > interval._end ? _end : interval._end);
6021     }
6022 
6023 
6024     /++
6025         Returns the union of two intervals
6026 
6027         Params:
6028             interval = The interval to merge with this interval.
6029 
6030         Note:
6031             There is no overload for `merge` which takes a
6032             `PosInfInterval`, because an interval
6033             going from negative infinity to positive infinity
6034             is not possible.
6035 
6036         Example:
6037 --------------------
6038 assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(
6039             NegInfInterval!Date(Date(1999, 7, 6))) ==
6040        NegInfInterval!Date(Date(2012, 3 , 1)));
6041 
6042 assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(
6043             NegInfInterval!Date(Date(2013, 1, 12))) ==
6044        NegInfInterval!Date(Date(2013, 1 , 12)));
6045 --------------------
6046       +/
6047     NegInfInterval merge(scope const NegInfInterval interval) const pure nothrow
6048     {
6049         return NegInfInterval(_end > interval._end ? _end : interval._end);
6050     }
6051 
6052 
6053     /++
6054         Returns an interval that covers from the earliest time point of two
6055         intervals up to (but not including) the latest time point of two
6056         intervals.
6057 
6058         Params:
6059             interval = The interval to create a span together with this
6060                        interval.
6061 
6062         Throws:
6063             $(REF DateTimeException,std,datetime,date) if the given interval
6064             is empty.
6065 
6066         Note:
6067             There is no overload for `span` which takes a
6068             `PosInfInterval`, because an interval
6069             going from negative infinity to positive infinity
6070             is not possible.
6071 
6072         Example:
6073 --------------------
6074 assert(NegInfInterval!Date(Date(2012, 3, 1)).span(
6075             Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
6076        NegInfInterval!Date(Date(2012, 3 , 1)));
6077 
6078 assert(NegInfInterval!Date(Date(2012, 3, 1)).span(
6079             Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) ==
6080        NegInfInterval!Date(Date(2015, 9 , 2)));
6081 
6082 assert(NegInfInterval!Date(Date(1600, 1, 7)).span(
6083             Interval!Date(Date(2012, 3, 11), Date(2017, 7, 1))) ==
6084        NegInfInterval!Date(Date(2017, 7 , 1)));
6085 --------------------
6086       +/
6087     NegInfInterval span(scope const Interval!TP interval) const pure
6088     {
6089         interval._enforceNotEmpty();
6090         return NegInfInterval(_end > interval._end ? _end : interval._end);
6091     }
6092 
6093 
6094     /++
6095         Returns an interval that covers from the earliest time point of two
6096         intervals up to (but not including) the latest time point of two
6097         intervals.
6098 
6099         Params:
6100             interval = The interval to create a span together with this
6101                        interval.
6102 
6103         Note:
6104             There is no overload for `span` which takes a
6105             `PosInfInterval`, because an interval
6106             going from negative infinity to positive infinity
6107             is not possible.
6108 
6109         Example:
6110 --------------------
6111 assert(NegInfInterval!Date(Date(2012, 3, 1)).span(
6112             NegInfInterval!Date(Date(1999, 7, 6))) ==
6113        NegInfInterval!Date(Date(2012, 3 , 1)));
6114 
6115 assert(NegInfInterval!Date(Date(2012, 3, 1)).span(
6116             NegInfInterval!Date(Date(2013, 1, 12))) ==
6117        NegInfInterval!Date(Date(2013, 1 , 12)));
6118 --------------------
6119       +/
6120     NegInfInterval span(scope const NegInfInterval interval) const pure nothrow
6121     {
6122         return NegInfInterval(_end > interval._end ? _end : interval._end);
6123     }
6124 
6125 
6126     /++
6127         Shifts the `end` of this interval forward or backwards in time by the
6128         given duration (a positive duration shifts the interval forward; a
6129         negative duration shifts it backward). Effectively, it does
6130         $(D end += duration).
6131 
6132         Params:
6133             duration = The duration to shift the interval by.
6134 
6135         Example:
6136 --------------------
6137 auto interval1 = NegInfInterval!Date(Date(2012, 4, 5));
6138 auto interval2 = NegInfInterval!Date(Date(2012, 4, 5));
6139 
6140 interval1.shift(dur!"days"(50));
6141 assert(interval1 == NegInfInterval!Date(Date(2012, 5, 25)));
6142 
6143 interval2.shift(dur!"days"(-50));
6144 assert(interval2 == NegInfInterval!Date( Date(2012, 2, 15)));
6145 --------------------
6146       +/
6147     void shift(D)(D duration) pure nothrow
6148         if (__traits(compiles, end + duration))
6149     {
6150         _end += duration;
6151     }
6152 
6153 
6154     static if (__traits(compiles, end.add!"months"(1)) &&
6155                __traits(compiles, end.add!"years"(1)))
6156     {
6157         /++
6158             Shifts the `end` of this interval forward or backwards in time by
6159             the given number of years and/or months (a positive number of years
6160             and months shifts the interval forward; a negative number shifts it
6161             backward). It adds the years the given years and months to end. It
6162             effectively calls `add!"years"()` and then `add!"months"()`
6163             on end with the given number of years and months.
6164 
6165             Params:
6166                 years         = The number of years to shift the interval by.
6167                 months        = The number of months to shift the interval by.
6168                 allowOverflow = Whether the days should be allowed to overflow
6169                                 on `end`, causing its month to increment.
6170 
6171             Throws:
6172                 $(REF DateTimeException,std,datetime,date) if empty is true or
6173                 if the resulting interval would be invalid.
6174 
6175             Example:
6176 --------------------
6177 auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
6178 auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
6179 
6180 interval1.shift(2);
6181 assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1)));
6182 
6183 interval2.shift(-2);
6184 assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1)));
6185 --------------------
6186           +/
6187         void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
6188             if (isIntegral!T)
6189         {
6190             auto end = _end;
6191 
6192             end.add!"years"(years, allowOverflow);
6193             end.add!"months"(months, allowOverflow);
6194 
6195             _end = end;
6196         }
6197     }
6198 
6199 
6200     /++
6201         Expands the interval forwards in time. Effectively, it does
6202         $(D end += duration).
6203 
6204         Params:
6205             duration = The duration to expand the interval by.
6206 
6207         Example:
6208 --------------------
6209 auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
6210 auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
6211 
6212 interval1.expand(dur!"days"(2));
6213 assert(interval1 == NegInfInterval!Date(Date(2012, 3, 3)));
6214 
6215 interval2.expand(dur!"days"(-2));
6216 assert(interval2 == NegInfInterval!Date(Date(2012, 2, 28)));
6217 --------------------
6218       +/
6219     void expand(D)(D duration) pure nothrow
6220         if (__traits(compiles, end + duration))
6221     {
6222         _end += duration;
6223     }
6224 
6225 
6226     static if (__traits(compiles, end.add!"months"(1)) &&
6227                __traits(compiles, end.add!"years"(1)))
6228     {
6229         /++
6230             Expands the interval forwards and/or backwards in time. Effectively,
6231             it adds the given number of months/years to end.
6232 
6233             Params:
6234                 years         = The number of years to expand the interval by.
6235                 months        = The number of months to expand the interval by.
6236                 allowOverflow = Whether the days should be allowed to overflow
6237                                 on `end`, causing their month to increment.
6238 
6239             Throws:
6240                 $(REF DateTimeException,std,datetime,date) if empty is true or
6241                 if the resulting interval would be invalid.
6242 
6243             Example:
6244 --------------------
6245 auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
6246 auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
6247 
6248 interval1.expand(2);
6249 assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1)));
6250 
6251 interval2.expand(-2);
6252 assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1)));
6253 --------------------
6254           +/
6255         void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
6256             if (isIntegral!T)
6257         {
6258             auto end = _end;
6259 
6260             end.add!"years"(years, allowOverflow);
6261             end.add!"months"(months, allowOverflow);
6262 
6263             _end = end;
6264         }
6265     }
6266 
6267 
6268     /++
6269         Returns a range which iterates backwards over the interval, starting
6270         at `end`, using $(D_PARAM func) to generate each successive time
6271         point.
6272 
6273         The range's `front` is the interval's `end`. $(D_PARAM func) is
6274         used to generate the next `front` when `popFront` is called. If
6275         $(D_PARAM popFirst) is `PopFirst.yes`, then `popFront` is called
6276         before the range is returned (so that `front` is a time point which
6277         $(D_PARAM func) would generate).
6278 
6279         If $(D_PARAM func) ever generates a time point greater than or equal to
6280         the current `front` of the range, then a
6281         $(REF DateTimeException,std,datetime,date) will be thrown.
6282 
6283         There are helper functions in this module which generate common
6284         delegates to pass to `bwdRange`. Their documentation starts with
6285         "Range-generating function," to make them easily searchable.
6286 
6287         Params:
6288             func     = The function used to generate the time points of the
6289                        range over the interval.
6290             popFirst = Whether `popFront` should be called on the range
6291                        before returning it.
6292 
6293         Throws:
6294             $(REF DateTimeException,std,datetime,date) if this interval is
6295             empty.
6296 
6297         Warning:
6298             $(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func)
6299             would be a function pointer to a pure function, but forcing
6300             $(D_PARAM func) to be pure is far too restrictive to be useful, and
6301             in order to have the ease of use of having functions which generate
6302             functions to pass to `fwdRange`, $(D_PARAM func) must be a
6303             delegate.
6304 
6305             If $(D_PARAM func) retains state which changes as it is called, then
6306             some algorithms will not work correctly, because the range's
6307             `save` will have failed to have really saved the range's state.
6308             To avoid such bugs, don't pass a delegate which is
6309             not logically pure to `fwdRange`. If $(D_PARAM func) is given the
6310             same time point with two different calls, it must return the same
6311             result both times.
6312 
6313             Of course, none of the functions in this module have this problem,
6314             so it's only relevant for custom delegates.
6315 
6316         Example:
6317 --------------------
6318 auto interval = NegInfInterval!Date(Date(2010, 9, 9));
6319 auto func = delegate (scope const Date date) //For iterating over even-numbered days.
6320             {
6321                 if ((date.day & 1) == 0)
6322                     return date - dur!"days"(2);
6323 
6324                 return date - dur!"days"(1);
6325             };
6326 auto range = interval.bwdRange(func);
6327 
6328 assert(range.front == Date(2010, 9, 9)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8).
6329 
6330 range.popFront();
6331 assert(range.front == Date(2010, 9, 8));
6332 
6333 range.popFront();
6334 assert(range.front == Date(2010, 9, 6));
6335 
6336 range.popFront();
6337 assert(range.front == Date(2010, 9, 4));
6338 
6339 range.popFront();
6340 assert(range.front == Date(2010, 9, 2));
6341 
6342 range.popFront();
6343 assert(!range.empty);
6344 --------------------
6345       +/
6346     NegInfIntervalRange!(TP) bwdRange(TP delegate(scope const TP) func, PopFirst popFirst = PopFirst.no) const
6347     {
6348         auto range = NegInfIntervalRange!(TP)(this, func);
6349 
6350         if (popFirst == PopFirst.yes)
6351             range.popFront();
6352 
6353         return range;
6354     }
6355 
6356 
6357     /+
6358         Converts this interval to a string.
6359       +/
6360     // Due to bug https://issues.dlang.org/show_bug.cgi?id=3715 , we can't
6361     // have versions of toString() with extra modifiers,
6362     // so we define one version with modifiers and one without.
6363     string toString()
6364     {
6365         return _toStringImpl();
6366     }
6367 
6368 
6369     /++
6370         Converts this interval to a string.
6371       +/
6372     // Due to bug https://issues.dlang.org/show_bug.cgi?id=3715 , we can't
6373     // have versions of toString() with extra modifiers,
6374     // so we define one version with modifiers and one without.
6375     string toString() const nothrow
6376     {
6377         return _toStringImpl();
6378     }
6379 
6380 private:
6381 
6382     /+
6383         Since we have two versions of toString(), we have _toStringImpl()
6384         so that they can share implementations.
6385       +/
6386     string _toStringImpl() const nothrow
6387     {
6388         import std.format : format;
6389         try
6390             return format("[-∞ - %s)", _end);
6391         catch (Exception e)
6392             assert(0, "format() threw.");
6393     }
6394 
6395 
6396     TP _end;
6397 }
6398 
6399 //Test NegInfInterval's constructor.
6400 @safe unittest
6401 {
6402     import std.datetime.date;
6403     import std.datetime.systime;
6404 
6405     NegInfInterval!Date(Date.init);
6406     NegInfInterval!TimeOfDay(TimeOfDay.init);
6407     NegInfInterval!DateTime(DateTime.init);
6408     NegInfInterval!SysTime(SysTime(0));
6409 }
6410 
6411 //Test NegInfInterval's end.
6412 @safe unittest
6413 {
6414     import std.datetime.date;
6415 
6416     assert(NegInfInterval!Date(Date(2010, 1, 1)).end == Date(2010, 1, 1));
6417     assert(NegInfInterval!Date(Date(2010, 1, 1)).end == Date(2010, 1, 1));
6418     assert(NegInfInterval!Date(Date(1998, 1, 1)).end == Date(1998, 1, 1));
6419 
6420     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6421     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6422     assert(cNegInfInterval.end != Date.init);
6423     assert(iNegInfInterval.end != Date.init);
6424 
6425     //Verify Examples.
6426     assert(NegInfInterval!Date(Date(2012, 3, 1)).end == Date(2012, 3, 1));
6427 }
6428 
6429 //Test NegInfInterval's empty.
6430 @safe unittest
6431 {
6432     import std.datetime.date;
6433     import std.datetime.systime;
6434 
6435     assert(!NegInfInterval!Date(Date(2010, 1, 1)).empty);
6436     assert(!NegInfInterval!TimeOfDay(TimeOfDay(0, 30, 0)).empty);
6437     assert(!NegInfInterval!DateTime(DateTime(2010, 1, 1, 0, 30, 0)).empty);
6438     assert(!NegInfInterval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0))).empty);
6439 
6440     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6441     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6442     assert(!cNegInfInterval.empty);
6443     assert(!iNegInfInterval.empty);
6444 
6445     //Verify Examples.
6446     assert(!NegInfInterval!Date(Date(1996, 1, 2)).empty);
6447 }
6448 
6449 //Test NegInfInterval's contains(time point).
6450 @safe unittest
6451 {
6452     import std.datetime.date;
6453 
6454     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6455 
6456     assert(negInfInterval.contains(Date(2009, 7, 4)));
6457     assert(negInfInterval.contains(Date(2010, 7, 3)));
6458     assert(negInfInterval.contains(Date(2010, 7, 4)));
6459     assert(negInfInterval.contains(Date(2010, 7, 5)));
6460     assert(negInfInterval.contains(Date(2011, 7, 1)));
6461     assert(negInfInterval.contains(Date(2012, 1, 6)));
6462     assert(!negInfInterval.contains(Date(2012, 1, 7)));
6463     assert(!negInfInterval.contains(Date(2012, 1, 8)));
6464     assert(!negInfInterval.contains(Date(2013, 1, 7)));
6465 
6466     const cdate = Date(2010, 7, 6);
6467     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6468     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6469     assert(negInfInterval.contains(cdate));
6470     assert(cNegInfInterval.contains(cdate));
6471     assert(iNegInfInterval.contains(cdate));
6472 
6473     //Verify Examples.
6474     assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(1994, 12, 24)));
6475     assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2000, 1, 5)));
6476     assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2012, 3, 1)));
6477 }
6478 
6479 //Test NegInfInterval's contains(Interval).
6480 @safe unittest
6481 {
6482     import std.datetime.date;
6483 
6484     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6485 
6486     static void testInterval(scope const NegInfInterval!Date negInfInterval, scope const Interval!Date interval)
6487     {
6488         negInfInterval.contains(interval);
6489     }
6490 
6491     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
6492 
6493     assert(negInfInterval.contains(negInfInterval));
6494     assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
6495     assert(!negInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
6496     assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
6497     assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
6498     assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
6499     assert(!negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
6500     assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
6501     assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
6502     assert(negInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
6503     assert(!negInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
6504     assert(!negInfInterval.contains(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
6505     assert(!negInfInterval.contains(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
6506 
6507     assert(negInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 3))));
6508     assert(negInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 4))));
6509     assert(negInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 5))));
6510     assert(negInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 6))));
6511     assert(negInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 7))));
6512     assert(!negInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 8))));
6513 
6514     assert(!NegInfInterval!Date(Date(2010, 7, 3)).contains(negInfInterval));
6515     assert(!NegInfInterval!Date(Date(2010, 7, 4)).contains(negInfInterval));
6516     assert(!NegInfInterval!Date(Date(2010, 7, 5)).contains(negInfInterval));
6517     assert(!NegInfInterval!Date(Date(2012, 1, 6)).contains(negInfInterval));
6518     assert(NegInfInterval!Date(Date(2012, 1, 7)).contains(negInfInterval));
6519     assert(NegInfInterval!Date(Date(2012, 1, 8)).contains(negInfInterval));
6520 
6521     assert(!negInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 3))));
6522     assert(!negInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 4))));
6523     assert(!negInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 5))));
6524     assert(!negInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 6))));
6525     assert(!negInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 7))));
6526     assert(!negInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 8))));
6527 
6528     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6529     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6530     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6531     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6532     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6533     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6534     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6535     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6536     assert(negInfInterval.contains(interval));
6537     assert(negInfInterval.contains(cInterval));
6538     assert(negInfInterval.contains(iInterval));
6539     assert(!negInfInterval.contains(posInfInterval));
6540     assert(!negInfInterval.contains(cPosInfInterval));
6541     assert(!negInfInterval.contains(iPosInfInterval));
6542     assert(negInfInterval.contains(negInfInterval));
6543     assert(negInfInterval.contains(cNegInfInterval));
6544     assert(negInfInterval.contains(iNegInfInterval));
6545     assert(cNegInfInterval.contains(interval));
6546     assert(cNegInfInterval.contains(cInterval));
6547     assert(cNegInfInterval.contains(iInterval));
6548     assert(!cNegInfInterval.contains(posInfInterval));
6549     assert(!cNegInfInterval.contains(cPosInfInterval));
6550     assert(!cNegInfInterval.contains(iPosInfInterval));
6551     assert(cNegInfInterval.contains(negInfInterval));
6552     assert(cNegInfInterval.contains(cNegInfInterval));
6553     assert(cNegInfInterval.contains(iNegInfInterval));
6554     assert(iNegInfInterval.contains(interval));
6555     assert(iNegInfInterval.contains(cInterval));
6556     assert(iNegInfInterval.contains(iInterval));
6557     assert(!iNegInfInterval.contains(posInfInterval));
6558     assert(!iNegInfInterval.contains(cPosInfInterval));
6559     assert(!iNegInfInterval.contains(iPosInfInterval));
6560     assert(iNegInfInterval.contains(negInfInterval));
6561     assert(iNegInfInterval.contains(cNegInfInterval));
6562     assert(iNegInfInterval.contains(iNegInfInterval));
6563 
6564     //Verify Examples.
6565     assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
6566     assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
6567     assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
6568 
6569     assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(PosInfInterval!Date(Date(1999, 5, 4))));
6570 
6571     assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(1996, 5, 4))));
6572     assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(2013, 7, 9))));
6573 }
6574 
6575 //Test NegInfInterval's isBefore(time point).
6576 @safe unittest
6577 {
6578     import std.datetime.date;
6579 
6580     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6581 
6582     assert(!negInfInterval.isBefore(Date(2009, 7, 4)));
6583     assert(!negInfInterval.isBefore(Date(2010, 7, 3)));
6584     assert(!negInfInterval.isBefore(Date(2010, 7, 4)));
6585     assert(!negInfInterval.isBefore(Date(2010, 7, 5)));
6586     assert(!negInfInterval.isBefore(Date(2011, 7, 1)));
6587     assert(!negInfInterval.isBefore(Date(2012, 1, 6)));
6588     assert(negInfInterval.isBefore(Date(2012, 1, 7)));
6589     assert(negInfInterval.isBefore(Date(2012, 1, 8)));
6590     assert(negInfInterval.isBefore(Date(2013, 1, 7)));
6591 
6592     const cdate = Date(2010, 7, 6);
6593     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6594     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6595     assert(!negInfInterval.isBefore(cdate));
6596     assert(!cNegInfInterval.isBefore(cdate));
6597     assert(!iNegInfInterval.isBefore(cdate));
6598 
6599     //Verify Examples.
6600     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(1994, 12, 24)));
6601     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2000, 1, 5)));
6602     assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2012, 3, 1)));
6603 }
6604 
6605 //Test NegInfInterval's isBefore(Interval).
6606 @safe unittest
6607 {
6608     import std.datetime.date;
6609 
6610     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6611 
6612     static void testInterval(scope const NegInfInterval!Date negInfInterval, scope const Interval!Date interval)
6613     {
6614         negInfInterval.isBefore(interval);
6615     }
6616 
6617     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
6618 
6619     assert(!negInfInterval.isBefore(negInfInterval));
6620     assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
6621     assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
6622     assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
6623     assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
6624     assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
6625     assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
6626     assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
6627     assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
6628     assert(!negInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
6629     assert(!negInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
6630     assert(negInfInterval.isBefore(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
6631     assert(negInfInterval.isBefore(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
6632 
6633     assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 3))));
6634     assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 4))));
6635     assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 5))));
6636     assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 6))));
6637     assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 7))));
6638     assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 8))));
6639 
6640     assert(!NegInfInterval!Date(Date(2010, 7, 3)).isBefore(negInfInterval));
6641     assert(!NegInfInterval!Date(Date(2010, 7, 4)).isBefore(negInfInterval));
6642     assert(!NegInfInterval!Date(Date(2010, 7, 5)).isBefore(negInfInterval));
6643     assert(!NegInfInterval!Date(Date(2012, 1, 6)).isBefore(negInfInterval));
6644     assert(!NegInfInterval!Date(Date(2012, 1, 7)).isBefore(negInfInterval));
6645     assert(!NegInfInterval!Date(Date(2012, 1, 8)).isBefore(negInfInterval));
6646 
6647     assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 3))));
6648     assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 4))));
6649     assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 5))));
6650     assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 6))));
6651     assert(negInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 7))));
6652     assert(negInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 8))));
6653 
6654     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6655     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6656     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6657     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6658     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6659     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6660     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6661     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6662     assert(!negInfInterval.isBefore(interval));
6663     assert(!negInfInterval.isBefore(cInterval));
6664     assert(!negInfInterval.isBefore(iInterval));
6665     assert(!negInfInterval.isBefore(posInfInterval));
6666     assert(!negInfInterval.isBefore(cPosInfInterval));
6667     assert(!negInfInterval.isBefore(iPosInfInterval));
6668     assert(!negInfInterval.isBefore(negInfInterval));
6669     assert(!negInfInterval.isBefore(cNegInfInterval));
6670     assert(!negInfInterval.isBefore(iNegInfInterval));
6671     assert(!cNegInfInterval.isBefore(interval));
6672     assert(!cNegInfInterval.isBefore(cInterval));
6673     assert(!cNegInfInterval.isBefore(iInterval));
6674     assert(!cNegInfInterval.isBefore(posInfInterval));
6675     assert(!cNegInfInterval.isBefore(cPosInfInterval));
6676     assert(!cNegInfInterval.isBefore(iPosInfInterval));
6677     assert(!cNegInfInterval.isBefore(negInfInterval));
6678     assert(!cNegInfInterval.isBefore(cNegInfInterval));
6679     assert(!cNegInfInterval.isBefore(iNegInfInterval));
6680     assert(!iNegInfInterval.isBefore(interval));
6681     assert(!iNegInfInterval.isBefore(cInterval));
6682     assert(!iNegInfInterval.isBefore(iInterval));
6683     assert(!iNegInfInterval.isBefore(posInfInterval));
6684     assert(!iNegInfInterval.isBefore(cPosInfInterval));
6685     assert(!iNegInfInterval.isBefore(iPosInfInterval));
6686     assert(!iNegInfInterval.isBefore(negInfInterval));
6687     assert(!iNegInfInterval.isBefore(cNegInfInterval));
6688     assert(!iNegInfInterval.isBefore(iNegInfInterval));
6689 
6690     //Verify Examples.
6691     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
6692     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
6693     assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
6694 
6695     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(1999, 5, 4))));
6696     assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(2012, 3, 1))));
6697 
6698     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(1996, 5, 4))));
6699     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(2013, 7, 9))));
6700 }
6701 
6702 //Test NegInfInterval's isAfter(time point).
6703 @safe unittest
6704 {
6705     import std.datetime.date;
6706 
6707     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6708 
6709     assert(!negInfInterval.isAfter(Date(2009, 7, 4)));
6710     assert(!negInfInterval.isAfter(Date(2010, 7, 3)));
6711     assert(!negInfInterval.isAfter(Date(2010, 7, 4)));
6712     assert(!negInfInterval.isAfter(Date(2010, 7, 5)));
6713     assert(!negInfInterval.isAfter(Date(2011, 7, 1)));
6714     assert(!negInfInterval.isAfter(Date(2012, 1, 6)));
6715     assert(!negInfInterval.isAfter(Date(2012, 1, 7)));
6716     assert(!negInfInterval.isAfter(Date(2012, 1, 8)));
6717     assert(!negInfInterval.isAfter(Date(2013, 1, 7)));
6718 
6719     const cdate = Date(2010, 7, 6);
6720     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6721     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6722     assert(!negInfInterval.isAfter(cdate));
6723     assert(!cNegInfInterval.isAfter(cdate));
6724     assert(!iNegInfInterval.isAfter(cdate));
6725 }
6726 
6727 //Test NegInfInterval's isAfter(Interval).
6728 @safe unittest
6729 {
6730     import std.datetime.date;
6731 
6732     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6733 
6734     static void testInterval(scope const NegInfInterval!Date negInfInterval, scope const Interval!Date interval)
6735     {
6736         negInfInterval.isAfter(interval);
6737     }
6738 
6739     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
6740 
6741     assert(!negInfInterval.isAfter(negInfInterval));
6742     assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
6743     assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
6744     assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
6745     assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
6746     assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
6747     assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
6748     assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
6749     assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
6750     assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
6751     assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
6752     assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
6753     assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
6754 
6755     assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 3))));
6756     assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 4))));
6757     assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 5))));
6758     assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 6))));
6759     assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 7))));
6760     assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 8))));
6761 
6762     assert(!NegInfInterval!Date(Date(2010, 7, 3)).isAfter(negInfInterval));
6763     assert(!NegInfInterval!Date(Date(2010, 7, 4)).isAfter(negInfInterval));
6764     assert(!NegInfInterval!Date(Date(2010, 7, 5)).isAfter(negInfInterval));
6765     assert(!NegInfInterval!Date(Date(2012, 1, 6)).isAfter(negInfInterval));
6766     assert(!NegInfInterval!Date(Date(2012, 1, 7)).isAfter(negInfInterval));
6767     assert(!NegInfInterval!Date(Date(2012, 1, 8)).isAfter(negInfInterval));
6768 
6769     assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 3))));
6770     assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 4))));
6771     assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 5))));
6772     assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 6))));
6773     assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 7))));
6774     assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 8))));
6775 
6776     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6777     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6778     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6779     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6780     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6781     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6782     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6783     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6784     assert(!negInfInterval.isAfter(interval));
6785     assert(!negInfInterval.isAfter(cInterval));
6786     assert(!negInfInterval.isAfter(iInterval));
6787     assert(!negInfInterval.isAfter(posInfInterval));
6788     assert(!negInfInterval.isAfter(cPosInfInterval));
6789     assert(!negInfInterval.isAfter(iPosInfInterval));
6790     assert(!negInfInterval.isAfter(negInfInterval));
6791     assert(!negInfInterval.isAfter(cNegInfInterval));
6792     assert(!negInfInterval.isAfter(iNegInfInterval));
6793     assert(!cNegInfInterval.isAfter(interval));
6794     assert(!cNegInfInterval.isAfter(cInterval));
6795     assert(!cNegInfInterval.isAfter(iInterval));
6796     assert(!cNegInfInterval.isAfter(posInfInterval));
6797     assert(!cNegInfInterval.isAfter(cPosInfInterval));
6798     assert(!cNegInfInterval.isAfter(iPosInfInterval));
6799     assert(!cNegInfInterval.isAfter(negInfInterval));
6800     assert(!cNegInfInterval.isAfter(cNegInfInterval));
6801     assert(!cNegInfInterval.isAfter(iNegInfInterval));
6802     assert(!iNegInfInterval.isAfter(interval));
6803     assert(!iNegInfInterval.isAfter(cInterval));
6804     assert(!iNegInfInterval.isAfter(iInterval));
6805     assert(!iNegInfInterval.isAfter(posInfInterval));
6806     assert(!iNegInfInterval.isAfter(cPosInfInterval));
6807     assert(!iNegInfInterval.isAfter(iPosInfInterval));
6808     assert(!iNegInfInterval.isAfter(negInfInterval));
6809     assert(!iNegInfInterval.isAfter(cNegInfInterval));
6810     assert(!iNegInfInterval.isAfter(iNegInfInterval));
6811 
6812     //Verify Examples.
6813     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(1994, 12, 24)));
6814     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2000, 1, 5)));
6815     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2012, 3, 1)));
6816 
6817     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
6818     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
6819     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
6820 
6821     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(1999, 5, 4))));
6822     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(2012, 3, 1))));
6823 
6824     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(1996, 5, 4))));
6825     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(2013, 7, 9))));
6826 }
6827 
6828 //Test NegInfInterval's intersects().
6829 @safe unittest
6830 {
6831     import std.datetime.date;
6832 
6833     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6834 
6835     static void testInterval(scope const NegInfInterval!Date negInfInterval, scope const Interval!Date interval)
6836     {
6837         negInfInterval.intersects(interval);
6838     }
6839 
6840     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
6841 
6842     assert(negInfInterval.intersects(negInfInterval));
6843     assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
6844     assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
6845     assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
6846     assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
6847     assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
6848     assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
6849     assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
6850     assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
6851     assert(negInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
6852     assert(negInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
6853     assert(!negInfInterval.intersects(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
6854     assert(!negInfInterval.intersects(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
6855 
6856     assert(negInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 3))));
6857     assert(negInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 4))));
6858     assert(negInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 5))));
6859     assert(negInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 6))));
6860     assert(negInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 7))));
6861     assert(negInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 8))));
6862 
6863     assert(NegInfInterval!Date(Date(2010, 7, 3)).intersects(negInfInterval));
6864     assert(NegInfInterval!Date(Date(2010, 7, 4)).intersects(negInfInterval));
6865     assert(NegInfInterval!Date(Date(2010, 7, 5)).intersects(negInfInterval));
6866     assert(NegInfInterval!Date(Date(2012, 1, 6)).intersects(negInfInterval));
6867     assert(NegInfInterval!Date(Date(2012, 1, 7)).intersects(negInfInterval));
6868     assert(NegInfInterval!Date(Date(2012, 1, 8)).intersects(negInfInterval));
6869 
6870     assert(negInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 3))));
6871     assert(negInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 4))));
6872     assert(negInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 5))));
6873     assert(negInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 6))));
6874     assert(!negInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 7))));
6875     assert(!negInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 8))));
6876 
6877     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6878     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6879     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6880     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6881     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6882     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6883     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6884     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6885     assert(negInfInterval.intersects(interval));
6886     assert(negInfInterval.intersects(cInterval));
6887     assert(negInfInterval.intersects(iInterval));
6888     assert(negInfInterval.intersects(posInfInterval));
6889     assert(negInfInterval.intersects(cPosInfInterval));
6890     assert(negInfInterval.intersects(iPosInfInterval));
6891     assert(negInfInterval.intersects(negInfInterval));
6892     assert(negInfInterval.intersects(cNegInfInterval));
6893     assert(negInfInterval.intersects(iNegInfInterval));
6894     assert(cNegInfInterval.intersects(interval));
6895     assert(cNegInfInterval.intersects(cInterval));
6896     assert(cNegInfInterval.intersects(iInterval));
6897     assert(cNegInfInterval.intersects(posInfInterval));
6898     assert(cNegInfInterval.intersects(cPosInfInterval));
6899     assert(cNegInfInterval.intersects(iPosInfInterval));
6900     assert(cNegInfInterval.intersects(negInfInterval));
6901     assert(cNegInfInterval.intersects(cNegInfInterval));
6902     assert(cNegInfInterval.intersects(iNegInfInterval));
6903     assert(iNegInfInterval.intersects(interval));
6904     assert(iNegInfInterval.intersects(cInterval));
6905     assert(iNegInfInterval.intersects(iInterval));
6906     assert(iNegInfInterval.intersects(posInfInterval));
6907     assert(iNegInfInterval.intersects(cPosInfInterval));
6908     assert(iNegInfInterval.intersects(iPosInfInterval));
6909     assert(iNegInfInterval.intersects(negInfInterval));
6910     assert(iNegInfInterval.intersects(cNegInfInterval));
6911     assert(iNegInfInterval.intersects(iNegInfInterval));
6912 
6913     //Verify Examples.
6914     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
6915     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
6916     assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
6917 
6918     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(1999, 5, 4))));
6919     assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(2012, 3, 1))));
6920 
6921     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(1996, 5, 4))));
6922     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(2013, 7, 9))));
6923 }
6924 
6925 //Test NegInfInterval's intersection().
6926 @safe unittest
6927 {
6928     import std.datetime.date;
6929 
6930     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6931 
6932     static void testInterval(I, J)(scope const I interval1, scope const J interval2)
6933     {
6934         interval1.intersection(interval2);
6935     }
6936 
6937     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
6938 
6939     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
6940     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
6941 
6942     assertThrown!DateTimeException(testInterval(negInfInterval, PosInfInterval!Date(Date(2012, 1, 7))));
6943     assertThrown!DateTimeException(testInterval(negInfInterval, PosInfInterval!Date(Date(2012, 1, 8))));
6944 
6945     assert(negInfInterval.intersection(negInfInterval) == negInfInterval);
6946     assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) ==
6947            Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)));
6948     assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
6949            Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7)));
6950     assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
6951            Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)));
6952     assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
6953            Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)));
6954     assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
6955            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
6956     assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
6957            Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
6958     assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
6959            Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
6960     assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
6961            Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
6962     assert(negInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
6963            Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
6964     assert(negInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
6965            Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
6966 
6967     assert(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 3))) == NegInfInterval!Date(Date(2010, 7, 3)));
6968     assert(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 4))) == NegInfInterval!Date(Date(2010, 7, 4)));
6969     assert(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 5))) == NegInfInterval!Date(Date(2010, 7, 5)));
6970     assert(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 6)));
6971     assert(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7)));
6972     assert(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 7)));
6973 
6974     assert(NegInfInterval!Date(Date(2010, 7, 3)).intersection(negInfInterval) == NegInfInterval!Date(Date(2010, 7, 3)));
6975     assert(NegInfInterval!Date(Date(2010, 7, 4)).intersection(negInfInterval) == NegInfInterval!Date(Date(2010, 7, 4)));
6976     assert(NegInfInterval!Date(Date(2010, 7, 5)).intersection(negInfInterval) == NegInfInterval!Date(Date(2010, 7, 5)));
6977     assert(NegInfInterval!Date(Date(2012, 1, 6)).intersection(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 6)));
6978     assert(NegInfInterval!Date(Date(2012, 1, 7)).intersection(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
6979     assert(NegInfInterval!Date(Date(2012, 1, 8)).intersection(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
6980 
6981     assert(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 3))) ==
6982            Interval!Date(Date(2010, 7, 3), Date(2012, 1 ,7)));
6983     assert(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 4))) ==
6984            Interval!Date(Date(2010, 7, 4), Date(2012, 1 ,7)));
6985     assert(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 5))) ==
6986            Interval!Date(Date(2010, 7, 5), Date(2012, 1 ,7)));
6987     assert(negInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 6))) ==
6988            Interval!Date(Date(2012, 1, 6), Date(2012, 1 ,7)));
6989 
6990     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6991     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6992     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
6993     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6994     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6995     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
6996     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6997     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
6998     assert(!negInfInterval.intersection(interval).empty);
6999     assert(!negInfInterval.intersection(cInterval).empty);
7000     assert(!negInfInterval.intersection(iInterval).empty);
7001     assert(!negInfInterval.intersection(posInfInterval).empty);
7002     assert(!negInfInterval.intersection(cPosInfInterval).empty);
7003     assert(!negInfInterval.intersection(iPosInfInterval).empty);
7004     assert(!negInfInterval.intersection(negInfInterval).empty);
7005     assert(!negInfInterval.intersection(cNegInfInterval).empty);
7006     assert(!negInfInterval.intersection(iNegInfInterval).empty);
7007     assert(!cNegInfInterval.intersection(interval).empty);
7008     assert(!cNegInfInterval.intersection(cInterval).empty);
7009     assert(!cNegInfInterval.intersection(iInterval).empty);
7010     assert(!cNegInfInterval.intersection(posInfInterval).empty);
7011     assert(!cNegInfInterval.intersection(cPosInfInterval).empty);
7012     assert(!cNegInfInterval.intersection(iPosInfInterval).empty);
7013     assert(!cNegInfInterval.intersection(negInfInterval).empty);
7014     assert(!cNegInfInterval.intersection(cNegInfInterval).empty);
7015     assert(!cNegInfInterval.intersection(iNegInfInterval).empty);
7016     assert(!iNegInfInterval.intersection(interval).empty);
7017     assert(!iNegInfInterval.intersection(cInterval).empty);
7018     assert(!iNegInfInterval.intersection(iInterval).empty);
7019     assert(!iNegInfInterval.intersection(posInfInterval).empty);
7020     assert(!iNegInfInterval.intersection(cPosInfInterval).empty);
7021     assert(!iNegInfInterval.intersection(iPosInfInterval).empty);
7022     assert(!iNegInfInterval.intersection(negInfInterval).empty);
7023     assert(!iNegInfInterval.intersection(cNegInfInterval).empty);
7024     assert(!iNegInfInterval.intersection(iNegInfInterval).empty);
7025 
7026     //Verify Examples.
7027     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
7028            Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2)));
7029     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) ==
7030            Interval!Date(Date(1999, 1, 12), Date(2012, 3, 1)));
7031 
7032     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) ==
7033            Interval!Date(Date(1990, 7, 6), Date(2012, 3, 1)));
7034     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) ==
7035            Interval!Date(Date(1999, 1, 12), Date(2012, 3, 1)));
7036 
7037     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) ==
7038            NegInfInterval!Date(Date(1999, 7, 6)));
7039     assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) ==
7040            NegInfInterval!Date(Date(2012, 3, 1)));
7041 }
7042 
7043 //Test NegInfInterval's isAdjacent().
7044 @safe unittest
7045 {
7046     import std.datetime.date;
7047 
7048     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7049 
7050     static void testInterval(scope const NegInfInterval!Date negInfInterval, scope const Interval!Date interval)
7051     {
7052         negInfInterval.isAdjacent(interval);
7053     }
7054 
7055     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
7056 
7057     assert(!negInfInterval.isAdjacent(negInfInterval));
7058     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
7059     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
7060     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
7061     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
7062     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
7063     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
7064     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
7065     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
7066     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
7067     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
7068     assert(negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
7069     assert(!negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
7070 
7071     assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 3))));
7072     assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 4))));
7073     assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 5))));
7074     assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 6))));
7075     assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 7))));
7076     assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 8))));
7077 
7078     assert(!NegInfInterval!Date(Date(2010, 7, 3)).isAdjacent(negInfInterval));
7079     assert(!NegInfInterval!Date(Date(2010, 7, 4)).isAdjacent(negInfInterval));
7080     assert(!NegInfInterval!Date(Date(2010, 7, 5)).isAdjacent(negInfInterval));
7081     assert(!NegInfInterval!Date(Date(2012, 1, 6)).isAdjacent(negInfInterval));
7082     assert(!NegInfInterval!Date(Date(2012, 1, 7)).isAdjacent(negInfInterval));
7083     assert(!NegInfInterval!Date(Date(2012, 1, 8)).isAdjacent(negInfInterval));
7084 
7085     assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 3))));
7086     assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 4))));
7087     assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 5))));
7088     assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 6))));
7089     assert(negInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 7))));
7090     assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 8))));
7091 
7092     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
7093     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
7094     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
7095     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
7096     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
7097     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
7098     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7099     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7100     assert(!negInfInterval.isAdjacent(interval));
7101     assert(!negInfInterval.isAdjacent(cInterval));
7102     assert(!negInfInterval.isAdjacent(iInterval));
7103     assert(!negInfInterval.isAdjacent(posInfInterval));
7104     assert(!negInfInterval.isAdjacent(cPosInfInterval));
7105     assert(!negInfInterval.isAdjacent(iPosInfInterval));
7106     assert(!negInfInterval.isAdjacent(negInfInterval));
7107     assert(!negInfInterval.isAdjacent(cNegInfInterval));
7108     assert(!negInfInterval.isAdjacent(iNegInfInterval));
7109     assert(!cNegInfInterval.isAdjacent(interval));
7110     assert(!cNegInfInterval.isAdjacent(cInterval));
7111     assert(!cNegInfInterval.isAdjacent(iInterval));
7112     assert(!cNegInfInterval.isAdjacent(posInfInterval));
7113     assert(!cNegInfInterval.isAdjacent(cPosInfInterval));
7114     assert(!cNegInfInterval.isAdjacent(iPosInfInterval));
7115     assert(!cNegInfInterval.isAdjacent(negInfInterval));
7116     assert(!cNegInfInterval.isAdjacent(cNegInfInterval));
7117     assert(!cNegInfInterval.isAdjacent(iNegInfInterval));
7118     assert(!iNegInfInterval.isAdjacent(interval));
7119     assert(!iNegInfInterval.isAdjacent(cInterval));
7120     assert(!iNegInfInterval.isAdjacent(iInterval));
7121     assert(!iNegInfInterval.isAdjacent(posInfInterval));
7122     assert(!iNegInfInterval.isAdjacent(cPosInfInterval));
7123     assert(!iNegInfInterval.isAdjacent(iPosInfInterval));
7124     assert(!iNegInfInterval.isAdjacent(negInfInterval));
7125     assert(!iNegInfInterval.isAdjacent(cNegInfInterval));
7126     assert(!iNegInfInterval.isAdjacent(iNegInfInterval));
7127 
7128     //Verify Examples.
7129     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
7130     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1999, 1, 12), Date(2012, 3, 1))));
7131     assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2012, 3, 1), Date(2019, 2, 2))));
7132     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
7133 
7134     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(1999, 5, 4))));
7135     assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(2012, 3, 1))));
7136 
7137     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(1996, 5, 4))));
7138     assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(2012, 3, 1))));
7139 }
7140 
7141 //Test NegInfInterval's merge().
7142 @safe unittest
7143 {
7144     import std.datetime.date;
7145 
7146     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7147 
7148     static void testInterval(I, J)(scope const I interval1, scope const J interval2)
7149     {
7150         interval1.merge(interval2);
7151     }
7152 
7153     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
7154 
7155     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
7156 
7157     assert(negInfInterval.merge(negInfInterval) == negInfInterval);
7158     assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) ==
7159            NegInfInterval!Date(Date(2012, 1, 7)));
7160     assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
7161            NegInfInterval!Date(Date(2013, 7, 3)));
7162     assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
7163            NegInfInterval!Date(Date(2012, 1, 7)));
7164     assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
7165            NegInfInterval!Date(Date(2012, 1, 7)));
7166     assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
7167            NegInfInterval!Date(Date(2012, 1, 7)));
7168     assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
7169            NegInfInterval!Date(Date(2012, 1, 8)));
7170     assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
7171            NegInfInterval!Date(Date(2012, 1, 7)));
7172     assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
7173            NegInfInterval!Date(Date(2012, 1, 7)));
7174     assert(negInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
7175            NegInfInterval!Date(Date(2012, 1, 7)));
7176     assert(negInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
7177            NegInfInterval!Date(Date(2012, 1, 8)));
7178     assert(negInfInterval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
7179            NegInfInterval!Date(Date(2012, 1, 8)));
7180 
7181     assert(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 3))) == NegInfInterval!Date(Date(2012, 1, 7)));
7182     assert(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 4))) == NegInfInterval!Date(Date(2012, 1, 7)));
7183     assert(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 5))) == NegInfInterval!Date(Date(2012, 1, 7)));
7184     assert(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 7)));
7185     assert(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7)));
7186     assert(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8)));
7187 
7188     assert(NegInfInterval!Date(Date(2010, 7, 3)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
7189     assert(NegInfInterval!Date(Date(2010, 7, 4)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
7190     assert(NegInfInterval!Date(Date(2010, 7, 5)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
7191     assert(NegInfInterval!Date(Date(2012, 1, 6)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
7192     assert(NegInfInterval!Date(Date(2012, 1, 7)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
7193     assert(NegInfInterval!Date(Date(2012, 1, 8)).merge(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 8)));
7194 
7195     static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 3)))));
7196     static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 4)))));
7197     static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 5)))));
7198     static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 6)))));
7199     static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 7)))));
7200     static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 8)))));
7201 
7202     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
7203     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
7204     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
7205     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
7206     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
7207     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
7208     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7209     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7210     assert(!negInfInterval.merge(interval).empty);
7211     assert(!negInfInterval.merge(cInterval).empty);
7212     assert(!negInfInterval.merge(iInterval).empty);
7213     static assert(!__traits(compiles, negInfInterval.merge(posInfInterval)));
7214     static assert(!__traits(compiles, negInfInterval.merge(cPosInfInterval)));
7215     static assert(!__traits(compiles, negInfInterval.merge(iPosInfInterval)));
7216     assert(!negInfInterval.merge(negInfInterval).empty);
7217     assert(!negInfInterval.merge(cNegInfInterval).empty);
7218     assert(!negInfInterval.merge(iNegInfInterval).empty);
7219     assert(!cNegInfInterval.merge(interval).empty);
7220     assert(!cNegInfInterval.merge(cInterval).empty);
7221     assert(!cNegInfInterval.merge(iInterval).empty);
7222     static assert(!__traits(compiles, cNegInfInterval.merge(posInfInterval)));
7223     static assert(!__traits(compiles, cNegInfInterval.merge(cPosInfInterval)));
7224     static assert(!__traits(compiles, cNegInfInterval.merge(iPosInfInterval)));
7225     assert(!cNegInfInterval.merge(negInfInterval).empty);
7226     assert(!cNegInfInterval.merge(cNegInfInterval).empty);
7227     assert(!cNegInfInterval.merge(iNegInfInterval).empty);
7228     assert(!iNegInfInterval.merge(interval).empty);
7229     assert(!iNegInfInterval.merge(cInterval).empty);
7230     assert(!iNegInfInterval.merge(iInterval).empty);
7231     static assert(!__traits(compiles, iNegInfInterval.merge(posInfInterval)));
7232     static assert(!__traits(compiles, iNegInfInterval.merge(cPosInfInterval)));
7233     static assert(!__traits(compiles, iNegInfInterval.merge(iPosInfInterval)));
7234     assert(!iNegInfInterval.merge(negInfInterval).empty);
7235     assert(!iNegInfInterval.merge(cNegInfInterval).empty);
7236     assert(!iNegInfInterval.merge(iNegInfInterval).empty);
7237 
7238     //Verify Examples.
7239     assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
7240            NegInfInterval!Date(Date(2012, 3, 1)));
7241     assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) ==
7242            NegInfInterval!Date(Date(2015, 9, 2)));
7243 
7244     assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(1999, 7, 6))) ==
7245            NegInfInterval!Date(Date(2012, 3, 1)));
7246     assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(2013, 1, 12))) ==
7247            NegInfInterval!Date(Date(2013, 1, 12)));
7248 }
7249 
7250 //Test NegInfInterval's span().
7251 @safe unittest
7252 {
7253     import std.datetime.date;
7254 
7255     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7256 
7257     static void testInterval(I, J)(scope const I interval1, scope const J interval2)
7258     {
7259         interval1.span(interval2);
7260     }
7261 
7262     assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
7263 
7264     assert(negInfInterval.span(negInfInterval) == negInfInterval);
7265     assert(negInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) ==
7266            NegInfInterval!Date(Date(2012, 1, 7)));
7267     assert(negInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
7268            NegInfInterval!Date(Date(2013, 7, 3)));
7269     assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
7270            NegInfInterval!Date(Date(2012, 1, 7)));
7271     assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
7272            NegInfInterval!Date(Date(2012, 1, 7)));
7273     assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
7274            NegInfInterval!Date(Date(2012, 1, 7)));
7275     assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
7276            NegInfInterval!Date(Date(2012, 1, 8)));
7277     assert(negInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
7278            NegInfInterval!Date(Date(2012, 1, 7)));
7279     assert(negInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
7280            NegInfInterval!Date(Date(2012, 1, 7)));
7281     assert(negInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
7282            NegInfInterval!Date(Date(2012, 1, 7)));
7283     assert(negInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
7284            NegInfInterval!Date(Date(2012, 1, 8)));
7285     assert(negInfInterval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
7286            NegInfInterval!Date(Date(2012, 1, 8)));
7287     assert(negInfInterval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) ==
7288            NegInfInterval!Date(Date(2012, 1, 9)));
7289 
7290     assert(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 3))) == NegInfInterval!Date(Date(2012, 1, 7)));
7291     assert(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 4))) == NegInfInterval!Date(Date(2012, 1, 7)));
7292     assert(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 5))) == NegInfInterval!Date(Date(2012, 1, 7)));
7293     assert(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 6))) == NegInfInterval!Date(Date(2012, 1, 7)));
7294     assert(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 7))) == NegInfInterval!Date(Date(2012, 1, 7)));
7295     assert(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 8))) == NegInfInterval!Date(Date(2012, 1, 8)));
7296 
7297     assert(NegInfInterval!Date(Date(2010, 7, 3)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
7298     assert(NegInfInterval!Date(Date(2010, 7, 4)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
7299     assert(NegInfInterval!Date(Date(2010, 7, 5)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
7300     assert(NegInfInterval!Date(Date(2012, 1, 6)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
7301     assert(NegInfInterval!Date(Date(2012, 1, 7)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 7)));
7302     assert(NegInfInterval!Date(Date(2012, 1, 8)).span(negInfInterval) == NegInfInterval!Date(Date(2012, 1, 8)));
7303 
7304     static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2010, 7, 3)))));
7305     static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2010, 7, 4)))));
7306     static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2010, 7, 5)))));
7307     static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2012, 1, 6)))));
7308     static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2012, 1, 7)))));
7309     static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2012, 1, 8)))));
7310 
7311     auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
7312     const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
7313     immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
7314     auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
7315     const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
7316     immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
7317     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7318     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7319     assert(!negInfInterval.span(interval).empty);
7320     assert(!negInfInterval.span(cInterval).empty);
7321     assert(!negInfInterval.span(iInterval).empty);
7322     static assert(!__traits(compiles, negInfInterval.span(posInfInterval)));
7323     static assert(!__traits(compiles, negInfInterval.span(cPosInfInterval)));
7324     static assert(!__traits(compiles, negInfInterval.span(iPosInfInterval)));
7325     assert(!negInfInterval.span(negInfInterval).empty);
7326     assert(!negInfInterval.span(cNegInfInterval).empty);
7327     assert(!negInfInterval.span(iNegInfInterval).empty);
7328     assert(!cNegInfInterval.span(interval).empty);
7329     assert(!cNegInfInterval.span(cInterval).empty);
7330     assert(!cNegInfInterval.span(iInterval).empty);
7331     static assert(!__traits(compiles, cNegInfInterval.span(posInfInterval)));
7332     static assert(!__traits(compiles, cNegInfInterval.span(cPosInfInterval)));
7333     static assert(!__traits(compiles, cNegInfInterval.span(iPosInfInterval)));
7334     assert(!cNegInfInterval.span(negInfInterval).empty);
7335     assert(!cNegInfInterval.span(cNegInfInterval).empty);
7336     assert(!cNegInfInterval.span(iNegInfInterval).empty);
7337     assert(!iNegInfInterval.span(interval).empty);
7338     assert(!iNegInfInterval.span(cInterval).empty);
7339     assert(!iNegInfInterval.span(iInterval).empty);
7340     static assert(!__traits(compiles, iNegInfInterval.span(posInfInterval)));
7341     static assert(!__traits(compiles, iNegInfInterval.span(cPosInfInterval)));
7342     static assert(!__traits(compiles, iNegInfInterval.span(iPosInfInterval)));
7343     assert(!iNegInfInterval.span(negInfInterval).empty);
7344     assert(!iNegInfInterval.span(cNegInfInterval).empty);
7345     assert(!iNegInfInterval.span(iNegInfInterval).empty);
7346 
7347     //Verify Examples.
7348     assert(NegInfInterval!Date(Date(2012, 3, 1)).span(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) ==
7349            NegInfInterval!Date(Date(2012, 3, 1)));
7350     assert(NegInfInterval!Date(Date(2012, 3, 1)).span(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) ==
7351            NegInfInterval!Date(Date(2015, 9, 2)));
7352     assert(NegInfInterval!Date(Date(1600, 1, 7)).span(Interval!Date(Date(2012, 3, 11), Date(2017, 7, 1))) ==
7353            NegInfInterval!Date(Date(2017, 7, 1)));
7354 
7355     assert(NegInfInterval!Date(Date(2012, 3, 1)).span(NegInfInterval!Date(Date(1999, 7, 6))) ==
7356            NegInfInterval!Date(Date(2012, 3, 1)));
7357     assert(NegInfInterval!Date(Date(2012, 3, 1)).span(NegInfInterval!Date(Date(2013, 1, 12))) ==
7358            NegInfInterval!Date(Date(2013, 1, 12)));
7359 }
7360 
7361 //Test NegInfInterval's shift().
7362 @safe unittest
7363 {
7364     import std.datetime.date;
7365 
7366     auto interval = NegInfInterval!Date(Date(2012, 1, 7));
7367 
7368     static void testInterval(I)(I interval, scope const Duration duration,
7369                                 scope const I expected, size_t line = __LINE__)
7370     {
7371         interval.shift(duration);
7372         assert(interval == expected);
7373     }
7374 
7375     testInterval(interval, dur!"days"(22), NegInfInterval!Date(Date(2012, 1, 29)));
7376     testInterval(interval, dur!"days"(-22), NegInfInterval!Date(Date(2011, 12, 16)));
7377 
7378     const cInterval = NegInfInterval!Date(Date(2012, 1, 7));
7379     immutable iInterval = NegInfInterval!Date(Date(2012, 1, 7));
7380     static assert(!__traits(compiles, cInterval.shift(dur!"days"(5))));
7381     static assert(!__traits(compiles, iInterval.shift(dur!"days"(5))));
7382 
7383     //Verify Examples.
7384     auto interval1 = NegInfInterval!Date(Date(2012, 4, 5));
7385     auto interval2 = NegInfInterval!Date(Date(2012, 4, 5));
7386 
7387     interval1.shift(dur!"days"(50));
7388     assert(interval1 == NegInfInterval!Date(Date(2012, 5, 25)));
7389 
7390     interval2.shift(dur!"days"(-50));
7391     assert(interval2 == NegInfInterval!Date( Date(2012, 2, 15)));
7392 }
7393 
7394 //Test NegInfInterval's shift(int, int, AllowDayOverflow).
7395 @safe unittest
7396 {
7397     import std.datetime.date;
7398 
7399     {
7400         auto interval = NegInfInterval!Date(Date(2012, 1, 7));
7401 
7402         static void testIntervalFail(I)(I interval, int years, int months)
7403         {
7404             interval.shift(years, months);
7405         }
7406 
7407         static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow,
7408                                     in I expected, size_t line = __LINE__)
7409         {
7410             interval.shift(years, months, allow);
7411             assert(interval == expected);
7412         }
7413 
7414         testInterval(interval, 5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2017, 1, 7)));
7415         testInterval(interval, -5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2007, 1, 7)));
7416 
7417         auto interval2 = NegInfInterval!Date(Date(2010, 5, 31));
7418 
7419         testInterval(interval2, 1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 7, 1)));
7420         testInterval(interval2, 1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 5, 1)));
7421         testInterval(interval2, -1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 5, 1)));
7422         testInterval(interval2, -1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 7, 1)));
7423 
7424         testInterval(interval2, 1, 1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 6, 30)));
7425         testInterval(interval2, 1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 4, 30)));
7426         testInterval(interval2, -1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2009, 4, 30)));
7427         testInterval(interval2, -1, 1, AllowDayOverflow.no, NegInfInterval!Date(Date(2009, 6, 30)));
7428     }
7429 
7430     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7431     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7432     static assert(!__traits(compiles, cNegInfInterval.shift(1)));
7433     static assert(!__traits(compiles, iNegInfInterval.shift(1)));
7434 
7435     //Verify Examples.
7436     auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
7437     auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
7438 
7439     interval1.shift(2);
7440     assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1)));
7441 
7442     interval2.shift(-2);
7443     assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1)));
7444 }
7445 
7446 //Test NegInfInterval's expand().
7447 @safe unittest
7448 {
7449     import std.datetime.date;
7450 
7451     auto interval = NegInfInterval!Date(Date(2012, 1, 7));
7452 
7453     static void testInterval(I)(I interval,
7454                                 scope const Duration duration, scope const I expected, size_t line = __LINE__)
7455     {
7456         interval.expand(duration);
7457         assert(interval == expected);
7458     }
7459 
7460     testInterval(interval, dur!"days"(22), NegInfInterval!Date(Date(2012, 1, 29)));
7461     testInterval(interval, dur!"days"(-22), NegInfInterval!Date(Date(2011, 12, 16)));
7462 
7463     const cInterval = NegInfInterval!Date(Date(2012, 1, 7));
7464     immutable iInterval = NegInfInterval!Date(Date(2012, 1, 7));
7465     static assert(!__traits(compiles, cInterval.expand(dur!"days"(5))));
7466     static assert(!__traits(compiles, iInterval.expand(dur!"days"(5))));
7467 
7468     //Verify Examples.
7469     auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
7470     auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
7471 
7472     interval1.expand(dur!"days"(2));
7473     assert(interval1 == NegInfInterval!Date(Date(2012, 3, 3)));
7474 
7475     interval2.expand(dur!"days"(-2));
7476     assert(interval2 == NegInfInterval!Date(Date(2012, 2, 28)));
7477 }
7478 
7479 //Test NegInfInterval's expand(int, int, AllowDayOverflow).
7480 @safe unittest
7481 {
7482     import std.datetime.date;
7483 
7484     {
7485         auto interval = NegInfInterval!Date(Date(2012, 1, 7));
7486 
7487         static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow,
7488                                     in I expected, size_t line = __LINE__)
7489         {
7490             interval.expand(years, months, allow);
7491             assert(interval == expected);
7492         }
7493 
7494         testInterval(interval, 5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2017, 1, 7)));
7495         testInterval(interval, -5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2007, 1, 7)));
7496 
7497         auto interval2 = NegInfInterval!Date(Date(2010, 5, 31));
7498 
7499         testInterval(interval2, 1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 7, 1)));
7500         testInterval(interval2, 1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 5, 1)));
7501         testInterval(interval2, -1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 5, 1)));
7502         testInterval(interval2, -1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 7, 1)));
7503 
7504         testInterval(interval2, 1, 1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 6, 30)));
7505         testInterval(interval2, 1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 4, 30)));
7506         testInterval(interval2, -1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2009, 4, 30)));
7507         testInterval(interval2, -1, 1, AllowDayOverflow.no, NegInfInterval!Date( Date(2009, 6, 30)));
7508     }
7509 
7510     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7511     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7512     static assert(!__traits(compiles, cNegInfInterval.expand(1)));
7513     static assert(!__traits(compiles, iNegInfInterval.expand(1)));
7514 
7515     //Verify Examples.
7516     auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
7517     auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
7518 
7519     interval1.expand(2);
7520     assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1)));
7521 
7522     interval2.expand(-2);
7523     assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1)));
7524 }
7525 
7526 //Test NegInfInterval's bwdRange().
7527 @system unittest
7528 {
7529     import std.datetime.date;
7530 
7531     auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7532 
7533     static void testInterval(NegInfInterval!Date negInfInterval)
7534     {
7535         negInfInterval.bwdRange(everyDayOfWeek!(Date, Direction.fwd)(DayOfWeek.fri)).popFront();
7536     }
7537 
7538     assertThrown!DateTimeException(testInterval(negInfInterval));
7539 
7540     assert(NegInfInterval!Date(Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).front ==
7541            Date(2010, 10, 1));
7542 
7543     assert(NegInfInterval!Date(Date(2010, 10, 1)).bwdRange(
7544                everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri), PopFirst.yes).front == Date(2010, 9, 24));
7545 
7546     //Verify Examples.
7547     auto interval = NegInfInterval!Date(Date(2010, 9, 9));
7548     auto func = delegate (scope const Date date)
7549                 {
7550                     if ((date.day & 1) == 0)
7551                         return date - dur!"days"(2);
7552                     return date - dur!"days"(1);
7553                 };
7554     auto range = interval.bwdRange(func);
7555 
7556     //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8).
7557     assert(range.front == Date(2010, 9, 9));
7558 
7559     range.popFront();
7560     assert(range.front == Date(2010, 9, 8));
7561 
7562     range.popFront();
7563     assert(range.front == Date(2010, 9, 6));
7564 
7565     range.popFront();
7566     assert(range.front == Date(2010, 9, 4));
7567 
7568     range.popFront();
7569     assert(range.front == Date(2010, 9, 2));
7570 
7571     range.popFront();
7572     assert(!range.empty);
7573 
7574     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7575     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7576     assert(!cNegInfInterval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).empty);
7577     assert(!iNegInfInterval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).empty);
7578 }
7579 
7580 //Test NegInfInterval's toString().
7581 @safe unittest
7582 {
7583     import std.datetime.date;
7584 
7585     assert(NegInfInterval!Date(Date(2012, 1, 7)).toString() == "[-∞ - 2012-Jan-07)");
7586 
7587     const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7588     immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
7589     assert(cNegInfInterval.toString());
7590     assert(iNegInfInterval.toString());
7591 }
7592 
7593 
7594 /++
7595     Range-generating function.
7596 
7597     Returns a delegate which returns the next time point with the given
7598     `DayOfWeek` in a range.
7599 
7600     Using this delegate allows iteration over successive time points which
7601     are all the same day of the week. e.g. passing `DayOfWeek.mon` to
7602     `everyDayOfWeek` would result in a delegate which could be used to
7603     iterate over all of the Mondays in a range.
7604 
7605     Params:
7606         dir       = The direction to iterate in. If passing the return value to
7607                     `fwdRange`, use `Direction.fwd`. If passing it to
7608                     `bwdRange`, use `Direction.bwd`.
7609         dayOfWeek = The week that each time point in the range will be.
7610   +/
7611 TP delegate(scope const TP) everyDayOfWeek(TP, Direction dir = Direction.fwd)(DayOfWeek dayOfWeek) nothrow
7612 if (isTimePoint!TP &&
7613     (dir == Direction.fwd || dir == Direction.bwd) &&
7614     __traits(hasMember, TP, "dayOfWeek") &&
7615     !__traits(isStaticFunction, TP.dayOfWeek) &&
7616     is(typeof(TP.dayOfWeek) == DayOfWeek))
7617 {
7618     TP func(scope const TP tp)
7619     {
7620         TP retval = cast(TP) tp;
7621         immutable days = daysToDayOfWeek(retval.dayOfWeek, dayOfWeek);
7622 
7623         static if (dir == Direction.fwd)
7624             immutable adjustedDays = days == 0 ? 7 : days;
7625         else
7626             immutable adjustedDays = days == 0 ? -7 : days - 7;
7627 
7628         return retval += dur!"days"(adjustedDays);
7629     }
7630 
7631     return &func;
7632 }
7633 
7634 ///
7635 @system unittest
7636 {
7637     import std.datetime.date : Date, DayOfWeek;
7638 
7639     auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27));
7640     auto func = everyDayOfWeek!Date(DayOfWeek.mon);
7641     auto range = interval.fwdRange(func);
7642 
7643     // A Thursday. Using PopFirst.yes would have made this Date(2010, 9, 6).
7644     assert(range.front == Date(2010, 9, 2));
7645 
7646     range.popFront();
7647     assert(range.front == Date(2010, 9, 6));
7648 
7649     range.popFront();
7650     assert(range.front == Date(2010, 9, 13));
7651 
7652     range.popFront();
7653     assert(range.front == Date(2010, 9, 20));
7654 
7655     range.popFront();
7656     assert(range.empty);
7657 }
7658 
7659 @system unittest
7660 {
7661     import std.datetime.date;
7662     import std.datetime.systime;
7663 
7664     auto funcFwd = everyDayOfWeek!Date(DayOfWeek.mon);
7665     auto funcBwd = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.mon);
7666 
7667     assert(funcFwd(Date(2010, 8, 28)) == Date(2010, 8, 30));
7668     assert(funcFwd(Date(2010, 8, 29)) == Date(2010, 8, 30));
7669     assert(funcFwd(Date(2010, 8, 30)) == Date(2010, 9, 6));
7670     assert(funcFwd(Date(2010, 8, 31)) == Date(2010, 9, 6));
7671     assert(funcFwd(Date(2010, 9, 1)) == Date(2010, 9, 6));
7672     assert(funcFwd(Date(2010, 9, 2)) == Date(2010, 9, 6));
7673     assert(funcFwd(Date(2010, 9, 3)) == Date(2010, 9, 6));
7674     assert(funcFwd(Date(2010, 9, 4)) == Date(2010, 9, 6));
7675     assert(funcFwd(Date(2010, 9, 5)) == Date(2010, 9, 6));
7676     assert(funcFwd(Date(2010, 9, 6)) == Date(2010, 9, 13));
7677     assert(funcFwd(Date(2010, 9, 7)) == Date(2010, 9, 13));
7678 
7679     assert(funcBwd(Date(2010, 8, 28)) == Date(2010, 8, 23));
7680     assert(funcBwd(Date(2010, 8, 29)) == Date(2010, 8, 23));
7681     assert(funcBwd(Date(2010, 8, 30)) == Date(2010, 8, 23));
7682     assert(funcBwd(Date(2010, 8, 31)) == Date(2010, 8, 30));
7683     assert(funcBwd(Date(2010, 9, 1)) == Date(2010, 8, 30));
7684     assert(funcBwd(Date(2010, 9, 2)) == Date(2010, 8, 30));
7685     assert(funcBwd(Date(2010, 9, 3)) == Date(2010, 8, 30));
7686     assert(funcBwd(Date(2010, 9, 4)) == Date(2010, 8, 30));
7687     assert(funcBwd(Date(2010, 9, 5)) == Date(2010, 8, 30));
7688     assert(funcBwd(Date(2010, 9, 6)) == Date(2010, 8, 30));
7689     assert(funcBwd(Date(2010, 9, 7)) == Date(2010, 9, 6));
7690 
7691     static assert(!__traits(compiles, everyDayOfWeek!TimeOfDay(DayOfWeek.mon)));
7692     assert(everyDayOfWeek!DateTime(DayOfWeek.mon) !is null);
7693     assert(everyDayOfWeek!SysTime(DayOfWeek.mon) !is null);
7694 }
7695 
7696 
7697 /++
7698     Range-generating function.
7699 
7700     Returns a delegate which returns the next time point with the given month
7701     which would be reached by adding months to the given time point.
7702 
7703     So, using this delegate allows iteration over successive time points
7704     which are in the same month but different years. For example,
7705     iterate over each successive December 25th in an interval by starting with a
7706     date which had the 25th as its day and passed `Month.dec` to
7707     `everyMonth` to create the delegate.
7708 
7709     Since it wouldn't really make sense to be iterating over a specific month
7710     and end up with some of the time points in the succeeding month or two years
7711     after the previous time point, `AllowDayOverflow.no` is always used when
7712     calculating the next time point.
7713 
7714     Params:
7715         dir   = The direction to iterate in. If passing the return value to
7716                 `fwdRange`, use `Direction.fwd`. If passing it to
7717                 `bwdRange`, use `Direction.bwd`.
7718         month = The month that each time point in the range will be in
7719                 (January is 1).
7720   +/
7721 TP delegate(scope const TP) everyMonth(TP, Direction dir = Direction.fwd)(int month)
7722 if (isTimePoint!TP &&
7723     (dir == Direction.fwd || dir == Direction.bwd) &&
7724     __traits(hasMember, TP, "month") &&
7725     !__traits(isStaticFunction, TP.month) &&
7726     is(typeof(TP.month) == Month))
7727 {
7728     import std.datetime.date : enforceValid, monthsToMonth;
7729 
7730     enforceValid!"months"(month);
7731 
7732     TP func(scope const TP tp)
7733     {
7734         TP retval = cast(TP) tp;
7735         immutable months = monthsToMonth(retval.month, month);
7736 
7737         static if (dir == Direction.fwd)
7738             immutable adjustedMonths = months == 0 ? 12 : months;
7739         else
7740             immutable adjustedMonths = months == 0 ? -12 : months - 12;
7741 
7742         retval.add!"months"(adjustedMonths, AllowDayOverflow.no);
7743 
7744         if (retval.month != month)
7745         {
7746             retval.add!"months"(-1);
7747             assert(retval.month == month);
7748         }
7749 
7750         return retval;
7751     }
7752 
7753     return &func;
7754 }
7755 
7756 ///
7757 @system unittest
7758 {
7759     import std.datetime.date : Date, Month;
7760 
7761     auto interval = Interval!Date(Date(2000, 1, 30), Date(2004, 8, 5));
7762     auto func = everyMonth!Date(Month.feb);
7763     auto range = interval.fwdRange(func);
7764 
7765     // Using PopFirst.yes would have made this Date(2010, 2, 29).
7766     assert(range.front == Date(2000, 1, 30));
7767 
7768     range.popFront();
7769     assert(range.front == Date(2000, 2, 29));
7770 
7771     range.popFront();
7772     assert(range.front == Date(2001, 2, 28));
7773 
7774     range.popFront();
7775     assert(range.front == Date(2002, 2, 28));
7776 
7777     range.popFront();
7778     assert(range.front == Date(2003, 2, 28));
7779 
7780     range.popFront();
7781     assert(range.front == Date(2004, 2, 28));
7782 
7783     range.popFront();
7784     assert(range.empty);
7785 }
7786 
7787 @system unittest
7788 {
7789     import std.datetime.date;
7790     import std.datetime.systime;
7791 
7792     auto funcFwd = everyMonth!Date(Month.jun);
7793     auto funcBwd = everyMonth!(Date, Direction.bwd)(Month.jun);
7794 
7795     assert(funcFwd(Date(2010, 5, 31)) == Date(2010, 6, 30));
7796     assert(funcFwd(Date(2010, 6, 30)) == Date(2011, 6, 30));
7797     assert(funcFwd(Date(2010, 7, 31)) == Date(2011, 6, 30));
7798     assert(funcFwd(Date(2010, 8, 31)) == Date(2011, 6, 30));
7799     assert(funcFwd(Date(2010, 9, 30)) == Date(2011, 6, 30));
7800     assert(funcFwd(Date(2010, 10, 31)) == Date(2011, 6, 30));
7801     assert(funcFwd(Date(2010, 11, 30)) == Date(2011, 6, 30));
7802     assert(funcFwd(Date(2010, 12, 31)) == Date(2011, 6, 30));
7803     assert(funcFwd(Date(2011, 1, 31)) == Date(2011, 6, 30));
7804     assert(funcFwd(Date(2011, 2, 28)) == Date(2011, 6, 28));
7805     assert(funcFwd(Date(2011, 3, 31)) == Date(2011, 6, 30));
7806     assert(funcFwd(Date(2011, 4, 30)) == Date(2011, 6, 30));
7807     assert(funcFwd(Date(2011, 5, 31)) == Date(2011, 6, 30));
7808     assert(funcFwd(Date(2011, 6, 30)) == Date(2012, 6, 30));
7809     assert(funcFwd(Date(2011, 7, 31)) == Date(2012, 6, 30));
7810 
7811     assert(funcBwd(Date(2010, 5, 31)) == Date(2009, 6, 30));
7812     assert(funcBwd(Date(2010, 6, 30)) == Date(2009, 6, 30));
7813     assert(funcBwd(Date(2010, 7, 31)) == Date(2010, 6, 30));
7814     assert(funcBwd(Date(2010, 8, 31)) == Date(2010, 6, 30));
7815     assert(funcBwd(Date(2010, 9, 30)) == Date(2010, 6, 30));
7816     assert(funcBwd(Date(2010, 10, 31)) == Date(2010, 6, 30));
7817     assert(funcBwd(Date(2010, 11, 30)) == Date(2010, 6, 30));
7818     assert(funcBwd(Date(2010, 12, 31)) == Date(2010, 6, 30));
7819     assert(funcBwd(Date(2011, 1, 31)) == Date(2010, 6, 30));
7820     assert(funcBwd(Date(2011, 2, 28)) == Date(2010, 6, 28));
7821     assert(funcBwd(Date(2011, 3, 31)) == Date(2010, 6, 30));
7822     assert(funcBwd(Date(2011, 4, 30)) == Date(2010, 6, 30));
7823     assert(funcBwd(Date(2011, 5, 31)) == Date(2010, 6, 30));
7824     assert(funcBwd(Date(2011, 6, 30)) == Date(2010, 6, 30));
7825     assert(funcBwd(Date(2011, 7, 30)) == Date(2011, 6, 30));
7826 
7827     static assert(!__traits(compiles, everyMonth!TimeOfDay(Month.jan)));
7828     assert(everyMonth!DateTime(Month.jan) !is null);
7829     assert(everyMonth!SysTime(Month.jan) !is null);
7830 }
7831 
7832 
7833 /++
7834     Range-generating function.
7835 
7836     Returns a delegate which returns the next time point which is the given
7837     duration later.
7838 
7839     Using this delegate allows iteration over successive time points which
7840     are apart by the given duration e.g. passing `dur!"days"(3)` to
7841     `everyDuration` would result in a delegate which could be used to iterate
7842     over a range of days which are each 3 days apart.
7843 
7844     Params:
7845         dir      = The direction to iterate in. If passing the return value to
7846                    `fwdRange`, use `Direction.fwd`. If passing it to
7847                    `bwdRange`, use `Direction.bwd`.
7848         duration = The duration which separates each successive time point in
7849                    the range.
7850   +/
7851 TP delegate(return scope const TP) everyDuration(TP, Direction dir = Direction.fwd, D)(D duration) nothrow
7852 if (isTimePoint!TP &&
7853     __traits(compiles, TP.init + duration) &&
7854     (dir == Direction.fwd || dir == Direction.bwd))
7855 {
7856     TP func(return scope const TP tp)
7857     {
7858         static if (dir == Direction.fwd)
7859             return tp + duration;
7860         else
7861             return tp - duration;
7862     }
7863 
7864     return &func;
7865 }
7866 
7867 ///
7868 @system unittest
7869 {
7870     import core.time : dur;
7871     import std.datetime.date : Date;
7872 
7873     auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27));
7874     auto func = everyDuration!Date(dur!"days"(8));
7875     auto range = interval.fwdRange(func);
7876 
7877     // Using PopFirst.yes would have made this Date(2010, 9, 10).
7878     assert(range.front == Date(2010, 9, 2));
7879 
7880     range.popFront();
7881     assert(range.front == Date(2010, 9, 10));
7882 
7883     range.popFront();
7884     assert(range.front == Date(2010, 9, 18));
7885 
7886     range.popFront();
7887     assert(range.front == Date(2010, 9, 26));
7888 
7889     range.popFront();
7890     assert(range.empty);
7891 }
7892 
7893 @system unittest
7894 {
7895     import std.datetime.date;
7896     import std.datetime.systime;
7897 
7898     auto funcFwd = everyDuration!Date(dur!"days"(27));
7899     auto funcBwd = everyDuration!(Date, Direction.bwd)(dur!"days"(27));
7900 
7901     assert(funcFwd(Date(2009, 12, 25)) == Date(2010, 1, 21));
7902     assert(funcFwd(Date(2009, 12, 26)) == Date(2010, 1, 22));
7903     assert(funcFwd(Date(2009, 12, 27)) == Date(2010, 1, 23));
7904     assert(funcFwd(Date(2009, 12, 28)) == Date(2010, 1, 24));
7905 
7906     assert(funcBwd(Date(2010, 1, 21)) == Date(2009, 12, 25));
7907     assert(funcBwd(Date(2010, 1, 22)) == Date(2009, 12, 26));
7908     assert(funcBwd(Date(2010, 1, 23)) == Date(2009, 12, 27));
7909     assert(funcBwd(Date(2010, 1, 24)) == Date(2009, 12, 28));
7910 
7911     assert(everyDuration!Date(dur!"hnsecs"(1)) !is null);
7912     assert(everyDuration!TimeOfDay(dur!"hnsecs"(1)) !is null);
7913     assert(everyDuration!DateTime(dur!"hnsecs"(1)) !is null);
7914     assert(everyDuration!SysTime(dur!"hnsecs"(1)) !is null);
7915 }
7916 
7917 
7918 /++
7919     Range-generating function.
7920 
7921     Returns a delegate which returns the next time point which is the given
7922     number of years, month, and duration later.
7923 
7924     The difference between this version of `everyDuration` and the version
7925     which just takes a $(REF Duration, core,time) is that this one also takes
7926     the number of years and months (along with an `AllowDayOverflow` to
7927     indicate whether adding years and months should allow the days to overflow).
7928 
7929     Note that if iterating forward, `add!"years"()` is called on the given
7930     time point, then `add!"months"()`, and finally the duration is added
7931     to it. However, if iterating backwards, the duration is added first, then
7932     `add!"months"()` is called, and finally `add!"years"()` is called.
7933     That way, going backwards generates close to the same time points that
7934     iterating forward does, but since adding years and months is not entirely
7935     reversible (due to possible day overflow, regardless of whether
7936     `AllowDayOverflow.yes` or `AllowDayOverflow.no` is used), it can't be
7937     guaranteed that iterating backwards will give the same time points as
7938     iterating forward would have (even assuming that the end of the range is a
7939     time point which would be returned by the delegate when iterating forward
7940     from `begin`).
7941 
7942     Params:
7943         dir           = The direction to iterate in. If passing the return
7944                         value to `fwdRange`, use `Direction.fwd`. If
7945                         passing it to `bwdRange`, use `Direction.bwd`.
7946         years         = The number of years to add to the time point passed to
7947                         the delegate.
7948         months        = The number of months to add to the time point passed to
7949                         the delegate.
7950         allowOverflow = Whether the days should be allowed to overflow on
7951                         `begin` and `end`, causing their month to
7952                         increment.
7953         duration      = The duration to add to the time point passed to the
7954                         delegate.
7955   +/
7956 TP delegate(scope const TP) everyDuration(TP, Direction dir = Direction.fwd, D)
7957                                  (int years,
7958                                  int months = 0,
7959                                  AllowDayOverflow allowOverflow = AllowDayOverflow.yes,
7960                                  D duration = dur!"days"(0)) nothrow
7961 if (isTimePoint!TP &&
7962     __traits(compiles, TP.init + duration) &&
7963     __traits(compiles, TP.init.add!"years"(years)) &&
7964     __traits(compiles, TP.init.add!"months"(months)) &&
7965     (dir == Direction.fwd || dir == Direction.bwd))
7966 {
7967     TP func(scope const TP tp)
7968     {
7969         static if (dir == Direction.fwd)
7970         {
7971             TP retval = cast(TP) tp;
7972 
7973             retval.add!"years"(years, allowOverflow);
7974             retval.add!"months"(months, allowOverflow);
7975 
7976             return retval + duration;
7977         }
7978         else
7979         {
7980             TP retval = tp - duration;
7981 
7982             retval.add!"months"(-months, allowOverflow);
7983             retval.add!"years"(-years, allowOverflow);
7984 
7985             return retval;
7986         }
7987     }
7988 
7989     return &func;
7990 }
7991 
7992 ///
7993 @system unittest
7994 {
7995     import core.time : dur;
7996     import std.datetime.date : AllowDayOverflow, Date;
7997 
7998     auto interval = Interval!Date(Date(2010, 9, 2), Date(2025, 9, 27));
7999     auto func = everyDuration!Date(4, 1, AllowDayOverflow.yes, dur!"days"(2));
8000     auto range = interval.fwdRange(func);
8001 
8002     // Using PopFirst.yes would have made this Date(2014, 10, 12).
8003     assert(range.front == Date(2010, 9, 2));
8004 
8005     range.popFront();
8006     assert(range.front == Date(2014, 10, 4));
8007 
8008     range.popFront();
8009     assert(range.front == Date(2018, 11, 6));
8010 
8011     range.popFront();
8012     assert(range.front == Date(2022, 12, 8));
8013 
8014     range.popFront();
8015     assert(range.empty);
8016 }
8017 
8018 @system unittest
8019 {
8020     import std.datetime.date;
8021     import std.datetime.systime;
8022 
8023     {
8024         auto funcFwd = everyDuration!Date(1, 2, AllowDayOverflow.yes, dur!"days"(3));
8025         auto funcBwd = everyDuration!(Date, Direction.bwd)(1, 2, AllowDayOverflow.yes, dur!"days"(3));
8026 
8027         assert(funcFwd(Date(2009, 12, 25)) == Date(2011, 2, 28));
8028         assert(funcFwd(Date(2009, 12, 26)) == Date(2011, 3, 1));
8029         assert(funcFwd(Date(2009, 12, 27)) == Date(2011, 3, 2));
8030         assert(funcFwd(Date(2009, 12, 28)) == Date(2011, 3, 3));
8031         assert(funcFwd(Date(2009, 12, 29)) == Date(2011, 3, 4));
8032 
8033         assert(funcBwd(Date(2011, 2, 28)) == Date(2009, 12, 25));
8034         assert(funcBwd(Date(2011, 3, 1)) == Date(2009, 12, 26));
8035         assert(funcBwd(Date(2011, 3, 2)) == Date(2009, 12, 27));
8036         assert(funcBwd(Date(2011, 3, 3)) == Date(2009, 12, 28));
8037         assert(funcBwd(Date(2011, 3, 4)) == Date(2010, 1, 1));
8038     }
8039 
8040     {
8041         auto funcFwd = everyDuration!Date(1, 2, AllowDayOverflow.no, dur!"days"(3));
8042         auto funcBwd = everyDuration!(Date, Direction.bwd)(1, 2, AllowDayOverflow.yes, dur!"days"(3));
8043 
8044         assert(funcFwd(Date(2009, 12, 25)) == Date(2011, 2, 28));
8045         assert(funcFwd(Date(2009, 12, 26)) == Date(2011, 3, 1));
8046         assert(funcFwd(Date(2009, 12, 27)) == Date(2011, 3, 2));
8047         assert(funcFwd(Date(2009, 12, 28)) == Date(2011, 3, 3));
8048         assert(funcFwd(Date(2009, 12, 29)) == Date(2011, 3, 3));
8049 
8050         assert(funcBwd(Date(2011, 2, 28)) == Date(2009, 12, 25));
8051         assert(funcBwd(Date(2011, 3, 1)) == Date(2009, 12, 26));
8052         assert(funcBwd(Date(2011, 3, 2)) == Date(2009, 12, 27));
8053         assert(funcBwd(Date(2011, 3, 3)) == Date(2009, 12, 28));
8054         assert(funcBwd(Date(2011, 3, 4)) == Date(2010, 1, 1));
8055     }
8056 
8057     assert(everyDuration!Date(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1)) !is null);
8058     static assert(!__traits(compiles, everyDuration!TimeOfDay(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1))));
8059     assert(everyDuration!DateTime(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1)) !is null);
8060     assert(everyDuration!SysTime(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1)) !is null);
8061 }
8062 
8063 
8064 /++
8065     A range over an $(LREF Interval).
8066 
8067     `IntervalRange` is only ever constructed by $(LREF Interval). However, when
8068     it is constructed, it is given a function, `func`, which is used to
8069     generate the time points which are iterated over. `func` takes a time
8070     point and returns a time point of the same type. For instance,
8071     to iterate over all of the days in
8072     the interval `Interval!Date`, pass a function to $(LREF Interval)'s
8073     `fwdRange` where that function took a $(REF Date,std,datetime,date) and
8074     returned a $(REF Date,std,datetime,date) which was one day later. That
8075     function would then be used by `IntervalRange`'s `popFront` to iterate
8076     over the $(REF Date,std,datetime,date)s in the interval.
8077 
8078     If $(D dir == Direction.fwd), then a range iterates forward in time, whereas
8079     if $(D dir == Direction.bwd), then it iterates backwards in time. So, if
8080     $(D dir == Direction.fwd) then $(D front == interval.begin), whereas if
8081     $(D dir == Direction.bwd) then $(D front == interval.end). `func` must
8082     generate a time point going in the proper direction of iteration, or a
8083     $(REF DateTimeException,std,datetime,date) will be thrown. So, to iterate
8084     forward in time, the time point that `func` generates must be later in
8085     time than the one passed to it. If it's either identical or earlier in time,
8086     then a $(REF DateTimeException,std,datetime,date) will be thrown. To
8087     iterate backwards, then the generated time point must be before the time
8088     point which was passed in.
8089 
8090     If the generated time point is ever passed the edge of the range in the
8091     proper direction, then the edge of that range will be used instead. So, if
8092     iterating forward, and the generated time point is past the interval's
8093     `end`, then `front` becomes `end`. If iterating backwards, and the
8094     generated time point is before `begin`, then `front` becomes
8095     `begin`. In either case, the range would then be empty.
8096 
8097     Also note that while normally the `begin` of an interval is included in
8098     it and its `end` is excluded from it, if $(D dir == Direction.bwd), then
8099     `begin` is treated as excluded and `end` is treated as included. This
8100     allows for the same behavior in both directions. This works because none of
8101     $(LREF Interval)'s functions which care about whether `begin` or `end`
8102     is included or excluded are ever called by `IntervalRange`. `interval`
8103     returns a normal interval, regardless of whether $(D dir == Direction.fwd)
8104     or if $(D dir == Direction.bwd), so any $(LREF Interval) functions which are
8105     called on it which care about whether `begin` or `end` are included or
8106     excluded will treat `begin` as included and `end` as excluded.
8107   +/
8108 struct IntervalRange(TP, Direction dir)
8109 if (isTimePoint!TP && dir != Direction.both)
8110 {
8111 public:
8112 
8113     /++
8114         Params:
8115             rhs = The `IntervalRange` to assign to this one.
8116       +/
8117     ref IntervalRange opAssign(ref IntervalRange rhs) pure nothrow
8118     {
8119         _interval = rhs._interval;
8120         _func = rhs._func;
8121         return this;
8122     }
8123 
8124 
8125     /++ Ditto +/
8126     ref IntervalRange opAssign(IntervalRange rhs) pure nothrow
8127     {
8128         return this = rhs;
8129     }
8130 
8131 
8132     /++
8133         Whether this `IntervalRange` is empty.
8134       +/
8135     @property bool empty() const pure nothrow
8136     {
8137         return _interval.empty;
8138     }
8139 
8140 
8141     /++
8142         The first time point in the range.
8143 
8144         Throws:
8145             $(REF DateTimeException,std,datetime,date) if the range is empty.
8146       +/
8147     @property TP front() const pure
8148     {
8149         _enforceNotEmpty();
8150 
8151         static if (dir == Direction.fwd)
8152             return _interval.begin;
8153         else
8154             return _interval.end;
8155     }
8156 
8157 
8158     /++
8159         Pops `front` from the range, using `func` to generate the next
8160         time point in the range. If the generated time point is beyond the edge
8161         of the range, then `front` is set to that edge, and the range is then
8162         empty. So, if iterating forwards, and the generated time point is
8163         greater than the interval's `end`, then `front` is set to
8164         `end`. If iterating backwards, and the generated time point is less
8165         than the interval's `begin`, then `front` is set to `begin`.
8166 
8167         Throws:
8168             $(REF DateTimeException,std,datetime,date) if the range is empty
8169             or if the generated time point is in the wrong direction (i.e. if
8170             iterating forward and the generated time point is before `front`,
8171             or if iterating backwards and the generated time point is after
8172             `front`).
8173       +/
8174     void popFront()
8175     {
8176         _enforceNotEmpty();
8177 
8178         static if (dir == Direction.fwd)
8179         {
8180             auto begin = _func(_interval.begin);
8181 
8182             if (begin > _interval.end)
8183                 begin = _interval.end;
8184 
8185             _enforceCorrectDirection(begin);
8186 
8187             _interval.begin = begin;
8188         }
8189         else
8190         {
8191             auto end = _func(_interval.end);
8192 
8193             if (end < _interval.begin)
8194                 end = _interval.begin;
8195 
8196             _enforceCorrectDirection(end);
8197 
8198             _interval.end = end;
8199         }
8200     }
8201 
8202 
8203     /++
8204         Returns a copy of `this`.
8205       +/
8206     @property IntervalRange save() pure nothrow
8207     {
8208         return this;
8209     }
8210 
8211 
8212     /++
8213         The interval that this `IntervalRange` currently covers.
8214       +/
8215     @property Interval!TP interval() const pure nothrow
8216     {
8217         return cast(Interval!TP)_interval;
8218     }
8219 
8220 
8221     /++
8222         The function used to generate the next time point in the range.
8223       +/
8224     TP delegate(scope const TP) func() pure nothrow @property
8225     {
8226         return _func;
8227     }
8228 
8229 
8230     /++
8231         The `Direction` that this range iterates in.
8232       +/
8233     @property Direction direction() const pure nothrow
8234     {
8235         return dir;
8236     }
8237 
8238 
8239 private:
8240 
8241     /+
8242         Params:
8243             interval = The interval that this range covers.
8244             func     = The function used to generate the time points which are
8245                        iterated over.
8246       +/
8247     this(const Interval!TP interval, TP delegate(scope const TP) func) pure nothrow @safe
8248     {
8249         _func = func;
8250         _interval = interval;
8251     }
8252 
8253 
8254     /+
8255         Throws:
8256             $(REF DateTimeException,std,datetime,date) if this interval is
8257             empty.
8258       +/
8259     void _enforceNotEmpty(size_t line = __LINE__) const pure
8260     {
8261         if (empty)
8262             throw new DateTimeException("Invalid operation for an empty IntervalRange.", __FILE__, line);
8263     }
8264 
8265 
8266     /+
8267         Throws:
8268             $(REF DateTimeException,std,datetime,date) if $(D_PARAM newTP) is
8269             in the wrong direction.
8270       +/
8271     void _enforceCorrectDirection(scope const TP newTP, size_t line = __LINE__) const
8272     {
8273         import std.format : format;
8274 
8275         static if (dir == Direction.fwd)
8276         {
8277             enforce(newTP > _interval._begin,
8278                     new DateTimeException(format("Generated time point is before previous begin: prev [%s] new [%s]",
8279                                                  interval._begin,
8280                                                  newTP),
8281                                                  __FILE__,
8282                                                  line));
8283         }
8284         else
8285         {
8286             enforce(newTP < _interval._end,
8287                     new DateTimeException(format("Generated time point is after previous end: prev [%s] new [%s]",
8288                                                  interval._end,
8289                                                  newTP),
8290                                                  __FILE__,
8291                                                  line));
8292         }
8293     }
8294 
8295 
8296     Interval!TP        _interval;
8297     TP delegate(scope const TP) _func;
8298 }
8299 
8300 //Test that IntervalRange satisfies the range predicates that it's supposed to satisfy.
8301 @safe unittest
8302 {
8303     import std.datetime.date;
8304     import std.datetime.systime;
8305     import std.range.primitives;
8306 
8307     static assert(isInputRange!(IntervalRange!(Date, Direction.fwd)));
8308     static assert(isForwardRange!(IntervalRange!(Date, Direction.fwd)));
8309 
8310     // Commented out due to bug https://issues.dlang.org/show_bug.cgi?id=4895
8311     // static assert(!isOutputRange!(IntervalRange!(Date, Direction.fwd), Date));
8312 
8313     static assert(!isBidirectionalRange!(IntervalRange!(Date, Direction.fwd)));
8314     static assert(!isRandomAccessRange!(IntervalRange!(Date, Direction.fwd)));
8315     static assert(!hasSwappableElements!(IntervalRange!(Date, Direction.fwd)));
8316     static assert(!hasAssignableElements!(IntervalRange!(Date, Direction.fwd)));
8317     static assert(!hasLength!(IntervalRange!(Date, Direction.fwd)));
8318     static assert(!isInfinite!(IntervalRange!(Date, Direction.fwd)));
8319     static assert(!hasSlicing!(IntervalRange!(Date, Direction.fwd)));
8320 
8321     static assert(is(ElementType!(IntervalRange!(Date, Direction.fwd)) == Date));
8322     static assert(is(ElementType!(IntervalRange!(TimeOfDay, Direction.fwd)) == TimeOfDay));
8323     static assert(is(ElementType!(IntervalRange!(DateTime, Direction.fwd)) == DateTime));
8324     static assert(is(ElementType!(IntervalRange!(SysTime, Direction.fwd)) == SysTime));
8325 }
8326 
8327 //Test construction of IntervalRange.
8328 @safe unittest
8329 {
8330     import std.datetime.date;
8331     import std.datetime.systime;
8332 
8333     {
8334         Date dateFunc(scope const Date date) { return date; }
8335         auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
8336         auto ir = IntervalRange!(Date, Direction.fwd)(interval, &dateFunc);
8337     }
8338 
8339     {
8340         TimeOfDay todFunc(scope const TimeOfDay tod) { return tod; }
8341         auto interval = Interval!TimeOfDay(TimeOfDay(12, 1, 7), TimeOfDay(14, 0, 0));
8342         auto ir = IntervalRange!(TimeOfDay, Direction.fwd)(interval, &todFunc);
8343     }
8344 
8345     {
8346         DateTime dtFunc(scope const DateTime dt) { return dt; }
8347         auto interval = Interval!DateTime(DateTime(2010, 7, 4, 12, 1, 7), DateTime(2012, 1, 7, 14, 0, 0));
8348         auto ir = IntervalRange!(DateTime, Direction.fwd)(interval, &dtFunc);
8349     }
8350 
8351     {
8352         SysTime stFunc(scope const SysTime st) { return SysTime.init; }
8353         auto interval = Interval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7)),
8354                                          SysTime(DateTime(2012, 1, 7, 14, 0, 0)));
8355         auto ir = IntervalRange!(SysTime, Direction.fwd)(interval, &stFunc);
8356     }
8357 }
8358 
8359 //Test IntervalRange's empty().
8360 @system unittest
8361 {
8362     import std.datetime.date;
8363 
8364     //fwd
8365     {
8366         auto range = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
8367 
8368         assert(!range.empty);
8369         range.popFront();
8370         assert(range.empty);
8371 
8372         const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
8373         assert(!cRange.empty);
8374 
8375         //Apparently, creating an immutable IntervalRange!Date doesn't work, so we can't test if
8376         //empty works with it. However, since an immutable range is pretty useless, it's no great loss.
8377     }
8378 
8379     //bwd
8380     {
8381         auto range = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21)).bwdRange(
8382             everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
8383 
8384         assert(!range.empty);
8385         range.popFront();
8386         assert(range.empty);
8387 
8388         const cRange = Interval!Date( Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(
8389             everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
8390         assert(!cRange.empty);
8391 
8392         //Apparently, creating an immutable IntervalRange!Date doesn't work, so we can't test if
8393         //empty works with it. However, since an immutable range is pretty useless, it's no great loss.
8394     }
8395 }
8396 
8397 //Test IntervalRange's front.
8398 @system unittest
8399 {
8400     import std.datetime.date;
8401 
8402     //fwd
8403     {
8404         auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).fwdRange(
8405             everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
8406         assertThrown!DateTimeException(
8407             (scope const IntervalRange!(Date, Direction.fwd) range){range.front;}(emptyRange));
8408 
8409         auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed));
8410         assert(range.front == Date(2010, 7, 4));
8411 
8412         auto poppedRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(
8413             everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
8414         assert(poppedRange.front == Date(2010, 7, 7));
8415 
8416         const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
8417         assert(cRange.front != Date.init);
8418     }
8419 
8420     //bwd
8421     {
8422         auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).bwdRange(
8423             everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
8424         assertThrown!DateTimeException(
8425             (scope const IntervalRange!(Date, Direction.bwd) range){range.front;}(emptyRange));
8426 
8427         auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(
8428             everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed));
8429         assert(range.front == Date(2012, 1, 7));
8430 
8431         auto poppedRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(
8432             everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
8433         assert(poppedRange.front == Date(2012, 1, 4));
8434 
8435         const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(
8436             everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
8437         assert(cRange.front != Date.init);
8438     }
8439 }
8440 
8441 //Test IntervalRange's popFront().
8442 @system unittest
8443 {
8444     import std.datetime.date;
8445     import std.range.primitives : walkLength;
8446 
8447     //fwd
8448     {
8449         auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).fwdRange(
8450             everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
8451         assertThrown!DateTimeException((IntervalRange!(Date, Direction.fwd) range){range.popFront();}(emptyRange));
8452 
8453         auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(
8454             everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
8455         auto expected = range.front;
8456 
8457         foreach (date; range)
8458         {
8459             assert(date == expected);
8460             expected += dur!"days"(7);
8461         }
8462 
8463         assert(walkLength(range) == 79);
8464 
8465         const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
8466         assert(cRange.front != Date.init);
8467     }
8468 
8469     //bwd
8470     {
8471         auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).bwdRange(
8472             everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
8473         assertThrown!DateTimeException((IntervalRange!(Date, Direction.bwd) range){range.popFront();}(emptyRange));
8474 
8475         auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(
8476             everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
8477         auto expected = range.front;
8478 
8479         foreach (date; range)
8480         {
8481             assert(date == expected);
8482             expected += dur!"days"(-7);
8483         }
8484 
8485         assert(walkLength(range) == 79);
8486 
8487         const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(
8488             everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
8489         static assert(!__traits(compiles, cRange.popFront()));
8490     }
8491 }
8492 
8493 //Test IntervalRange's save.
8494 @system unittest
8495 {
8496     import std.datetime.date;
8497 
8498     //fwd
8499     {
8500         auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
8501         auto func = everyDayOfWeek!Date(DayOfWeek.fri);
8502         auto range = interval.fwdRange(func);
8503 
8504         assert(range.save == range);
8505     }
8506 
8507     //bwd
8508     {
8509         auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
8510         auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
8511         auto range = interval.bwdRange(func);
8512 
8513         assert(range.save == range);
8514     }
8515 }
8516 
8517 //Test IntervalRange's interval.
8518 @system unittest
8519 {
8520     import std.datetime.date;
8521 
8522     //fwd
8523     {
8524         auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
8525         auto func = everyDayOfWeek!Date(DayOfWeek.fri);
8526         auto range = interval.fwdRange(func);
8527 
8528         assert(range.interval == interval);
8529 
8530         const cRange = range;
8531         assert(!cRange.interval.empty);
8532     }
8533 
8534     //bwd
8535     {
8536         auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
8537         auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
8538         auto range = interval.bwdRange(func);
8539 
8540         assert(range.interval == interval);
8541 
8542         const cRange = range;
8543         assert(!cRange.interval.empty);
8544     }
8545 }
8546 
8547 //Test IntervalRange's func.
8548 @system unittest
8549 {
8550     import std.datetime.date;
8551 
8552     //fwd
8553     {
8554         auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
8555         auto func = everyDayOfWeek!Date(DayOfWeek.fri);
8556         auto range = interval.fwdRange(func);
8557 
8558         assert(range.func == func);
8559     }
8560 
8561     //bwd
8562     {
8563         auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
8564         auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
8565         auto range = interval.bwdRange(func);
8566 
8567         assert(range.func == func);
8568     }
8569 }
8570 
8571 //Test IntervalRange's direction.
8572 @system unittest
8573 {
8574     import std.datetime.date;
8575 
8576     //fwd
8577     {
8578         auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
8579         auto func = everyDayOfWeek!Date(DayOfWeek.fri);
8580         auto range = interval.fwdRange(func);
8581 
8582         assert(range.direction == Direction.fwd);
8583 
8584         const cRange = range;
8585         assert(cRange.direction == Direction.fwd);
8586     }
8587 
8588     //bwd
8589     {
8590         auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
8591         auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
8592         auto range = interval.bwdRange(func);
8593 
8594         assert(range.direction == Direction.bwd);
8595 
8596         const cRange = range;
8597         assert(cRange.direction == Direction.bwd);
8598     }
8599 }
8600 
8601 
8602 /++
8603     A range over a `PosInfInterval`. It is an infinite range.
8604 
8605     `PosInfIntervalRange` is only ever constructed by `PosInfInterval`.
8606     However, when it is constructed, it is given a function, `func`, which
8607     is used to generate the time points which are iterated over. `func`
8608     takes a time point and returns a time point of the same type. For
8609     instance, to iterate
8610     over all of the days in the interval `PosInfInterval!Date`, pass a
8611     function to `PosInfInterval`'s `fwdRange` where that function took a
8612     $(REF Date,std,datetime,date) and returned a $(REF Date,std,datetime,date)
8613     which was one day later. That function would then be used by
8614     `PosInfIntervalRange`'s `popFront` to iterate over the
8615     $(REF Date,std,datetime,date)s in the interval - though obviously, since the
8616     range is infinite, use a function such as `std.range.take` with it rather
8617     than iterating over $(I all) of the dates.
8618 
8619     As the interval goes to positive infinity, the range is always iterated over
8620     forwards, never backwards. `func` must generate a time point going in
8621     the proper direction of iteration, or a
8622     $(REF DateTimeException,std,datetime,date) will be thrown. So, the time
8623     points that `func` generates must be later in time than the one passed to
8624     it. If it's either identical or earlier in time, then a
8625     $(REF DateTimeException,std,datetime,date) will be thrown.
8626   +/
8627 struct PosInfIntervalRange(TP)
8628 if (isTimePoint!TP)
8629 {
8630 public:
8631 
8632     /++
8633         Params:
8634             rhs = The `PosInfIntervalRange` to assign to this one.
8635       +/
8636     ref PosInfIntervalRange opAssign(ref PosInfIntervalRange rhs) pure nothrow
8637     {
8638         _interval = rhs._interval;
8639         _func = rhs._func;
8640         return this;
8641     }
8642 
8643 
8644     /++ Ditto +/
8645     ref PosInfIntervalRange opAssign(PosInfIntervalRange rhs) pure nothrow
8646     {
8647         return this = rhs;
8648     }
8649 
8650 
8651     /++
8652         This is an infinite range, so it is never empty.
8653       +/
8654     enum bool empty = false;
8655 
8656 
8657     /++
8658         The first time point in the range.
8659       +/
8660     @property TP front() const pure nothrow
8661     {
8662         return _interval.begin;
8663     }
8664 
8665 
8666     /++
8667         Pops `front` from the range, using `func` to generate the next
8668         time point in the range.
8669 
8670         Throws:
8671             $(REF DateTimeException,std,datetime,date) if the generated time
8672             point is less than `front`.
8673       +/
8674     void popFront()
8675     {
8676         auto begin = _func(_interval.begin);
8677         _enforceCorrectDirection(begin);
8678         _interval.begin = begin;
8679     }
8680 
8681 
8682     /++
8683         Returns a copy of `this`.
8684       +/
8685     @property PosInfIntervalRange save() pure nothrow
8686     {
8687         return this;
8688     }
8689 
8690 
8691     /++
8692         The interval that this range currently covers.
8693       +/
8694     @property PosInfInterval!TP interval() const pure nothrow
8695     {
8696         return cast(PosInfInterval!TP)_interval;
8697     }
8698 
8699 
8700     /++
8701         The function used to generate the next time point in the range.
8702       +/
8703     TP delegate(scope const TP) func() pure nothrow @property
8704     {
8705         return _func;
8706     }
8707 
8708 
8709 private:
8710 
8711     /+
8712         Params:
8713             interval = The interval that this range covers.
8714             func     = The function used to generate the time points which are
8715                        iterated over.
8716       +/
8717     this(const PosInfInterval!TP interval, TP delegate(scope const TP) func) pure nothrow
8718     {
8719         _func = func;
8720         _interval = interval;
8721     }
8722 
8723 
8724     /+
8725         Throws:
8726             $(REF DateTimeException,std,datetime,date) if $(D_PARAM newTP) is
8727             in the wrong direction.
8728       +/
8729     void _enforceCorrectDirection(scope const TP newTP, size_t line = __LINE__) const
8730     {
8731         import std.format : format;
8732 
8733         enforce(newTP > _interval._begin,
8734                 new DateTimeException(format("Generated time point is before previous begin: prev [%s] new [%s]",
8735                                              interval._begin,
8736                                              newTP),
8737                                              __FILE__,
8738                                              line));
8739     }
8740 
8741 
8742     PosInfInterval!TP  _interval;
8743     TP delegate(scope const TP) _func;
8744 }
8745 
8746 //Test that PosInfIntervalRange satisfies the range predicates that it's supposed to satisfy.
8747 @safe unittest
8748 {
8749     import std.datetime.date;
8750     import std.datetime.systime;
8751     import std.range.primitives;
8752 
8753     static assert(isInputRange!(PosInfIntervalRange!Date));
8754     static assert(isForwardRange!(PosInfIntervalRange!Date));
8755     static assert(isInfinite!(PosInfIntervalRange!Date));
8756 
8757     // Commented out due to bug https://issues.dlang.org/show_bug.cgi?id=4895
8758     // static assert(!isOutputRange!(PosInfIntervalRange!Date, Date));
8759     static assert(!isBidirectionalRange!(PosInfIntervalRange!Date));
8760     static assert(!isRandomAccessRange!(PosInfIntervalRange!Date));
8761     static assert(!hasSwappableElements!(PosInfIntervalRange!Date));
8762     static assert(!hasAssignableElements!(PosInfIntervalRange!Date));
8763     static assert(!hasLength!(PosInfIntervalRange!Date));
8764     static assert(!hasSlicing!(PosInfIntervalRange!Date));
8765 
8766     static assert(is(ElementType!(PosInfIntervalRange!Date) == Date));
8767     static assert(is(ElementType!(PosInfIntervalRange!TimeOfDay) == TimeOfDay));
8768     static assert(is(ElementType!(PosInfIntervalRange!DateTime) == DateTime));
8769     static assert(is(ElementType!(PosInfIntervalRange!SysTime) == SysTime));
8770 }
8771 
8772 //Test construction of PosInfIntervalRange.
8773 @safe unittest
8774 {
8775     import std.datetime.date;
8776     import std.datetime.systime;
8777 
8778     {
8779         Date dateFunc(scope const Date date) { return date; }
8780         auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
8781         auto ir = PosInfIntervalRange!Date(posInfInterval, &dateFunc);
8782     }
8783 
8784     {
8785         TimeOfDay todFunc(scope const TimeOfDay tod) { return tod; }
8786         auto posInfInterval = PosInfInterval!TimeOfDay(TimeOfDay(12, 1, 7));
8787         auto ir = PosInfIntervalRange!(TimeOfDay)(posInfInterval, &todFunc);
8788     }
8789 
8790     {
8791         DateTime dtFunc(scope const DateTime dt) { return dt; }
8792         auto posInfInterval = PosInfInterval!DateTime(DateTime(2010, 7, 4, 12, 1, 7));
8793         auto ir = PosInfIntervalRange!(DateTime)(posInfInterval, &dtFunc);
8794     }
8795 
8796     {
8797         SysTime stFunc(scope const SysTime st) { return SysTime.init; }
8798         auto posInfInterval = PosInfInterval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7)));
8799         auto ir = PosInfIntervalRange!SysTime(posInfInterval, &stFunc);
8800     }
8801 }
8802 
8803 //Test PosInfIntervalRange's front.
8804 @system unittest
8805 {
8806     import std.datetime.date;
8807 
8808     auto range = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed));
8809     assert(range.front == Date(2010, 7, 4));
8810 
8811     auto poppedRange = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
8812     assert(poppedRange.front == Date(2010, 7, 7));
8813 
8814     const cRange = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
8815     assert(cRange.front != Date.init);
8816 }
8817 
8818 //Test PosInfIntervalRange's popFront().
8819 @system unittest
8820 {
8821     import std.datetime.date;
8822     import std.range : take;
8823 
8824     auto range = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
8825     auto expected = range.front;
8826 
8827     foreach (date; take(range, 79))
8828     {
8829         assert(date == expected);
8830         expected += dur!"days"(7);
8831     }
8832 
8833     const cRange = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
8834     static assert(!__traits(compiles, cRange.popFront()));
8835 }
8836 
8837 //Test PosInfIntervalRange's save.
8838 @system unittest
8839 {
8840     import std.datetime.date;
8841 
8842     auto interval = PosInfInterval!Date(Date(2010, 7, 4));
8843     auto func = everyDayOfWeek!Date(DayOfWeek.fri);
8844     auto range = interval.fwdRange(func);
8845 
8846     assert(range.save == range);
8847 }
8848 
8849 //Test PosInfIntervalRange's interval.
8850 @system unittest
8851 {
8852     import std.datetime.date;
8853 
8854     auto interval = PosInfInterval!Date(Date(2010, 7, 4));
8855     auto func = everyDayOfWeek!Date(DayOfWeek.fri);
8856     auto range = interval.fwdRange(func);
8857 
8858     assert(range.interval == interval);
8859 
8860     const cRange = range;
8861     assert(!cRange.interval.empty);
8862 }
8863 
8864 //Test PosInfIntervalRange's func.
8865 @system unittest
8866 {
8867     import std.datetime.date;
8868 
8869     auto interval = PosInfInterval!Date(Date(2010, 7, 4));
8870     auto func = everyDayOfWeek!Date(DayOfWeek.fri);
8871     auto range = interval.fwdRange(func);
8872 
8873     assert(range.func == func);
8874 }
8875 
8876 
8877 /++
8878     A range over a `NegInfInterval`. It is an infinite range.
8879 
8880     `NegInfIntervalRange` is only ever constructed by `NegInfInterval`.
8881     However, when it is constructed, it is given a function, `func`, which
8882     is used to generate the time points which are iterated over. `func`
8883     takes a time point and returns a time point of the same type. For
8884     instance, to iterate over all of the days in the interval
8885     `NegInfInterval!Date`, pass a function to `NegInfInterval`'s
8886     `bwdRange` where that function took a $(REF Date,std,datetime,date) and
8887     returned a $(REF Date,std,datetime,date) which was one day earlier. That
8888     function would then be used by `NegInfIntervalRange`'s `popFront` to
8889     iterate over the $(REF Date,std,datetime,date)s in the interval - though
8890     obviously, since the range is infinite, use a function such as
8891     `std.range.take` with it rather than iterating over $(I all) of the dates.
8892 
8893     As the interval goes to negative infinity, the range is always iterated over
8894     backwards, never forwards. `func` must generate a time point going in
8895     the proper direction of iteration, or a
8896     $(REF DateTimeException,std,datetime,date) will be thrown. So, the time
8897     points that `func` generates must be earlier in time than the one passed
8898     to it. If it's either identical or later in time, then a
8899     $(REF DateTimeException,std,datetime,date) will be thrown.
8900 
8901     Also note that while normally the `end` of an interval is excluded from
8902     it, `NegInfIntervalRange` treats it as if it were included. This allows
8903     for the same behavior as with `PosInfIntervalRange`. This works
8904     because none of `NegInfInterval`'s functions which care about whether
8905     `end` is included or excluded are ever called by
8906     `NegInfIntervalRange`. `interval` returns a normal interval, so any
8907     `NegInfInterval` functions which are called on it which care about
8908     whether `end` is included or excluded will treat `end` as excluded.
8909   +/
8910 struct NegInfIntervalRange(TP)
8911 if (isTimePoint!TP)
8912 {
8913 public:
8914 
8915     /++
8916         Params:
8917             rhs = The `NegInfIntervalRange` to assign to this one.
8918       +/
8919     ref NegInfIntervalRange opAssign(ref NegInfIntervalRange rhs) pure nothrow
8920     {
8921         _interval = rhs._interval;
8922         _func = rhs._func;
8923 
8924         return this;
8925     }
8926 
8927 
8928     /++ Ditto +/
8929     ref NegInfIntervalRange opAssign(NegInfIntervalRange rhs) pure nothrow
8930     {
8931         return this = rhs;
8932     }
8933 
8934 
8935     /++
8936         This is an infinite range, so it is never empty.
8937       +/
8938     enum bool empty = false;
8939 
8940 
8941     /++
8942         The first time point in the range.
8943       +/
8944     @property TP front() const pure nothrow
8945     {
8946         return _interval.end;
8947     }
8948 
8949 
8950     /++
8951         Pops `front` from the range, using `func` to generate the next
8952         time point in the range.
8953 
8954         Throws:
8955             $(REF DateTimeException,std,datetime,date) if the generated time
8956             point is greater than `front`.
8957       +/
8958     void popFront()
8959     {
8960         auto end = _func(_interval.end);
8961         _enforceCorrectDirection(end);
8962         _interval.end = end;
8963     }
8964 
8965 
8966     /++
8967         Returns a copy of `this`.
8968       +/
8969     @property NegInfIntervalRange save() pure nothrow
8970     {
8971         return this;
8972     }
8973 
8974 
8975     /++
8976         The interval that this range currently covers.
8977       +/
8978     @property NegInfInterval!TP interval() const pure nothrow
8979     {
8980         return cast(NegInfInterval!TP)_interval;
8981     }
8982 
8983 
8984     /++
8985         The function used to generate the next time point in the range.
8986       +/
8987     TP delegate(scope const TP) func() pure nothrow @property
8988     {
8989         return _func;
8990     }
8991 
8992 
8993 private:
8994 
8995     /+
8996         Params:
8997             interval = The interval that this range covers.
8998             func     = The function used to generate the time points which are
8999                        iterated over.
9000       +/
9001     this(const NegInfInterval!TP interval, TP delegate(scope const TP) func) pure nothrow
9002     {
9003         _func = func;
9004         _interval = interval;
9005     }
9006 
9007 
9008     /+
9009         Throws:
9010             $(REF DateTimeException,std,datetime,date) if $(D_PARAM newTP) is
9011             in the wrong direction.
9012       +/
9013     void _enforceCorrectDirection(scope const TP newTP, size_t line = __LINE__) const
9014     {
9015         import std.format : format;
9016 
9017         enforce(newTP < _interval._end,
9018                 new DateTimeException(format("Generated time point is before previous end: prev [%s] new [%s]",
9019                                              interval._end,
9020                                              newTP),
9021                                              __FILE__,
9022                                              line));
9023     }
9024 
9025 
9026     NegInfInterval!TP  _interval;
9027     TP delegate(scope const TP) _func;
9028 }
9029 
9030 //Test that NegInfIntervalRange satisfies the range predicates that it's supposed to satisfy.
9031 @safe unittest
9032 {
9033     import std.datetime.date;
9034     import std.range.primitives;
9035 
9036     static assert(isInputRange!(NegInfIntervalRange!Date));
9037     static assert(isForwardRange!(NegInfIntervalRange!Date));
9038     static assert(isInfinite!(NegInfIntervalRange!Date));
9039 
9040     // Commented out due to bug https://issues.dlang.org/show_bug.cgi?id=4895
9041     // static assert(!isOutputRange!(NegInfIntervalRange!Date, Date));
9042     static assert(!isBidirectionalRange!(NegInfIntervalRange!Date));
9043     static assert(!isRandomAccessRange!(NegInfIntervalRange!Date));
9044     static assert(!hasSwappableElements!(NegInfIntervalRange!Date));
9045     static assert(!hasAssignableElements!(NegInfIntervalRange!Date));
9046     static assert(!hasLength!(NegInfIntervalRange!Date));
9047     static assert(!hasSlicing!(NegInfIntervalRange!Date));
9048 
9049     static assert(is(ElementType!(NegInfIntervalRange!Date) == Date));
9050     static assert(is(ElementType!(NegInfIntervalRange!TimeOfDay) == TimeOfDay));
9051     static assert(is(ElementType!(NegInfIntervalRange!DateTime) == DateTime));
9052 }
9053 
9054 //Test construction of NegInfIntervalRange.
9055 @safe unittest
9056 {
9057     import std.datetime.date;
9058     import std.datetime.systime;
9059 
9060     {
9061         Date dateFunc(scope const Date date) { return date; }
9062         auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
9063         auto ir = NegInfIntervalRange!Date(negInfInterval, &dateFunc);
9064     }
9065 
9066     {
9067         TimeOfDay todFunc(scope const TimeOfDay tod) { return tod; }
9068         auto negInfInterval = NegInfInterval!TimeOfDay(TimeOfDay(14, 0, 0));
9069         auto ir = NegInfIntervalRange!(TimeOfDay)(negInfInterval, &todFunc);
9070     }
9071 
9072     {
9073         DateTime dtFunc(scope const DateTime dt) { return dt; }
9074         auto negInfInterval = NegInfInterval!DateTime(DateTime(2012, 1, 7, 14, 0, 0));
9075         auto ir = NegInfIntervalRange!(DateTime)(negInfInterval, &dtFunc);
9076     }
9077 
9078     {
9079         SysTime stFunc(scope const SysTime st) { return SysTime.init; }
9080         auto negInfInterval = NegInfInterval!SysTime(SysTime(DateTime(2012, 1, 7, 14, 0, 0)));
9081         auto ir = NegInfIntervalRange!(SysTime)(negInfInterval, &stFunc);
9082     }
9083 }
9084 
9085 //Test NegInfIntervalRange's front.
9086 @system unittest
9087 {
9088     import std.datetime.date;
9089 
9090     auto range = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed));
9091     assert(range.front == Date(2012, 1, 7));
9092 
9093     auto poppedRange = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(
9094         everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
9095     assert(poppedRange.front == Date(2012, 1, 4));
9096 
9097     const cRange = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
9098     assert(cRange.front != Date.init);
9099 }
9100 
9101 //Test NegInfIntervalRange's popFront().
9102 @system unittest
9103 {
9104     import std.datetime.date;
9105     import std.range : take;
9106 
9107     auto range = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(
9108         everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
9109     auto expected = range.front;
9110 
9111     foreach (date; take(range, 79))
9112     {
9113         assert(date == expected);
9114         expected += dur!"days"(-7);
9115     }
9116 
9117     const cRange = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
9118     static assert(!__traits(compiles, cRange.popFront()));
9119 }
9120 
9121 //Test NegInfIntervalRange's save.
9122 @system unittest
9123 {
9124     import std.datetime.date;
9125 
9126     auto interval = NegInfInterval!Date(Date(2012, 1, 7));
9127     auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
9128     auto range = interval.bwdRange(func);
9129 
9130     assert(range.save == range);
9131 }
9132 
9133 //Test NegInfIntervalRange's interval.
9134 @system unittest
9135 {
9136     import std.datetime.date;
9137 
9138     auto interval = NegInfInterval!Date(Date(2012, 1, 7));
9139     auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
9140     auto range = interval.bwdRange(func);
9141 
9142     assert(range.interval == interval);
9143 
9144     const cRange = range;
9145     assert(!cRange.interval.empty);
9146 }
9147 
9148 //Test NegInfIntervalRange's func.
9149 @system unittest
9150 {
9151     import std.datetime.date;
9152 
9153     auto interval = NegInfInterval!Date(Date(2012, 1, 7));
9154     auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
9155     auto range = interval.bwdRange(func);
9156 
9157     assert(range.func == func);
9158 }