1 /*
2 	Copyright (C) 2010 DeSmuME team
3 
4 	This file is based on System.DateTime.cs and System.TimeSpan.cs from mono-2.6.7
5 
6 	This file is free software: you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation, either version 2 of the License, or
9 	(at your option) any later version.
10 
11 	This file is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	You should have received a copy of the GNU General Public License
17 	along with the this software.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 //
21 // System.DateTime.cs
22 //
23 // author:
24 //   Marcel Narings (marcel@narings.nl)
25 //   Martin Baulig (martin@gnome.org)
26 //   Atsushi Enomoto (atsushi@ximian.com)
27 //
28 //   (C) 2001 Marcel Narings
29 // Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
30 //
31 // Permission is hereby granted, free of charge, to any person obtaining
32 // a copy of this software and associated documentation files (the
33 // "Software"), to deal in the Software without restriction, including
34 // without limitation the rights to use, copy, modify, merge, publish,
35 // distribute, sublicense, and/or sell copies of the Software, and to
36 // permit persons to whom the Software is furnished to do so, subject to
37 // the following conditions:
38 //
39 // The above copyright notice and this permission notice shall be
40 // included in all copies or substantial portions of the Software.
41 //
42 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
45 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
46 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
47 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
48 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
49 
50 //
51 // System.TimeSpan.cs
52 //
53 // Authors:
54 //   Duco Fijma (duco@lorentz.xs4all.nl)
55 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
56 //   Sebastien Pouliot  <sebastien@ximian.com>
57 //
58 // (C) 2001 Duco Fijma
59 // (C) 2004 Andreas Nahr
60 // Copyright (C) 2004 Novell (http://www.novell.com)
61 //
62 // Permission is hereby granted, free of charge, to any person obtaining
63 // a copy of this software and associated documentation files (the
64 // "Software"), to deal in the Software without restriction, including
65 // without limitation the rights to use, copy, modify, merge, publish,
66 // distribute, sublicense, and/or sell copies of the Software, and to
67 // permit persons to whom the Software is furnished to do so, subject to
68 // the following conditions:
69 //
70 // The above copyright notice and this permission notice shall be
71 // included in all copies or substantial portions of the Software.
72 //
73 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
74 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
75 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
76 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
77 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
78 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
79 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
80 //
81 
82 #ifndef _DATETIME_H_
83 #define _DATETIME_H_
84 
85 #include <math.h>
86 #include <time.h>
87 #include <string.h>
88 #include <stdio.h>
89 
90 #include <string>
91 
92 #include "../types.h"
93 
94 enum DayOfWeek {
95 	DayOfWeek_Sunday=0,
96 	DayOfWeek_Monday=1,
97 	DayOfWeek_Tuesday=2,
98 	DayOfWeek_Wednesday=3,
99 	DayOfWeek_Thursday=4,
100 	DayOfWeek_Friday=5,
101 	DayOfWeek_Saturday=6
102 };
103 
104 class TimeSpan
105 {
106 	friend class DateTime;
107 
108 public:
get_MaxValue()109 	static const TimeSpan& get_MaxValue()
110 	{
111 		static TimeSpan val(0x7FFFFFFFFFFFFFFFLL);
112 		return val;
113 	}
114 
get_MinValue()115 	static const TimeSpan& get_MinValue()
116 	{
117 		static TimeSpan val(0x8000000000000000LL);
118 		return val;
119 	}
120 
get_Zero()121 	static const TimeSpan& get_Zero()
122 	{
123 		static TimeSpan val(0);
124 		return val;
125 	}
126 
127 	static const s64 TicksPerDay = 864000000000LL;
128 	static const s64 TicksPerHour = 36000000000LL;
129 	static const s64 TicksPerMillisecond = 10000LL;
130 	static const s64 TicksPerMinute = 600000000LL;
131 	static const s64 TicksPerSecond = 10000000LL;
132 
TimeSpan()133 	TimeSpan ()
134 	{
135 	}
136 
TimeSpan(s64 ticks)137 	TimeSpan (s64 ticks)
138 		: _ticks(ticks)
139 	{
140 	}
141 
TimeSpan(int hours,int minutes,int seconds)142 	TimeSpan (int hours, int minutes, int seconds)
143 	{
144 		_ticks = CalculateTicks (0, hours, minutes, seconds, 0);
145 	}
146 
TimeSpan(int days,int hours,int minutes,int seconds)147 	TimeSpan (int days, int hours, int minutes, int seconds)
148 	{
149 		_ticks = CalculateTicks (days, hours, minutes, seconds, 0);
150 	}
151 
TimeSpan(int days,int hours,int minutes,int seconds,int milliseconds)152 	TimeSpan (int days, int hours, int minutes, int seconds, int milliseconds)
153 	{
154 		_ticks = CalculateTicks (days, hours, minutes, seconds, milliseconds);
155 	}
156 
get_Days()157 	int get_Days() const { return (int) (_ticks / TicksPerDay); }
get_Hours()158 	int get_Hours() const { return (int) (_ticks % TicksPerDay / TicksPerHour); }
get_Milliseconds()159 	int get_Milliseconds() const { return (int) (_ticks % TicksPerSecond / TicksPerMillisecond); }
get_Minutes()160 	int get_Minutes() const { return (int) (_ticks % TicksPerHour / TicksPerMinute); }
get_Seconds()161 	int get_Seconds() const { return (int) (_ticks % TicksPerMinute / TicksPerSecond); }
get_Ticks()162 	s64 get_Ticks() const { return _ticks; }
get_TotalDays()163 	double get_TotalDays() const { return (double) _ticks / TicksPerDay; }
get_TotalHours()164 	double get_TotalHours() const { return (double) _ticks / TicksPerHour; }
get_TotalMilliseconds()165 	double get_TotalMilliseconds() const { return (double) _ticks  / TicksPerMillisecond; }
get_TotalMinutes()166 	double get_TotalMinutes() const { return (double) _ticks / TicksPerMinute; }
get_TotalSeconds()167 	double get_TotalSeconds() const { return (double) _ticks / TicksPerSecond; }
168 
Add(const TimeSpan & ts)169 	TimeSpan Add (const TimeSpan &ts)
170 	{
171 		return TimeSpan (_ticks + ts._ticks);
172 		//removed:
173 		//catch (OverflowException) throw new OverflowException (Locale.GetText ("Resulting timespan is too big."));
174 	}
175 
Compare(const TimeSpan & t1,const TimeSpan & t2)176 	static int Compare (const TimeSpan& t1, const TimeSpan& t2)
177 	{
178 		if (t1._ticks < t2._ticks)
179 			return -1;
180 		if (t1._ticks > t2._ticks)
181 			return 1;
182 		return 0;
183 	}
184 
CompareTo(const TimeSpan & value)185 	int CompareTo (const TimeSpan& value)
186 	{
187 		return Compare (*this, value);
188 	}
189 
Duration()190 	TimeSpan Duration ()
191 	{
192 		return TimeSpan(_ticks<0?-_ticks:_ticks);
193 		//removed:
194 		//catch (OverflowException) throw new OverflowException (Locale.GetText ("This TimeSpan value is MinValue so you cannot get the duration."));
195 	}
196 
197 	//removed per http://sourceforge.net/p/desmume/bugs/1484/ since it was erroneous (well, From() was) and wasn't being used
198 	//static TimeSpan FromDays (double value)
199 	//{
200 	//	return From (value, TicksPerDay);
201 	//}
202 
203 	//static TimeSpan FromHours (double value)
204 	//{
205 	//	return From (value, TicksPerHour);
206 	//}
207 
208 	//static TimeSpan FromMinutes (double value)
209 	//{
210 	//	return From (value, TicksPerMinute);
211 	//}
212 
213 	//static TimeSpan FromSeconds (double value)
214 	//{
215 	//	return From (value, TicksPerSecond);
216 	//}
217 
218 	//static TimeSpan FromMilliseconds (double value)
219 	//{
220 	//	return From (value, TicksPerMillisecond);
221 	//}
222 
FromTicks(s64 value)223 	static TimeSpan FromTicks (s64 value)
224 	{
225 		return TimeSpan (value);
226 	}
227 
Negate()228 	TimeSpan Negate ()
229 	{
230 		//removed error handling
231 		//if (_ticks == MinValue()._ticks) throw new OverflowException (Locale.GetText ( "This TimeSpan value is MinValue and cannot be negated."));
232 		return TimeSpan (-_ticks);
233 	}
234 
Subtract(const TimeSpan & ts)235 	TimeSpan Subtract (const TimeSpan& ts)
236 	{
237 		//removed error handling
238 		//try { checked {
239 		return TimeSpan (_ticks - ts._ticks);
240 		//	}
241 		//}
242 		//catch (OverflowException) {
243 		//	throw new OverflowException (Locale.GetText ("Resulting timespan is too big."));
244 		//}
245 	}
246 
247 	TimeSpan operator + (const TimeSpan& t2) const
248 	{
249 		TimeSpan temp = *this;
250 		temp.Add (t2);
251 		return temp;
252 	}
253 
254 	bool operator == (const TimeSpan& t2) const
255 	{
256 		return _ticks == t2._ticks;
257 	}
258 
259 	bool operator > (const TimeSpan& t2) const
260 	{
261 		return _ticks > t2._ticks;
262 	}
263 
264 	bool operator >= (const TimeSpan& t2) const
265 	{
266 		return _ticks >= t2._ticks;
267 	}
268 
269 	bool operator != (const TimeSpan& t2) const
270 	{
271 		return _ticks != t2._ticks;
272 	}
273 
274 	bool operator < (const TimeSpan& t2) const
275 	{
276 		return _ticks < t2._ticks;
277 	}
278 
279 	bool operator <= (const TimeSpan& t2) const
280 	{
281 		return _ticks <= t2._ticks;
282 	}
283 
284 	TimeSpan operator - (const TimeSpan& t2) const
285 	{
286 		TimeSpan temp = *this;
287 		return temp.Subtract (t2);
288 	}
289 
290 	TimeSpan operator - ()
291 	{
292 		return Negate ();
293 	}
294 
295 
296 private:
297 	s64 _ticks;
298 
CalculateTicks(int days,int hours,int minutes,int seconds,int milliseconds)299 	static s64 CalculateTicks (int days, int hours, int minutes, int seconds, int milliseconds)
300 	{
301 		// there's no overflow checks for hours, minutes, ...
302 		// so big hours/minutes values can overflow at some point and change expected values
303 		int hrssec = (hours * 3600); // break point at (Int32.MaxValue - 596523)
304 		int minsec = (minutes * 60);
305 		s64 t = ((s64)(hrssec + minsec + seconds) * 1000L + (s64)milliseconds);
306 		t *= 10000;
307 
308 		bool overflow = false;
309 		// days is problematic because it can overflow but that overflow can be
310 		// "legal" (i.e. temporary) (e.g. if other parameters are negative) or
311 		// illegal (e.g. sign change).
312 		if (days > 0) {
313 			s64 td = TicksPerDay * days;
314 			if (t < 0) {
315 				s64 ticks = t;
316 				t += td;
317 				// positive days -> total ticks should be lower
318 				overflow = (ticks > t);
319 			}
320 			else {
321 				t += td;
322 				// positive + positive != negative result
323 				overflow = (t < 0);
324 			}
325 		}
326 		else if (days < 0) {
327 			s64 td = TicksPerDay * days;
328 			if (t <= 0) {
329 				t += td;
330 				// negative + negative != positive result
331 				overflow = (t > 0);
332 			}
333 			else {
334 				s64 ticks = t;
335 				t += td;
336 				// negative days -> total ticks should be lower
337 				overflow = (t > ticks);
338 			}
339 		}
340 
341 		//removed:
342 		//if (overflow) throw ArgumentOutOfRangeException ("The timespan is too big or too small.");
343 
344 		return t;
345 	}
346 
347 	//removed per http://sourceforge.net/p/desmume/bugs/1484/ since it was erroneous and wasn't being used
348 	//static TimeSpan From (double value, s64 tickMultiplicator)
349 	//{
350 	//	//a bunch of error handling removed
351 
352 	//	//if (Double.IsNaN (value)) throw new ArgumentException (Locale.GetText ("Value cannot be NaN."), "value");
353 	//	//if (Double.IsNegativeInfinity (value) || Double.IsPositiveInfinity (value) ||
354 	//	//	(value < MinValue.Ticks) || (value > MaxValue.Ticks))
355 	//	//	throw new OverflowException (Locale.GetText ("Outside range [MinValue,MaxValue]"));
356 
357 	//	//try {
358 	//	value = (value * (tickMultiplicator / TicksPerMillisecond));
359 
360 	//	//	checked {
361 	//	//		long val = (long) Math.Round(value);
362 	//	//		return new TimeSpan (val * TicksPerMillisecond);
363 	//	//	}
364 	//	//}
365 	//	//catch (OverflowException) {
366 	//	//	throw new OverflowException (Locale.GetText ("Resulting timespan is too big."));
367 	//	//}
368 	//	//}
369 	//}
370 
371 };
372 
373 class DateTime
374 {
375 private:
376 	TimeSpan ticks;
377 
round(const double x)378 	static inline double round(const double x) { return floor(x + 0.5); }
379 
380 	static const int dp400 = 146097;
381 	static const int dp100 = 36524;
382 	static const int dp4 = 1461;
383 
384 	// w32 file time starts counting from 1/1/1601 00:00 GMT
385 	// which is the constant ticks from the .NET epoch
386 	static const s64 w32file_epoch = 504911232000000000LL;
387 
388 	//private const long MAX_VALUE_TICKS = 3155378975400000000L;
389 	// -- Microsoft .NET has this value.
390 	static const s64 MAX_VALUE_TICKS = 3155378975999999999LL;
391 
392 	//
393 	// The UnixEpoch, it begins on Jan 1, 1970 at 0:0:0, expressed
394 	// in Ticks
395 	//
396 	static const s64 UnixEpoch = 621355968000000000LL;
397 
398 
399 	static const int daysmonth[13];
400 	static const int daysmonthleap[13];
401 	static const char* monthnames[13];
402 
init(int year,int month,int day,int hour,int minute,int second,int millisecond)403 	void init (int year, int month, int day, int hour, int minute, int second, int millisecond)
404 	{
405 		//removed error handling
406 		/*	if ( year < 1 || year > 9999 ||
407 		month < 1 || month >12  ||
408 		day < 1 || day > DaysInMonth(year, month) ||
409 		hour < 0 || hour > 23 ||
410 		minute < 0 || minute > 59 ||
411 		second < 0 || second > 59 ||
412 		millisecond < 0 || millisecond > 999)
413 		throw new ArgumentOutOfRangeException ("Parameters describe an " +
414 		"unrepresentable DateTime.");*/
415 
416 		ticks = TimeSpan (AbsoluteDays(year,month,day), hour, minute, second, millisecond);
417 	}
418 
419 
420 
AbsoluteDays(int year,int month,int day)421 	static int AbsoluteDays (int year, int month, int day)
422 	{
423 		const int* days;
424 		int temp = 0, m=1 ;
425 
426 		days = (IsLeapYear(year) ? daysmonthleap  : daysmonth);
427 
428 		while (m < month)
429 			temp += days[m++];
430 		return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));
431 	}
432 
433 
434 	enum Which
435 	{
436 		Which_Day,
437 		Which_DayYear,
438 		Which_Month,
439 		Which_Year
440 	};
441 
FromTicks(Which what)442 	int FromTicks(Which what) const
443 	{
444 		int num400, num100, num4, numyears;
445 		int M =1;
446 
447 		const int* days = daysmonth;
448 		int totaldays = ticks.get_Days();
449 
450 		num400 = (totaldays / dp400);
451 		totaldays -=  num400 * dp400;
452 
453 		num100 = (totaldays / dp100);
454 		if (num100 == 4)   // leap
455 			num100 = 3;
456 		totaldays -= (num100 * dp100);
457 
458 		num4 = totaldays / dp4;
459 		totaldays -= (num4 * dp4);
460 
461 		numyears = totaldays / 365 ;
462 
463 		if (numyears == 4)  //leap
464 			numyears =3 ;
465 		if (what == Which_Year )
466 			return num400*400 + num100*100 + num4*4 + numyears + 1;
467 
468 		totaldays -= (numyears * 365) ;
469 		if (what == Which_DayYear )
470 			return totaldays + 1;
471 
472 		if  ((numyears==3) && ((num100 == 3) || !(num4 == 24)) ) //31 dec leapyear
473 			days = daysmonthleap;
474 
475 		while (totaldays >= days[M])
476 			totaldays -= days[M++];
477 
478 		if (what == Which_Month )
479 			return M;
480 
481 		return totaldays +1;
482 	}
483 
484 public:
DateTime()485 	DateTime()
486 		: ticks(0)
487 	{
488 	}
489 
GetNameOfMonth(int month)490 	static const char* GetNameOfMonth(int month) { return monthnames[month]; }
491 
DateTime(s64 ticks)492 	DateTime (s64 ticks)
493 	{
494 		this->ticks = TimeSpan (ticks);
495 		//removed error handling
496 		//if (ticks < get_MinValue().get_Ticks() || ticks > get_MaxValue().get_Ticks()) {
497 		//	string msg = Locale.GetText ("Value {0} is outside the valid range [{1},{2}].",
498 		//		ticks, MinValue.Ticks, MaxValue.Ticks);
499 		//	throw new ArgumentOutOfRangeException ("ticks", msg);
500 		//}
501 	}
502 
get_MaxValue()503 	static const DateTime& get_MaxValue() {
504 		static DateTime val(false, TimeSpan (MAX_VALUE_TICKS));
505 		return val;
506 	}
507 
get_MinValue()508 	static const DateTime& get_MinValue() {
509 		static DateTime val(false, TimeSpan (0));
510 		return val;
511 	}
512 
DateTime(int year,int month,int day)513 	DateTime (int year, int month, int day)
514 	{
515 		init(year,month,day,0,0,0,0);
516 	}
517 
DateTime(int year,int month,int day,int hour,int minute,int second)518 	DateTime (int year, int month, int day, int hour, int minute, int second)
519 	{
520 		init(year, month, day, hour, minute, second, 0);
521 	}
522 
DateTime(int year,int month,int day,int hour,int minute,int second,int millisecond)523 	DateTime (int year, int month, int day, int hour, int minute, int second, int millisecond)
524 	{
525 		init(year,month,day,hour,minute,second,millisecond);
526 	}
527 
528 
DateTime(bool check,const TimeSpan & value)529 	DateTime (bool check, const TimeSpan& value)
530 	{
531 		//removed error handling
532 		//if (check && (value.Ticks < MinValue.Ticks || value.Ticks > MaxValue.Ticks))
533 		//	throw new ArgumentOutOfRangeException ();
534 
535 		ticks = value;
536 	}
537 
get_Date()538 	DateTime get_Date () const
539 	{
540 		return DateTime (get_Year(), get_Month(), get_Day());
541 	}
542 
get_Month()543 	int get_Month () const {
544 		return FromTicks(Which_Month);
545 	}
546 
get_Day()547 	int get_Day() const
548 	{
549 		return FromTicks(Which_Day);
550 	}
551 
get_DayOfWeek()552 	DayOfWeek get_DayOfWeek () const
553 	{
554 		return ( (DayOfWeek) ((ticks.get_Days()+1) % 7) );
555 	}
556 
get_DayOfYear()557 	int get_DayOfYear () const
558 	{
559 		return FromTicks(Which_DayYear);
560 	}
561 
get_TimeOfDay()562 	TimeSpan get_TimeOfDay () const
563 	{
564 		return TimeSpan(ticks.get_Ticks() % TimeSpan::TicksPerDay );
565 	}
566 
get_Hour()567 	int get_Hour () const
568 	{
569 		return ticks.get_Hours();
570 	}
571 
get_Minute()572 	int get_Minute () const
573 	{
574 		return ticks.get_Minutes();
575 	}
576 
get_Second()577 	int get_Second () const
578 	{
579 		return ticks.get_Seconds();
580 	}
581 
get_Millisecond()582 	int get_Millisecond () const
583 	{
584 		return ticks.get_Milliseconds();
585 	}
586 
587 	//internal static extern s64 GetTimeMonotonic ();
588 	//internal static extern s64 GetNow ();
589 
get_Now()590 	static DateTime get_Now ()
591 	{
592 		time_t timer;
593 		time(&timer);
594 		struct tm *tm = localtime(&timer);
595 		return DateTime(tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);
596 	}
597 
get_Ticks()598 	s64 get_Ticks()const
599 	{
600 		return ticks.get_Ticks();
601 	}
602 
get_Today()603 	static DateTime get_Today ()
604 	{
605 		DateTime now = get_Now();
606 		DateTime today = DateTime (now.get_Year(), now.get_Month(), now.get_Day());
607 		return today;
608 	}
609 
get_Year()610 	int get_Year () const
611 	{
612 		return FromTicks(Which_Year);
613 	}
614 
Add(const TimeSpan & value)615 	DateTime Add (const TimeSpan& value) const
616 	{
617 		DateTime ret = AddTicks (value.get_Ticks());
618 		return ret;
619 	}
620 
AddDays(double value)621 	DateTime AddDays (double value) const
622 	{
623 		return AddMilliseconds (round(value * 86400000));
624 	}
625 
AddTicks(const s64 value)626 	DateTime AddTicks (const s64 value) const
627 	{
628 		//removed error handling
629 		//if ((value + ticks.Ticks) > MAX_VALUE_TICKS || (value + ticks.Ticks) < 0) {
630 		//	throw new ArgumentOutOfRangeException();
631 		//}
632 		return DateTime (value + ticks.get_Ticks());
633 	}
634 
AddHours(double value)635 	DateTime AddHours (double value) const
636 	{
637 		return AddMilliseconds (value * 3600000);
638 	}
639 
AddMilliseconds(double value)640 	DateTime AddMilliseconds (double value) const
641 	{
642 		//removed error handling
643 		/*		if ((value * TimeSpan.TicksPerMillisecond) > long.MaxValue ||
644 		(value * TimeSpan.TicksPerMillisecond) < long.MinValue) {
645 		throw new ArgumentOutOfRangeException();
646 		}
647 		*/
648 		s64 msticks = (s64) round(value * TimeSpan::TicksPerMillisecond);
649 		return AddTicks (msticks);
650 	}
651 
AddMinutes(double value)652 	DateTime AddMinutes (double value) const
653 	{
654 		return AddMilliseconds (value * 60000);
655 	}
656 
AddMonths(int months)657 	DateTime AddMonths (int months) const
658 	{
659 		int day, month, year,  maxday ;
660 		DateTime temp;
661 
662 		day = get_Day();
663 		month = get_Month() + (months % 12);
664 		year = get_Year() + months/12 ;
665 
666 		if (month < 1)
667 		{
668 			month = 12 + month ;
669 			year -- ;
670 		}
671 		else if (month>12)
672 		{
673 			month = month -12;
674 			year ++;
675 		}
676 		maxday = DaysInMonth(year, month);
677 		if (day > maxday)
678 			day = maxday;
679 
680 		temp = (year, month, day);
681 		return  temp.Add (get_TimeOfDay());
682 	}
683 
AddSeconds(double value)684 	DateTime AddSeconds (double value) const
685 	{
686 		return AddMilliseconds (value * 1000);
687 	}
688 
AddYears(int value)689 	DateTime AddYears (int value) const
690 	{
691 		return AddMonths (value * 12);
692 	}
693 
Compare(const DateTime & t1,const DateTime & t2)694 	static int Compare (const DateTime& t1,	const DateTime& t2)
695 	{
696 		if (t1.ticks < t2.ticks)
697 			return -1;
698 		else if (t1.ticks > t2.ticks)
699 			return 1;
700 		else
701 			return 0;
702 	}
703 
DaysInMonth(int year,int month)704 	static int DaysInMonth (int year, int month)
705 	{
706 		const int* days ;
707 
708 		//removed error handling
709 		//if (month < 1 || month >12)throw new ArgumentOutOfRangeException ();
710 		//if (year < 1 || year > 9999)throw new ArgumentOutOfRangeException ();
711 
712 		days = (IsLeapYear(year) ? daysmonthleap  : daysmonth);
713 		return days[month];
714 	}
IsLeapYear(int year)715 	static bool IsLeapYear (int year)
716 	{
717 		//removed error handling
718 		/*		if (year < 1 || year > 9999)
719 		throw new ArgumentOutOfRangeException ();*/
720 		return  ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
721 	}
722 
Subtract(const DateTime & value)723 	TimeSpan Subtract (const DateTime& value) const
724 	{
725 		return TimeSpan (ticks.get_Ticks()) - value.ticks;
726 	}
727 
Subtract(const TimeSpan & value)728 	DateTime Subtract(const TimeSpan& value) const
729 	{
730 		TimeSpan newticks;
731 
732 		newticks = (TimeSpan (ticks.get_Ticks())) - value;
733 		DateTime ret = DateTime (true,newticks);
734 		return ret;
735 	}
736 
737 	DateTime operator +(const TimeSpan& t) const
738 	{
739 		return DateTime (true, ticks + t);
740 	}
741 
742 	bool operator ==(const DateTime& d2) const
743 	{
744 		return (ticks == d2.ticks);
745 	}
746 
747 	bool operator >(const DateTime& t2) const
748 	{
749 		return (ticks > t2.ticks);
750 	}
751 
752 	bool operator >=(const DateTime &t2) const
753 	{
754 		return (ticks >= t2.ticks);
755 	}
756 
757 	bool operator !=(const DateTime& d2) const
758 	{
759 		return (ticks != d2.ticks);
760 	}
761 
762 	bool operator <(const DateTime& t2) const
763 	{
764 		return (ticks < t2.ticks );
765 	}
766 
767 	bool operator <=(const DateTime& t2) const
768 	{
769 		return (ticks <= t2.ticks);
770 	}
771 
772 	TimeSpan operator -(const DateTime& d2) const
773 	{
774 		return TimeSpan((ticks - d2.ticks).get_Ticks());
775 	}
776 
777 	DateTime operator -(const TimeSpan& t) const
778 	{
779 		return DateTime (true, ticks - t);
780 	}
781 
782 	//try to have a canonical format here. this was comment was typed at 2010-oct-04 02:16:44:000
783 
ToString()784 	std::string ToString() const
785 	{
786 		char tmp[32];
787 		sprintf(tmp,"%04d-%s-%02d %02d:%02d:%02d:%03d",get_Year(),monthnames[get_Month()],get_Day(),get_Hour(),get_Minute(),get_Second(),get_Millisecond());
788 		return tmp;
789 	}
790 
TryParse(const char * str,DateTime & out)791 	static bool TryParse(const char* str, DateTime& out)
792 	{
793 		int year,mon=-1,day,hour,min,sec,ms;
794 		char strmon[4];
795 		int done = sscanf(str,"%04d-%3s-%02d %02d:%02d:%02d:%03d",&year,strmon,&day,&hour,&min,&sec,&ms);
796 		if(done != 7) return false;
797 		for(int i=1;i<12;i++)
798 			if(!strncasecmp(monthnames[i],strmon,3))
799 			{
800 				mon=i;
801 				break;
802 			}
803 		if(mon==-1) return false;
804 		out = DateTime(year,mon,day,hour,min,sec);
805 		return true;
806 	}
807 
Parse(const char * str)808 	static DateTime Parse(const char* str)
809 	{
810 		DateTime ret;
811 		TryParse(str,ret);
812 		return ret;
813 	}
814 
815 };
816 
817 
818 #endif //_DATETIME_H_
819