xref: /haiku/src/kits/support/DateTime.cpp (revision e0ef64750f3169cd634bb2f7a001e22488b05231)
1 /*
2  * Copyright 2007-2010, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Julun <host.haiku@gmx.de>
7  *		Stephan Aßmus <superstippi@gmx.de>
8  */
9 
10 #include "DateTime.h"
11 
12 
13 #include <time.h>
14 #include <sys/time.h>
15 
16 #include <Message.h>
17 
18 
19 namespace BPrivate {
20 
21 
22 const int32			kSecondsPerMinute			= 60;
23 
24 const int32			kHoursPerDay				= 24;
25 const int32			kMinutesPerDay				= 1440;
26 const int32			kSecondsPerDay				= 86400;
27 const int32			kMillisecondsPerDay			= 86400000;
28 
29 const bigtime_t		kMicrosecondsPerSecond		= 1000000LL;
30 const bigtime_t		kMicrosecondsPerMinute		= 60000000LL;
31 const bigtime_t		kMicrosecondsPerHour		= 3600000000LL;
32 const bigtime_t		kMicrosecondsPerDay			= 86400000000LL;
33 
34 
35 /*!
36 	Constructs a new BTime object. Asked for its time representation, it will
37 	return 0 for Hour(), Minute(), Second() etc. This can represent midnight,
38 	but be aware IsValid() will return false.
39 */
40 BTime::BTime()
41 	:
42 	fMicroseconds(-1)
43 {
44 }
45 
46 
47 /*!
48 	Constructs a new BTime object as a copy of \c other.
49 */
50 BTime::BTime(const BTime& other)
51 	:
52 	fMicroseconds(other.fMicroseconds)
53 {
54 }
55 
56 
57 /*!
58 	Constructs a BTime object with \c hour \c minute, \c second, \c microsecond.
59 
60 	\c hour must be between 0 and 23, \c minute and \c second must be between
61 	0 and 59 and \c microsecond should be in the range of 0 and 999999. If the
62 	specified time is invalid, the time is not set and IsValid() returns false.
63 */
64 BTime::BTime(int32 hour, int32 minute, int32 second, int32 microsecond)
65 	:
66 	fMicroseconds(-1)
67 {
68 	_SetTime(hour, minute, second, microsecond);
69 }
70 
71 
72 /*!
73 	Constructs a new BTime object from the provided BMessage archive.
74 */
75 BTime::BTime(const BMessage* archive)
76 	:
77 	fMicroseconds(-1)
78 {
79 	if (archive == NULL)
80 		return;
81 	archive->FindInt64("mircoseconds", &fMicroseconds);
82 }
83 
84 
85 /*!
86 	Empty destructor.
87 */
88 BTime::~BTime()
89 {
90 }
91 
92 
93 /*!
94 	Archives the BTime object into the provided BMessage object.
95 	@returns	\c B_OK if all went well.
96 				\c B_BAD_VALUE, if the message is \c NULL.
97 				\c other error codes, depending on failure to append
98 				fields to the message.
99 */
100 status_t
101 BTime::Archive(BMessage* into) const
102 {
103 	if (into == NULL)
104 		return B_BAD_VALUE;
105 	return into->AddInt64("mircoseconds", fMicroseconds);
106 }
107 
108 
109 /*!
110 	Returns true if the time is valid, otherwise false. A valid time can be
111 	BTime(23, 59, 59, 999999) while BTime(24, 00, 01) would be invalid.
112 */
113 bool
114 BTime::IsValid() const
115 {
116 	return fMicroseconds > -1 && fMicroseconds < kMicrosecondsPerDay;
117 }
118 
119 
120 /*!
121 	This is an overloaded member function, provided for convenience.
122 */
123 bool
124 BTime::IsValid(const BTime& time) const
125 {
126 	return time.fMicroseconds > -1 && time.fMicroseconds < kMicrosecondsPerDay;
127 }
128 
129 
130 /*!
131 	This is an overloaded member function, provided for convenience.
132 */
133 bool
134 BTime::IsValid(int32 hour, int32 minute, int32 second, int32 microsecond) const
135 {
136 	return BTime(hour, minute, second, microsecond).IsValid();
137 }
138 
139 
140 /*!
141 	Returns the current time as reported by the system depending on the given
142 	time_type \c type.
143 */
144 BTime
145 BTime::CurrentTime(time_type type)
146 {
147 	struct timeval tv;
148 	if (gettimeofday(&tv, NULL) != 0) {
149 		// gettimeofday failed?
150 		time(&tv.tv_sec);
151 	}
152 
153 	struct tm result;
154 	struct tm* timeinfo;
155 	if (type == B_GMT_TIME)
156 		timeinfo = gmtime_r(&tv.tv_sec, &result);
157 	else
158 		timeinfo = localtime_r(&tv.tv_sec, &result);
159 
160 	if (timeinfo == NULL)
161 		return BTime();
162 
163 	int32 sec = timeinfo->tm_sec;
164 	return BTime(timeinfo->tm_hour, timeinfo->tm_min, (sec > 59) ? 59 : sec,
165 		tv.tv_usec);
166 }
167 
168 
169 /*!
170 	Returns a copy of the current BTime object.
171 */
172 BTime
173 BTime::Time() const
174 {
175 	return *this;
176 }
177 
178 
179 /*!
180 	This is an overloaded member function, provided for convenience. Set the
181 	current BTime object to the passed BTime \c time object.
182 */
183 bool
184 BTime::SetTime(const BTime& time)
185 {
186 	fMicroseconds = time.fMicroseconds;
187 	return IsValid();
188 }
189 
190 
191 /*!
192 	Set the time to \c hour \c minute, \c second and \c microsecond.
193 
194 	\c hour must be between 0 and 23, \c minute and \c second must be between
195 	0 and 59 and \c microsecond should be in the range of 0 and 999999. Returns
196 	true if the time is valid; otherwise false. If the specified time is
197 	invalid, the time is not set and the function returns false.
198 */
199 bool
200 BTime::SetTime(int32 hour, int32 minute, int32 second, int32 microsecond)
201 {
202 	return _SetTime(hour, minute, second, microsecond);
203 }
204 
205 
206 
207 /*!
208 	Adds \c hours to the current time. If the passed value is negativ it will
209 	become earlier. Note: The time will wrap if it passes midnight.
210 */
211 BTime&
212 BTime::AddHours(int32 hours)
213 {
214 	return _AddMicroseconds(bigtime_t(hours % kHoursPerDay)
215 		* kMicrosecondsPerHour);
216 }
217 
218 
219 /*!
220 	Adds \c minutes to the current time. If the passed value is negativ it will
221 	become earlier. Note: The time will wrap if it passes midnight.
222 */
223 BTime&
224 BTime::AddMinutes(int32 minutes)
225 {
226 	return _AddMicroseconds(bigtime_t(minutes % kMinutesPerDay)
227 		* kMicrosecondsPerMinute);
228 }
229 
230 
231 /*!
232 	Adds \c seconds to the current time. If the passed value is negativ it will
233 	become earlier. Note: The time will wrap if it passes midnight.
234 */
235 BTime&
236 BTime::AddSeconds(int32 seconds)
237 {
238 	return _AddMicroseconds(bigtime_t(seconds % kSecondsPerDay)
239 		* kMicrosecondsPerSecond);
240 }
241 
242 
243 /*!
244 	Adds \c milliseconds to the current time. If the passed value is negativ it
245 	will become earlier. Note: The time will wrap if it passes midnight.
246 */
247 BTime&
248 BTime::AddMilliseconds(int32 milliseconds)
249 {
250 	return _AddMicroseconds(bigtime_t(milliseconds % kMillisecondsPerDay)
251 		* 1000);
252 }
253 
254 
255 /*!
256 	Adds \c microseconds to the current time. If the passed value is negativ it
257 	will become earlier. Note: The time will wrap if it passes midnight.
258 */
259 BTime&
260 BTime::AddMicroseconds(int32 microseconds)
261 {
262 	return _AddMicroseconds(microseconds);
263 }
264 
265 
266 /*!
267 	Returns the hour fragment of the time.
268 */
269 int32
270 BTime::Hour() const
271 {
272 	return int32(_Microseconds() / kMicrosecondsPerHour);
273 }
274 
275 
276 /*!
277 	Returns the minute fragment of the time.
278 */
279 int32
280 BTime::Minute() const
281 {
282 	return int32(((_Microseconds() % kMicrosecondsPerHour)) / kMicrosecondsPerMinute);
283 }
284 
285 
286 /*!
287 	Returns the second fragment of the time.
288 */
289 int32
290 BTime::Second() const
291 {
292 	return int32(_Microseconds() / kMicrosecondsPerSecond) % kSecondsPerMinute;
293 }
294 
295 
296 /*!
297 	Returns the millisecond fragment of the time.
298 */
299 int32
300 BTime::Millisecond() const
301 {
302 
303 	return Microsecond() / 1000;
304 }
305 
306 
307 /*!
308 	Returns the microsecond fragment of the time.
309 */
310 int32
311 BTime::Microsecond() const
312 {
313 	return int32(_Microseconds() % 1000000);
314 }
315 
316 
317 bigtime_t
318 BTime::_Microseconds() const
319 {
320 	return fMicroseconds == -1 ? 0 : fMicroseconds;
321 }
322 
323 
324 /*!
325 	Returns the difference between this time and the given BTime \c time based
326 	on the passed diff_type \c type. If \c time is earlier the return value will
327 	be negativ.
328 
329 	The return value then can be hours, minutes, seconds, milliseconds or
330 	microseconds while its range will always be between -86400000000 and
331 	86400000000 depending on diff_type \c type.
332 */
333 bigtime_t
334 BTime::Difference(const BTime& time, diff_type type) const
335 {
336 	bigtime_t diff = time._Microseconds() - _Microseconds();
337 	switch (type) {
338 		case B_HOURS_DIFF: {
339 			diff /= kMicrosecondsPerHour;
340 		}	break;
341 		case B_MINUTES_DIFF: {
342 			diff /= kMicrosecondsPerMinute;
343 		}	break;
344 		case B_SECONDS_DIFF: {
345 			diff /= kMicrosecondsPerSecond;
346 		}	break;
347 		case B_MILLISECONDS_DIFF: {
348 			diff /= 1000;
349 		}	break;
350 		case B_MICROSECONDS_DIFF:
351 		default:	break;
352 	}
353 	return diff;
354 }
355 
356 
357 /*!
358 	Returns true if this time is different from \c time, otherwise false.
359 */
360 bool
361 BTime::operator!=(const BTime& time) const
362 {
363 	return fMicroseconds != time.fMicroseconds;
364 }
365 
366 
367 /*!
368 	Returns true if this time is equal to \c time, otherwise false.
369 */
370 bool
371 BTime::operator==(const BTime& time) const
372 {
373 	return fMicroseconds == time.fMicroseconds;
374 }
375 
376 
377 /*!
378 	Returns true if this time is earlier than \c time, otherwise false.
379 */
380 bool
381 BTime::operator<(const BTime& time) const
382 {
383 	return fMicroseconds < time.fMicroseconds;
384 }
385 
386 
387 /*!
388 	Returns true if this time is earlier than or equal to \c time, otherwise false.
389 */
390 bool
391 BTime::operator<=(const BTime& time) const
392 {
393 	return fMicroseconds <= time.fMicroseconds;
394 }
395 
396 
397 /*!
398 	Returns true if this time is later than \c time, otherwise false.
399 */
400 bool
401 BTime::operator>(const BTime& time) const
402 {
403 	return fMicroseconds > time.fMicroseconds;
404 }
405 
406 
407 /*!
408 	Returns true if this time is later than or equal to \c time, otherwise false.
409 */
410 bool
411 BTime::operator>=(const BTime& time) const
412 {
413 	return fMicroseconds >= time.fMicroseconds;
414 }
415 
416 
417 BTime&
418 BTime::_AddMicroseconds(bigtime_t microseconds)
419 {
420 	bigtime_t count = 0;
421 	if (microseconds < 0) {
422 		count = ((kMicrosecondsPerDay - microseconds) / kMicrosecondsPerDay) *
423 			kMicrosecondsPerDay;
424 	}
425 	fMicroseconds = (_Microseconds() + microseconds + count) % kMicrosecondsPerDay;
426 	return *this;
427 }
428 
429 
430 bool
431 BTime::_SetTime(bigtime_t hour, bigtime_t minute, bigtime_t second,
432 	bigtime_t microsecond)
433 {
434 	fMicroseconds = hour * kMicrosecondsPerHour +
435 					minute * kMicrosecondsPerMinute +
436 					second * kMicrosecondsPerSecond +
437 					microsecond;
438 
439 	bool isValid = IsValid();
440 	if (!isValid)
441 		fMicroseconds = -1;
442 
443 	return isValid;
444 }
445 
446 
447 //	#pragma mark - BDate
448 
449 
450 /*!
451 	Constructs a new BDate object. IsValid() will return false.
452 */
453 BDate::BDate()
454 	:
455 	fDay(-1),
456 	fYear(0),
457 	fMonth(-1)
458 {
459 }
460 
461 
462 /*!
463 	Constructs a new BDate object as a copy of \c other.
464 */
465 BDate::BDate(const BDate& other)
466 	:
467 	fDay(other.fDay),
468 	fYear(other.fYear),
469 	fMonth(other.fMonth)
470 {
471 }
472 
473 
474 /*!
475 	Constructs a BDate object with \c year \c month and \c day.
476 
477 	Please note that a date before 1.1.4713 BC, a date with year 0 and a date
478 	between 4.10.1582 and 15.10.1582 are considered invalid. If the specified
479 	date is invalid, the date is not set and IsValid() returns false. Also note
480 	that every passed year will be interpreted as is.
481 
482 */
483 BDate::BDate(int32 year, int32 month, int32 day)
484 {
485 	_SetDate(year, month, day);
486 }
487 
488 
489 /*!
490 	Constructs a new BDate object from the provided archive.
491 */
492 BDate::BDate(const BMessage* archive)
493 	:
494 	fDay(-1),
495 	fYear(0),
496 	fMonth(-1)
497 {
498 	if (archive == NULL)
499 		return;
500 	archive->FindInt32("day", &fDay);
501 	archive->FindInt32("year", &fYear);
502 	archive->FindInt32("month", &fMonth);
503 }
504 
505 
506 /*!
507 	Empty destructor.
508 */
509 BDate::~BDate()
510 {
511 }
512 
513 
514 /*!
515 	Archives the BDate object into the provided BMessage object.
516 	@returns	\c B_OK if all went well.
517 				\c B_BAD_VALUE, if the message is \c NULL.
518 				\c other error codes, depending on failure to append
519 				fields to the message.
520 */
521 status_t
522 BDate::Archive(BMessage* into) const
523 {
524 	if (into == NULL)
525 		return B_BAD_VALUE;
526 	status_t ret = into->AddInt32("day", fDay);
527 	if (ret == B_OK)
528 		ret = into->AddInt32("year", fYear);
529 	if (ret == B_OK)
530 		ret = into->AddInt32("month", fMonth);
531 	return ret;
532 }
533 
534 
535 /*!
536 	Returns true if the date is valid, otherwise false.
537 
538 	Please note that a date before 1.1.4713 BC, a date with year 0 and a date
539 	between 4.10.1582 and 15.10.1582 are considered invalid.
540 */
541 bool
542 BDate::IsValid() const
543 {
544 	return IsValid(fYear, fMonth, fDay);
545 }
546 
547 
548 /*!
549 	This is an overloaded member function, provided for convenience.
550 */
551 bool
552 BDate::IsValid(const BDate& date) const
553 {
554 	return IsValid(date.fYear, date.fMonth, date.fDay);
555 }
556 
557 
558 /*!
559 	This is an overloaded member function, provided for convenience.
560 */
561 bool
562 BDate::IsValid(int32 year, int32 month, int32 day) const
563 {
564 	// no year 0 in Julian and nothing before 1.1.4713 BC
565 	if (year == 0 || year < -4713)
566 		return false;
567 
568 	if (month < 1 || month > 12)
569 		return false;
570 
571 	if (day < 1 || day > _DaysInMonth(year, month))
572 		return false;
573 
574 	// 'missing' days between switch julian - gregorian
575 	if (year == 1582 && month == 10 && day > 4 && day < 15)
576 		return false;
577 
578 	return true;
579 }
580 
581 
582 /*!
583 	Returns the current date as reported by the system depending on the given
584 	time_type \c type.
585 */
586 BDate
587 BDate::CurrentDate(time_type type)
588 {
589 	time_t timer;
590 	struct tm result;
591 	struct tm* timeinfo;
592 
593 	time(&timer);
594 
595 	if (type == B_GMT_TIME)
596 		timeinfo = gmtime_r(&timer, &result);
597 	else
598 		timeinfo = localtime_r(&timer, &result);
599 
600 	if (timeinfo == NULL)
601 		return BDate();
602 
603 	return BDate(timeinfo->tm_year + 1900, timeinfo->tm_mon +1, timeinfo->tm_mday);
604 }
605 
606 
607 /*!
608 	Returns a copy of the current BTime object.
609 */
610 BDate
611 BDate::Date() const
612 {
613 	return *this;
614 }
615 
616 
617 /*!
618 	This is an overloaded member function, provided for convenience.
619 */
620 bool
621 BDate::SetDate(const BDate& date)
622 {
623 	return _SetDate(date.fYear, date.fMonth, date.fDay);
624 }
625 
626 
627 /*!
628 	Set the date to \c year \c month and \c day.
629 
630 	Returns true if the date is valid; otherwise false. If the specified date is
631 	invalid, the date is not set and the function returns false.
632 */
633 bool
634 BDate::SetDate(int32 year, int32 month, int32 day)
635 {
636 	return _SetDate(year, month, day);
637 }
638 
639 
640 /*!
641 	This function sets the given \c year, \c month and \c day to the
642 	representative values of this date. The pointers can be NULL. If the date is
643 	invalid, the values will be set to -1 for \c month and \c day, the \c year
644 	will be set to 0.
645 */
646 void
647 BDate::GetDate(int32* year, int32* month, int32* day)
648 {
649 	if (year)
650 		*year = fYear;
651 
652 	if (month)
653 		*month = fMonth;
654 
655 	if (day)
656 		*day = fDay;
657 }
658 
659 
660 /*!
661 	Adds \c days to the current date. If the passed value is negativ it will
662 	become earlier. If the current date is invalid, the \c days are not added.
663 */
664 void
665 BDate::AddDays(int32 days)
666 {
667 	if (IsValid())
668 		*this = JulianDayToDate(DateToJulianDay() + days);
669 }
670 
671 
672 /*!
673 	Adds \c years to the current date. If the passed value is negativ it will
674 	become earlier. If the current date is invalid, the \c years are not added.
675 	The day/ month combination will be adjusted if it does not exist in the
676 	resulting year, so this function will then return the latest valid date.
677 */
678 void
679 BDate::AddYears(int32 years)
680 {
681 	if (IsValid()) {
682 		const int32 tmp = fYear;
683 		fYear += years;
684 
685 		if ((tmp > 0 && fYear <= 0) || (tmp < 0 && fYear >= 0))
686 			fYear += (years > 0) ? +1 : -1;
687 
688 		fDay = min_c(fDay, _DaysInMonth(fYear, fMonth));
689 	}
690 }
691 
692 
693 /*!
694 	Adds \c months to the current date. If the passed value is negativ it will
695 	become earlier. If the current date is invalid, the \c months are not added.
696 	The day/ month combination will be adjusted if it does not exist in the
697 	resulting year, so this function will then return the latest valid date.
698 */
699 void
700 BDate::AddMonths(int32 months)
701 {
702 	if (IsValid()) {
703 		const int32 tmp = fYear;
704 		fYear += months / 12;
705 		fMonth +=  months % 12;
706 
707 		if (fMonth > 12) {
708 			fYear++;
709 			fMonth -= 12;
710 		} else if (fMonth < 1) {
711 			fYear--;
712 			fMonth += 12;
713 		}
714 
715 		if ((tmp > 0 && fYear <= 0) || (tmp < 0 && fYear >= 0))
716 			fYear += (months > 0) ? +1 : -1;
717 
718 		// 'missing' days between switch julian - gregorian
719 		if (fYear == 1582 && fMonth == 10 && fDay > 4 && fDay < 15)
720 			fDay = (months > 0) ? 15 : 4;
721 
722 		fDay = min_c(fDay, DaysInMonth());
723 	}
724 }
725 
726 
727 /*!
728 	Returns the day fragment of the date. The return value will be in the range
729 	of 1 to 31, in case the date is invalid it will be -1.
730 */
731 int32
732 BDate::Day() const
733 {
734 	return fDay;
735 }
736 
737 
738 /*!
739 	Returns the year fragment of the date. If the date is invalid, the function
740 	returns 0.
741 */
742 int32
743 BDate::Year() const
744 {
745 	return fYear;
746 }
747 
748 
749 /*!
750 	Returns the month fragment of the date. The return value will be in the
751 	range of 1 to 12, in case the date is invalid it will be -1.
752 */
753 int32
754 BDate::Month() const
755 {
756 	return fMonth;
757 }
758 
759 
760 /*!
761 	Returns the difference in days between this date and the given BDate \c date.
762 	If \c date is earlier the return value will be negativ. If the calculation
763 	is done with an invalid date, the result is undefined.
764 */
765 int32
766 BDate::Difference(const BDate& date) const
767 {
768 	return date.DateToJulianDay() - DateToJulianDay();
769 }
770 
771 
772 /*!
773 	Returns the week number of the date, if the date is invalid it will return
774 	B_ERROR. Please note that this function does only work within the Gregorian
775 	calendar, thus a date before 15.10.1582 will return B_ERROR.
776 */
777 int32
778 BDate::WeekNumber() const
779 {
780 	/*
781 		This algorithm is taken from:
782 		Frequently Asked Questions about Calendars
783 		Version 2.8 Claus Tøndering 15 December 2005
784 
785 		Note: it will work only within the Gregorian Calendar
786 	*/
787 
788 	if (!IsValid() || fYear < 1582
789 		|| (fYear == 1582 && fMonth < 10)
790 		|| (fYear == 1582 && fMonth == 10 && fDay < 15))
791 		return int32(B_ERROR);
792 
793 	int32 a;
794 	int32 b;
795 	int32 s;
796 	int32 e;
797 	int32 f;
798 
799 	if (fMonth > 0 && fMonth < 3) {
800 		a = fYear - 1;
801 		b = (a / 4) - (a / 100) + (a / 400);
802 		int32 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a -1) / 400);
803 		s = b - c;
804 		e = 0;
805 		f = fDay - 1 + 31 * (fMonth - 1);
806 	} else if (fMonth >= 3 && fMonth <= 12) {
807 		a = fYear;
808 		b = (a / 4) - (a / 100) + (a / 400);
809 		int32 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a -1) / 400);
810 		s = b - c;
811 		e = s + 1;
812 		f = fDay + ((153 * (fMonth - 3) + 2) / 5) + 58 + s;
813 	} else
814 		return int32(B_ERROR);
815 
816 	int32 g = (a + b) % 7;
817 	int32 d = (f + g - e) % 7;
818 	int32 n = f + 3 - d;
819 
820 	int32 weekNumber;
821 	if (n < 0)
822 		weekNumber = 53 - (g -s) / 5;
823 	else if (n > 364 + s)
824 		weekNumber = 1;
825 	else
826 		weekNumber = n / 7 + 1;
827 
828 	return weekNumber;
829 }
830 
831 
832 /*!
833 	Returns the day of the week in the range of 1 to 7, while 1 stands for
834 	monday. If the date is invalid, the function will return B_ERROR.
835 */
836 int32
837 BDate::DayOfWeek() const
838 {
839 	// http://en.wikipedia.org/wiki/Julian_day#Calculation
840 	return IsValid() ? (DateToJulianDay() % 7) + 1 : int32(B_ERROR);
841 }
842 
843 
844 /*!
845 	Returns the day of the year in the range of 1 to 365 (366 in leap years). If
846 	the date is invalid, the function will return B_ERROR.
847 */
848 int32
849 BDate::DayOfYear() const
850 {
851 	if (!IsValid())
852 		return int32(B_ERROR);
853 
854 	return DateToJulianDay() - _DateToJulianDay(fYear, 1, 1) + 1;
855 }
856 
857 
858 /*!
859 	Returns true if the passed \c year is a leap year, otherwise false. If the
860 	\c year passed is before 4713 BC, the result is undefined.
861 */
862 bool
863 BDate::IsLeapYear(int32 year) const
864 {
865 	if (year < 1582) {
866 		if (year < 0)
867 			year++;
868 		return (year % 4) == 0;
869 	}
870 	return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
871 }
872 
873 
874 /*!
875 	Returns the number of days in the year of the current date. If the date is
876 	valid it will return 365 or 366, otherwise B_ERROR;
877 */
878 int32
879 BDate::DaysInYear() const
880 {
881 	if (!IsValid())
882 		return int32(B_ERROR);
883 
884 	return IsLeapYear(fYear) ? 366 : 365;
885 }
886 
887 
888 /*!
889 	Returns the number of days in the month of the current date. If the date is
890 	valid it will return 28 up to 31, otherwise B_ERROR;
891 */
892 int32
893 BDate::DaysInMonth() const
894 {
895 	if (!IsValid())
896 		return int32(B_ERROR);
897 
898 	return _DaysInMonth(fYear, fMonth);
899 }
900 
901 
902 /*!
903 	Returns the short day name of this object.
904 */
905 BString
906 BDate::ShortDayName() const
907 {
908 	return ShortDayName(DayOfWeek());
909 }
910 
911 
912 /*!
913 	Returns the short day name in case of an valid day, otherwise an empty
914 	string. The passed \c day must be in the range of 1 to 7 while 1 stands for
915 	monday.
916 */
917 /*static*/ BString
918 BDate::ShortDayName(int32 day)
919 {
920 	if (day < 1 || day > 7)
921 		return BString();
922 
923 	tm tm_struct;
924 	memset(&tm_struct, 0, sizeof(tm));
925 	tm_struct.tm_wday = day == 7 ? 0 : day;
926 
927 	char buffer[256];
928 	strftime(buffer, sizeof(buffer), "%a", &tm_struct);
929 
930 	return BString(buffer);
931 }
932 
933 
934 /*!
935 	Returns the short month name of this object.
936 */
937 BString
938 BDate::ShortMonthName() const
939 {
940 	return ShortMonthName(Month());
941 }
942 
943 
944 /*!
945 	Returns the short month name in case of an valid month, otherwise an empty
946 	string. The passed \c month must be in the range of 1 to 12.
947 */
948 /*static*/ BString
949 BDate::ShortMonthName(int32 month)
950 {
951 	if (month < 1 || month > 12)
952 		return BString();
953 
954 	tm tm_struct;
955 	memset(&tm_struct, 0, sizeof(tm));
956 	tm_struct.tm_mon = month - 1;
957 
958 	char buffer[256];
959 	strftime(buffer, sizeof(buffer), "%b", &tm_struct);
960 
961 	return BString(buffer);
962 }
963 
964 
965 /*!
966 	Returns the long day name of this object's week day.
967 */
968 BString
969 BDate::LongDayName() const
970 {
971 	return LongDayName(DayOfWeek());
972 }
973 
974 
975 /*!
976 	Returns the long day name in case of an valid day, otherwise an empty
977 	string. The passed \c day must be in the range of 1 to 7 while 1 stands for
978 	monday.
979 */
980 /*static*/ BString
981 BDate::LongDayName(int32 day)
982 {
983 	if (day < 1 || day > 7)
984 		return BString();
985 
986 	tm tm_struct;
987 	memset(&tm_struct, 0, sizeof(tm));
988 	tm_struct.tm_wday = day == 7 ? 0 : day;
989 
990 	char buffer[256];
991 	strftime(buffer, sizeof(buffer), "%A", &tm_struct);
992 
993 	return BString(buffer);
994 }
995 
996 
997 /*!
998 	Returns the long month name of this object's month.
999 */
1000 BString
1001 BDate::LongMonthName() const
1002 {
1003 	return LongMonthName(Month());
1004 }
1005 
1006 
1007 /*!
1008 	Returns the long month name in case of an valid month, otherwise an empty
1009 	string. The passed \c month must be in the range of 1 to 12.
1010 */
1011 /*static*/ BString
1012 BDate::LongMonthName(int32 month)
1013 {
1014 	if (month < 1 || month > 12)
1015 		return BString();
1016 
1017 	tm tm_struct;
1018 	memset(&tm_struct, 0, sizeof(tm));
1019 	tm_struct.tm_mon = month - 1;
1020 
1021 	char buffer[256];
1022 	strftime(buffer, sizeof(buffer), "%B", &tm_struct);
1023 
1024 	return BString(buffer);
1025 }
1026 
1027 
1028 /*!
1029 	Converts the date to Julian day. If your date is invalid, the function will
1030 	return B_ERROR.
1031 */
1032 int32
1033 BDate::DateToJulianDay() const
1034 {
1035 	return _DateToJulianDay(fYear, fMonth, fDay);
1036 }
1037 
1038 
1039 /*
1040 	Converts the passed \c julianDay to an BDate. If the \c julianDay is negativ,
1041 	the function will return an invalid date. Because of the switch from Julian
1042 	calendar to Gregorian calendar the 4.10.1582 is followed by the 15.10.1582.
1043 */
1044 BDate
1045 BDate::JulianDayToDate(int32 julianDay)
1046 {
1047 	BDate date;
1048 	const int32 kGregorianCalendarStart = 2299161;
1049 	if (julianDay >= kGregorianCalendarStart) {
1050 		// http://en.wikipedia.org/wiki/Julian_day#Gregorian_calendar_from_Julian_day_number
1051 		int32 j = julianDay + 32044;
1052 		int32 dg = j % 146097;
1053 		int32 c = (dg / 36524 + 1) * 3 / 4;
1054 		int32 dc = dg - c * 36524;
1055 		int32 db = dc % 1461;
1056 		int32 a = (db / 365 + 1) * 3 / 4;
1057 		int32 da = db - a * 365;
1058 		int32 m = (da * 5 + 308) / 153 - 2;
1059 		date.fYear = ((j / 146097) * 400 + c * 100 + (dc / 1461) * 4 + a) - 4800 +
1060 			(m + 2) / 12;
1061 		date.fMonth = (m + 2) % 12 + 1;
1062 		date.fDay = int32((da - (m + 4) * 153 / 5 + 122) + 1.5);
1063 	} else if (julianDay >= 0) {
1064 		// http://en.wikipedia.org/wiki/Julian_day#Calculation
1065 		julianDay += 32082;
1066 		int32 d = (4 * julianDay + 3) / 1461;
1067 		int32 e = julianDay - (1461 * d) / 4;
1068 		int32 m = ((5 * e) + 2) / 153;
1069 		date.fDay = e - (153 * m + 2) / 5 + 1;
1070 		date.fMonth = m + 3 - 12 * (m / 10);
1071 		int32 year = d - 4800 + (m / 10);
1072 		if (year <= 0)
1073 			year--;
1074 		date.fYear = year;
1075 	}
1076 	return date;
1077 }
1078 
1079 
1080 /*!
1081 	Returns true if this date is different from \c date, otherwise false.
1082 */
1083 bool
1084 BDate::operator!=(const BDate& date) const
1085 {
1086 	return DateToJulianDay() != date.DateToJulianDay();
1087 }
1088 
1089 
1090 /*!
1091 	Returns true if this date is equal to \c date, otherwise false.
1092 */
1093 bool
1094 BDate::operator==(const BDate& date) const
1095 {
1096 	return DateToJulianDay() == date.DateToJulianDay();
1097 }
1098 
1099 
1100 /*!
1101 	Returns true if this date is earlier than \c date, otherwise false.
1102 */
1103 bool
1104 BDate::operator<(const BDate& date) const
1105 {
1106 	return DateToJulianDay() < date.DateToJulianDay();
1107 }
1108 
1109 
1110 /*!
1111 	Returns true if this date is earlier than or equal to \c date, otherwise false.
1112 */
1113 bool
1114 BDate::operator<=(const BDate& date) const
1115 {
1116 	return DateToJulianDay() <= date.DateToJulianDay();
1117 }
1118 
1119 
1120 /*!
1121 	Returns true if this date is later than \c date, otherwise false.
1122 */
1123 bool
1124 BDate::operator>(const BDate& date) const
1125 {
1126 	return DateToJulianDay() > date.DateToJulianDay();
1127 }
1128 
1129 
1130 /*!
1131 	Returns true if this date is later than or equal to \c date, otherwise false.
1132 */
1133 bool
1134 BDate::operator>=(const BDate& date) const
1135 {
1136 	return DateToJulianDay() >= date.DateToJulianDay();
1137 }
1138 
1139 
1140 bool
1141 BDate::_SetDate(int32 year, int32 month, int32 day)
1142 {
1143 	fDay = -1;
1144 	fYear = 0;
1145 	fMonth = -1;
1146 
1147 	bool valid = IsValid(year, month, day);
1148 	if (valid) {
1149 		fDay = day;
1150 		fYear = year;
1151 		fMonth = month;
1152 	}
1153 
1154 	return valid;
1155 }
1156 
1157 
1158 int32
1159 BDate::_DaysInMonth(int32 year, int32 month) const
1160 {
1161 	if (month == 2 && IsLeapYear(year))
1162 		return 29;
1163 
1164 	const int32 daysInMonth[12] =
1165 		{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1166 
1167 	return daysInMonth[month -1];
1168 }
1169 
1170 
1171 int32
1172 BDate::_DateToJulianDay(int32 _year, int32 month, int32 day) const
1173 {
1174 	if (IsValid(_year, month, day)) {
1175 		int32 year = _year;
1176 		if (year < 0) year++;
1177 
1178 		int32 a = (14 - month) / 12;
1179 		int32 y = year + 4800 - a;
1180 		int32 m = month + (12 * a) - 3;
1181 
1182 		// http://en.wikipedia.org/wiki/Julian_day#Calculation
1183 		if (year > 1582
1184 			|| (year == 1582 && month > 10)
1185 			|| (year == 1582 && month == 10 && day >= 15)) {
1186 			return day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) -
1187 				(y / 100) + (y / 400) - 32045;
1188 		} else if (year < 1582
1189 			|| (year == 1582 && month < 10)
1190 			|| (year == 1582 && month == 10 && day <= 4)) {
1191 			return day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - 32083;
1192 		}
1193 	}
1194 
1195 	// http://en.wikipedia.org/wiki/Gregorian_calendar:
1196 	//		The last day of the Julian calendar was Thursday October 4, 1582
1197 	//		and this was followed by the first day of the Gregorian calendar,
1198 	//		Friday October 15, 1582 (the cycle of weekdays was not affected).
1199 	return int32(B_ERROR);
1200 }
1201 
1202 
1203 //	#pragma mark - BDateTime
1204 
1205 
1206 /*!
1207 	Constructs a new BDateTime object. IsValid() will return false.
1208 */
1209 BDateTime::BDateTime()
1210 	: fDate(),
1211 	  fTime()
1212 {
1213 }
1214 
1215 
1216 /*!
1217 	Constructs a BDateTime object with \c date and \c time. The return value
1218 	of IsValid() depends on the validity of the passed objects.
1219 */
1220 BDateTime::BDateTime(const BDate& date, const BTime& time)
1221 	: fDate(date),
1222 	  fTime(time)
1223 {
1224 }
1225 
1226 
1227 /*!
1228 	Constructs a new BDateTime object. IsValid() will return false.
1229 */
1230 BDateTime::BDateTime(const BMessage* archive)
1231 	: fDate(archive),
1232 	  fTime(archive)
1233 {
1234 }
1235 
1236 
1237 /*!
1238 	Empty destructor.
1239 */
1240 BDateTime::~BDateTime()
1241 {
1242 }
1243 
1244 
1245 /*!
1246 	Archives the BDateTime object into the provided BMessage object.
1247 	@returns	\c B_OK if all went well.
1248 				\c B_BAD_VALUE, if the message is \c NULL.
1249 				\c other error codes, depending on failure to append
1250 				fields to the message.
1251 */
1252 status_t
1253 BDateTime::Archive(BMessage* into) const
1254 {
1255 	status_t ret = fDate.Archive(into);
1256 	if (ret == B_OK)
1257 		ret = fTime.Archive(into);
1258 	return ret;
1259 }
1260 
1261 
1262 /*!
1263 	Returns true if the date time is valid, otherwise false.
1264 */
1265 bool
1266 BDateTime::IsValid() const
1267 {
1268 	return fDate.IsValid() && fTime.IsValid();
1269 }
1270 
1271 
1272 /*!
1273 	Returns the current date and time as reported by the system depending on the
1274 	given time_type \c type.
1275 */
1276 BDateTime
1277 BDateTime::CurrentDateTime(time_type type)
1278 {
1279 	return BDateTime(BDate::CurrentDate(type), BTime::CurrentTime(type));
1280 }
1281 
1282 
1283 /*!
1284 	Sets the current date and time of this object to \c date and \c time.
1285 */
1286 void
1287 BDateTime::SetDateTime(const BDate& date, const BTime& time)
1288 {
1289 	fDate = date;
1290 	fTime = time;
1291 }
1292 
1293 
1294 /*!
1295 	Returns the current date of this object.
1296 */
1297 BDate&
1298 BDateTime::Date()
1299 {
1300 	return fDate;
1301 }
1302 
1303 
1304 /*!
1305 	Returns the current date of this object.
1306 */
1307 const BDate&
1308 BDateTime::Date() const
1309 {
1310 	return fDate;
1311 }
1312 
1313 
1314 /*!
1315 	Set the current date of this object to \c date.
1316 */
1317 void
1318 BDateTime::SetDate(const BDate& date)
1319 {
1320 	fDate = date;
1321 }
1322 
1323 
1324 /*!
1325 	Returns the current time of this object.
1326 */
1327 BTime&
1328 BDateTime::Time()
1329 {
1330 	return fTime;
1331 }
1332 
1333 
1334 /*!
1335 	Returns the current time of this object.
1336 */
1337 const BTime&
1338 BDateTime::Time() const
1339 {
1340 	return fTime;
1341 }
1342 
1343 
1344 /*!
1345 	Sets the current time of this object to \c time.
1346 */
1347 void
1348 BDateTime::SetTime(const BTime& time)
1349 {
1350 	fTime = time;
1351 }
1352 
1353 
1354 /*!
1355 	Returns the current date and time converted to seconds since
1356 	1.1.1970 - 00:00:00. If the current date is before 1.1.1970 the function
1357 	returns -1;
1358 */
1359 int32
1360 BDateTime::Time_t() const
1361 {
1362 	BDate date(1970, 1, 1);
1363 	if (date.Difference(fDate) < 0)
1364 		return -1;
1365 
1366 	tm tm_struct;
1367 
1368 	tm_struct.tm_hour = fTime.Hour();
1369 	tm_struct.tm_min = fTime.Minute();
1370 	tm_struct.tm_sec = fTime.Second();
1371 
1372 	tm_struct.tm_year = fDate.Year() - 1900;
1373 	tm_struct.tm_mon = fDate.Month() - 1;
1374 	tm_struct.tm_mday = fDate.Day();
1375 
1376 	// set less 0 as we wan't use it
1377 	tm_struct.tm_isdst = -1;
1378 
1379 	// return secs_since_jan1_1970 or -1 on error
1380 	return int32(mktime(&tm_struct));
1381 }
1382 
1383 
1384 /*!
1385 	Sets the current date and time converted from seconds since
1386 	1.1.1970 - 00:00:00.
1387 */
1388 void
1389 BDateTime::SetTime_t(uint32 seconds)
1390 {
1391 	BTime time;
1392 	time.AddSeconds(seconds % kSecondsPerDay);
1393 	fTime.SetTime(time);
1394 
1395 	BDate date(1970, 1, 1);
1396 	date.AddDays(seconds / kSecondsPerDay);
1397 	fDate.SetDate(date);
1398 }
1399 
1400 
1401 /*!
1402 	Returns true if this datetime is different from \c dateTime, otherwise false.
1403 */
1404 bool
1405 BDateTime::operator!=(const BDateTime& dateTime) const
1406 {
1407 	return fTime != dateTime.fTime && fDate != dateTime.fDate;
1408 }
1409 
1410 
1411 /*!
1412 	Returns true if this datetime is equal to \c dateTime, otherwise false.
1413 */
1414 bool
1415 BDateTime::operator==(const BDateTime& dateTime) const
1416 {
1417 	return fTime == dateTime.fTime && fDate == dateTime.fDate;
1418 }
1419 
1420 
1421 /*!
1422 	Returns true if this datetime is earlier than \c dateTime, otherwise false.
1423 */
1424 bool
1425 BDateTime::operator<(const BDateTime& dateTime) const
1426 {
1427 	if (fDate < dateTime.fDate)
1428 		return true;
1429 	if (fDate == dateTime.fDate)
1430 		return fTime < dateTime.fTime;
1431 	return false;
1432 }
1433 
1434 
1435 /*!
1436 	Returns true if this datetime is earlier than or equal to \c dateTime,
1437 	otherwise false.
1438 */
1439 bool
1440 BDateTime::operator<=(const BDateTime& dateTime) const
1441 {
1442 	if (fDate < dateTime.fDate)
1443 		return true;
1444 	if (fDate == dateTime.fDate)
1445 		return fTime <= dateTime.fTime;
1446 	return false;
1447 }
1448 
1449 
1450 /*!
1451 	Returns true if this datetime is later than \c dateTime, otherwise false.
1452 */
1453 bool
1454 BDateTime::operator>(const BDateTime& dateTime) const
1455 {
1456 	if (fDate > dateTime.fDate)
1457 		return true;
1458 	if (fDate == dateTime.fDate)
1459 		return fTime > dateTime.fTime;
1460 	return false;
1461 }
1462 
1463 
1464 /*!
1465 	Returns true if this datetime is later than or equal to \c dateTime,
1466 	otherwise false.
1467 */
1468 bool
1469 BDateTime::operator>=(const BDateTime& dateTime) const
1470 {
1471 	if (fDate > dateTime.fDate)
1472 		return true;
1473 	if (fDate == dateTime.fDate)
1474 		return fTime >= dateTime.fTime;
1475 	return false;
1476 }
1477 
1478 
1479 }	//namespace BPrivate
1480