1 /*
2 	 -------------------------------------------------------------------
3 
4 	 Copyright (C) 2014, Edwin van Leeuwen
5 
6 	 This file is part of todod todo list manager.
7 
8 	 Todod is free software; you can redistribute it and/or modify
9 	 it under the terms of the GNU General Public License as published by
10 	 the Free Software Foundation; either version 3 of the License, or
11 	 (at your option) any later version.
12 
13 	 Todod is distributed in the hope that it will be useful,
14 	 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 	 GNU General Public License for more details.
17 
18 	 You should have received a copy of the GNU General Public License
19 	 along with Todod. If not, see <http://www.gnu.org/licenses/>.
20 
21 	 -------------------------------------------------------------------
22 	 */
23 
24 module todod.date;
25 
26 import datetime = std.datetime;
27 import std.conv;
28 import std.string;
29 import std.regex;
30 
31 /// Convenience struct around datetime.Date
32 struct Date {
33 	/// Return Date from given string
34 	this( string dateStr ) {
35 		if ( dateStr != "-1" ) {
36 			if (dateStr.match( r"^\d\d\d\d-\d\d-\d\d$" ) ) {
37 				mytime = 
38 					cast(datetime.SysTime)(datetime.Date.fromISOExtString( dateStr ));
39 			} else {
40 				mytime = datetime.SysTime.fromISOExtString( dateStr );
41 			}
42 			init = true;
43 		}
44 	}
45 
46 	/// Convert date to bool (used to test if date is initialized)
47 	bool opCast( T : bool )() const {
48 		return init;
49 	}
50 
51 	/// Return today's date
52 	static Date now() {
53 		Date dt;
54 		dt.mytime = datetime.Clock.currTime;
55 		dt.init = true;
56 		return dt;
57 	}
58 
59 	/// Returns difference in days
60 	long substract( const Date otherDate ) const {
61 		// First cast to dates, so that we work on actual dates, 
62 		// not number of 24 hours, i.e. the day before, but within 24 hours should
63 		// still count as a day.
64 		auto date1 = cast( datetime.Date )( this.mytime );
65 		auto date2 = cast( datetime.Date )( otherDate.mytime );
66 		return (date1 - date2).total!"days";
67 	}
68 
69 	/// Add given number of days
70 	void addDays( long days ) {
71 		mytime += datetime.dur!"days"(days);
72 	}
73 
74 	unittest {
75 		auto dt = Date( "2014-01-16" );
76 		dt.addDays(4);
77 		assert( dt.mytime.day == 20 );
78 		dt.addDays(31);
79 		assert( dt.mytime.day == 20 );
80 		assert( dt.mytime.month == 2 );
81 	}
82 
83 	/// Create copy of the date
84 	Date dup() {
85 		Date dt;
86 		dt.mytime = mytime;
87 		dt.init = true;
88 		return dt;
89 	}
90 
91 	private:
92 		datetime.SysTime mytime;
93 		bool init = false;
94 }
95 
96 version( unittest ) {
97 	import std.stdio;
98 }
99 
100 unittest {
101 	// Test for initialization
102 	Date dt;
103 	assert( !dt );
104 	dt = Date( "2014-08-01" );
105 	assert( dt );
106 
107 	dt = Date( "-1" );
108 	assert( !dt );
109 
110 	dt = Date.now;
111 	assert( dt );
112 }
113 
114 unittest {
115 	auto dt = Date( "2014-01-12T00:01:01" );
116 	assert( dt.substract( Date( "2014-01-16T00:02:01" ) ) == -4 );
117 	assert( dt.substract( Date( "2014-01-01T00:02:01" ) ) == 11 );
118 	assert( dt.substract( Date( "2013-01-12T00:02:01" ) ) == 365 );
119 }
120 
121 /// Convert date to ISO string
122 string toString( const Date dt ) {
123 	if (dt)
124 		return dt.mytime.toISOExtString();
125 	else
126 		return "-1";
127 }
128 
129 /// Convert date to simple string
130 string toStringDate( const Date dt ) {
131 	return toString( dt );
132 }
133 
134 unittest {
135 	Date dt;
136 	assert( toString( dt ) == "-1" );
137 	auto dt_invalid = Date( toString( dt ) );
138 	assert( !dt_invalid );
139 
140 	dt = Date( "2014-01-08" );
141 	assert( toString( dt ) == "2014-01-08T00:00:00" );
142 
143 	dt = Date( "2014-01-08T08:01:01" );
144 	assert( toString( dt ) == "2014-01-08T08:01:01" );
145 
146 	auto now = datetime.Clock.currTime;
147 	dt = Date.now;
148 	assert( now.year == dt.mytime.year );
149 	assert( now.month == dt.mytime.month );
150 	assert( now.day == dt.mytime.day );
151 }
152 
153