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