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