1 /**
2  * Proleptic Gregorian calendar: date ranges
3  *
4  * Copyright: Maxim Freck, 2017.
5  * Authors:   Maxim Freck <maxim@freck.pp.ru>
6  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  */
8 module pgc.daterange;
9 
10 public import pgc.date;
11 
12 /***********************************
13  * An implementation of a ForwardRange for dates.
14  *
15  * Examples:
16  * --------------------
17  * DateRange(mkDate(20, 3, 2016), mkDate(4, 4, 2016)); //returns the date range between 2016-03-20 and 2016-04-04
18  * DateRange(2, 2016); //return the date range for the Feb. 2016
19  * DateRange(2016); //return the date range for the whole 2016 year
20  * --------------------
21  */
22 struct DateRange {
23 	private Date frontDate;
24 	private Date endDate;
25 
26 	@disable private this();
27 
28 	/// Constructor
29 	this(Date start, Date end) @safe
30 	{
31 		import std.algorithm: max, min;
32 		this.frontDate = min(start, end);
33 		this.endDate = max(start, end).nextDay;
34 	}
35 
36 	/// ditto
37 	this(int month, int year) @safe
38 	{
39 		this.frontDate = mkDate(1, month, year);
40 		this.endDate = mkDate(daysInMonth(month, year), month, year).nextDay;
41 	}
42 
43 	/// ditto
44 	this(int year) @safe
45 	{
46 		this.frontDate = mkDate(1, 1, year);
47 		this.endDate = mkDateISO(1, 1, ++year);
48 	}
49 
50 	/// for Range access
51 	pure nothrow bool empty() const @safe
52 	{
53 		return this.frontDate == this.endDate;
54 	}
55 
56 	/// ditto
57 	pure nothrow auto front() @safe
58 	{
59 		return this.frontDate;
60 	}
61 
62 	/// ditto
63 	pure void popFront() @safe
64 	{
65 		if (this.frontDate < this.endDate) this.frontDate = this.frontDate.nextDay;
66 	}
67 
68 	/// ditto
69 	auto save() const @safe
70 	{
71 		return this;
72 	}
73 
74 	/***********************************
75 	 * Returns the number of days in a range
76 	 */
77 	@property @safe pure nothrow auto days()
78 	{
79 		return daysBetween(this.frontDate, this.endDate);
80 	}
81 }
82 
83 
84 ///
85 @safe unittest
86 {
87 	auto Feb2016 = DateRange(2,2016);
88 
89 	assert(Feb2016.days == 29);
90 
91 	Feb2016.popFront();
92 	assert(Feb2016.front == mkDate(2, 2, 2016));
93 }