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