xref: /haiku/src/kits/support/DateTime.cpp (revision 81ec973846ea4816c53ed8901822e43c8b06878d)
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 /*!
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 /*static*/ bool
552 BDate::IsValid(const BDate& date)
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 /*static*/ bool
562 BDate::IsValid(int32 year, int32 month, int32 day)
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) const
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(fYear, fMonth));
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 void
773 BDate::SetDay(int32 day)
774 {
775 	fDay = day;
776 }
777 
778 
779 void
780 BDate::SetMonth(int32 month)
781 {
782 	fMonth = month;
783 }
784 
785 
786 void
787 BDate::SetYear(int32 year)
788 {
789 	fYear = year;
790 }
791 
792 
793 /*!
794 	Returns the week number of the date, if the date is invalid it will return
795 	B_ERROR. Please note that this function does only work within the Gregorian
796 	calendar, thus a date before 15.10.1582 will return B_ERROR.
797 */
798 int32
799 BDate::WeekNumber() const
800 {
801 	/*
802 		This algorithm is taken from:
803 		Frequently Asked Questions about Calendars
804 		Version 2.8 Claus Tøndering 15 December 2005
805 
806 		Note: it will work only within the Gregorian Calendar
807 	*/
808 
809 	if (!IsValid() || fYear < 1582
810 		|| (fYear == 1582 && fMonth < 10)
811 		|| (fYear == 1582 && fMonth == 10 && fDay < 15))
812 		return int32(B_ERROR);
813 
814 	int32 a;
815 	int32 b;
816 	int32 s;
817 	int32 e;
818 	int32 f;
819 
820 	if (fMonth > 0 && fMonth < 3) {
821 		a = fYear - 1;
822 		b = (a / 4) - (a / 100) + (a / 400);
823 		int32 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a -1) / 400);
824 		s = b - c;
825 		e = 0;
826 		f = fDay - 1 + 31 * (fMonth - 1);
827 	} else if (fMonth >= 3 && fMonth <= 12) {
828 		a = fYear;
829 		b = (a / 4) - (a / 100) + (a / 400);
830 		int32 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a -1) / 400);
831 		s = b - c;
832 		e = s + 1;
833 		f = fDay + ((153 * (fMonth - 3) + 2) / 5) + 58 + s;
834 	} else
835 		return int32(B_ERROR);
836 
837 	int32 g = (a + b) % 7;
838 	int32 d = (f + g - e) % 7;
839 	int32 n = f + 3 - d;
840 
841 	int32 weekNumber;
842 	if (n < 0)
843 		weekNumber = 53 - (g -s) / 5;
844 	else if (n > 364 + s)
845 		weekNumber = 1;
846 	else
847 		weekNumber = n / 7 + 1;
848 
849 	return weekNumber;
850 }
851 
852 
853 /*!
854 	Returns the day of the week in the range of 1 to 7, while 1 stands for
855 	monday. If the date is invalid, the function will return B_ERROR.
856 */
857 int32
858 BDate::DayOfWeek() const
859 {
860 	// http://en.wikipedia.org/wiki/Julian_day#Calculation
861 	return IsValid() ? (DateToJulianDay() % 7) + 1 : int32(B_ERROR);
862 }
863 
864 
865 /*!
866 	Returns the day of the year in the range of 1 to 365 (366 in leap years). If
867 	the date is invalid, the function will return B_ERROR.
868 */
869 int32
870 BDate::DayOfYear() const
871 {
872 	if (!IsValid())
873 		return int32(B_ERROR);
874 
875 	return DateToJulianDay() - _DateToJulianDay(fYear, 1, 1) + 1;
876 }
877 
878 
879 /*!
880 	Returns true if the year of this object is a leap year, otherwise false. If
881 	the \c year passed is before 4713 BC, the result is undefined.
882 */
883 bool
884 BDate::IsLeapYear() const
885 {
886 	return IsLeapYear(fYear);
887 }
888 
889 
890 /*!
891 	Returns true if the passed \c year is a leap year, otherwise false. If the
892 	\c year passed is before 4713 BC, the result is undefined.
893 */
894 /*static*/ bool
895 BDate::IsLeapYear(int32 year)
896 {
897 	if (year < 1582) {
898 		if (year < 0)
899 			year++;
900 		return (year % 4) == 0;
901 	}
902 	return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
903 }
904 
905 
906 /*!
907 	Returns the number of days in the year of the current date. If the date is
908 	valid it will return 365 or 366, otherwise B_ERROR;
909 */
910 int32
911 BDate::DaysInYear() const
912 {
913 	if (!IsValid())
914 		return int32(B_ERROR);
915 
916 	return IsLeapYear(fYear) ? 366 : 365;
917 }
918 
919 
920 /*!
921 	Returns the number of days in the month of the current date. If the date is
922 	valid it will return 28 up to 31, otherwise B_ERROR;
923 */
924 int32
925 BDate::DaysInMonth() const
926 {
927 	if (!IsValid())
928 		return int32(B_ERROR);
929 
930 	return _DaysInMonth(fYear, fMonth);
931 }
932 
933 
934 /*!
935 	Returns the short day name of this object.
936 */
937 BString
938 BDate::ShortDayName() const
939 {
940 	return ShortDayName(DayOfWeek());
941 }
942 
943 
944 /*!
945 	Returns the short day name in case of an valid day, otherwise an empty
946 	string. The passed \c day must be in the range of 1 to 7 while 1 stands for
947 	monday.
948 */
949 /*static*/ BString
950 BDate::ShortDayName(int32 day)
951 {
952 	if (day < 1 || day > 7)
953 		return BString();
954 
955 	tm tm_struct;
956 	memset(&tm_struct, 0, sizeof(tm));
957 	tm_struct.tm_wday = day == 7 ? 0 : day;
958 
959 	char buffer[256];
960 	strftime(buffer, sizeof(buffer), "%a", &tm_struct);
961 
962 	return BString(buffer);
963 }
964 
965 
966 /*!
967 	Returns the short month name of this object.
968 */
969 BString
970 BDate::ShortMonthName() const
971 {
972 	return ShortMonthName(Month());
973 }
974 
975 
976 /*!
977 	Returns the short month name in case of an valid month, otherwise an empty
978 	string. The passed \c month must be in the range of 1 to 12.
979 */
980 /*static*/ BString
981 BDate::ShortMonthName(int32 month)
982 {
983 	if (month < 1 || month > 12)
984 		return BString();
985 
986 	tm tm_struct;
987 	memset(&tm_struct, 0, sizeof(tm));
988 	tm_struct.tm_mon = month - 1;
989 
990 	char buffer[256];
991 	strftime(buffer, sizeof(buffer), "%b", &tm_struct);
992 
993 	return BString(buffer);
994 }
995 
996 
997 /*!
998 	Returns the long day name of this object's week day.
999 */
1000 BString
1001 BDate::LongDayName() const
1002 {
1003 	return LongDayName(DayOfWeek());
1004 }
1005 
1006 
1007 /*!
1008 	Returns the long day name in case of an valid day, otherwise an empty
1009 	string. The passed \c day must be in the range of 1 to 7 while 1 stands for
1010 	monday.
1011 */
1012 /*static*/ BString
1013 BDate::LongDayName(int32 day)
1014 {
1015 	if (day < 1 || day > 7)
1016 		return BString();
1017 
1018 	tm tm_struct;
1019 	memset(&tm_struct, 0, sizeof(tm));
1020 	tm_struct.tm_wday = day == 7 ? 0 : day;
1021 
1022 	char buffer[256];
1023 	strftime(buffer, sizeof(buffer), "%A", &tm_struct);
1024 
1025 	return BString(buffer);
1026 }
1027 
1028 
1029 /*!
1030 	Returns the long month name of this object's month.
1031 */
1032 BString
1033 BDate::LongMonthName() const
1034 {
1035 	return LongMonthName(Month());
1036 }
1037 
1038 
1039 /*!
1040 	Returns the long month name in case of an valid month, otherwise an empty
1041 	string. The passed \c month must be in the range of 1 to 12.
1042 */
1043 /*static*/ BString
1044 BDate::LongMonthName(int32 month)
1045 {
1046 	if (month < 1 || month > 12)
1047 		return BString();
1048 
1049 	tm tm_struct;
1050 	memset(&tm_struct, 0, sizeof(tm));
1051 	tm_struct.tm_mon = month - 1;
1052 
1053 	char buffer[256];
1054 	strftime(buffer, sizeof(buffer), "%B", &tm_struct);
1055 
1056 	return BString(buffer);
1057 }
1058 
1059 
1060 /*!
1061 	Converts the date to Julian day. If your date is invalid, the function will
1062 	return B_ERROR.
1063 */
1064 int32
1065 BDate::DateToJulianDay() const
1066 {
1067 	return _DateToJulianDay(fYear, fMonth, fDay);
1068 }
1069 
1070 
1071 /*!
1072 	Converts the passed \c julianDay to an BDate. If the \c julianDay is negativ,
1073 	the function will return an invalid date. Because of the switch from Julian
1074 	calendar to Gregorian calendar the 4.10.1582 is followed by the 15.10.1582.
1075 */
1076 /*static*/ BDate
1077 BDate::JulianDayToDate(int32 julianDay)
1078 {
1079 	BDate date;
1080 	const int32 kGregorianCalendarStart = 2299161;
1081 	if (julianDay >= kGregorianCalendarStart) {
1082 		// http://en.wikipedia.org/wiki/Julian_day#Gregorian_calendar_from_Julian_day_number
1083 		int32 j = julianDay + 32044;
1084 		int32 dg = j % 146097;
1085 		int32 c = (dg / 36524 + 1) * 3 / 4;
1086 		int32 dc = dg - c * 36524;
1087 		int32 db = dc % 1461;
1088 		int32 a = (db / 365 + 1) * 3 / 4;
1089 		int32 da = db - a * 365;
1090 		int32 m = (da * 5 + 308) / 153 - 2;
1091 		date.fYear = ((j / 146097) * 400 + c * 100 + (dc / 1461) * 4 + a)
1092 			- 4800 + (m + 2) / 12;
1093 		date.fMonth = (m + 2) % 12 + 1;
1094 		date.fDay = int32((da - (m + 4) * 153 / 5 + 122) + 1.5);
1095 	} else if (julianDay >= 0) {
1096 		// http://en.wikipedia.org/wiki/Julian_day#Calculation
1097 		julianDay += 32082;
1098 		int32 d = (4 * julianDay + 3) / 1461;
1099 		int32 e = julianDay - (1461 * d) / 4;
1100 		int32 m = ((5 * e) + 2) / 153;
1101 		date.fDay = e - (153 * m + 2) / 5 + 1;
1102 		date.fMonth = m + 3 - 12 * (m / 10);
1103 		int32 year = d - 4800 + (m / 10);
1104 		if (year <= 0)
1105 			year--;
1106 		date.fYear = year;
1107 	}
1108 	return date;
1109 }
1110 
1111 
1112 /*!
1113 	Returns true if this date is different from \c date, otherwise false.
1114 */
1115 bool
1116 BDate::operator!=(const BDate& date) const
1117 {
1118 	return DateToJulianDay() != date.DateToJulianDay();
1119 }
1120 
1121 
1122 /*!
1123 	Returns true if this date is equal to \c date, otherwise false.
1124 */
1125 bool
1126 BDate::operator==(const BDate& date) const
1127 {
1128 	return DateToJulianDay() == date.DateToJulianDay();
1129 }
1130 
1131 
1132 /*!
1133 	Returns true if this date is earlier than \c date, otherwise false.
1134 */
1135 bool
1136 BDate::operator<(const BDate& date) const
1137 {
1138 	return DateToJulianDay() < date.DateToJulianDay();
1139 }
1140 
1141 
1142 /*!
1143 	Returns true if this date is earlier than or equal to \c date, otherwise
1144 	false.
1145 */
1146 bool
1147 BDate::operator<=(const BDate& date) const
1148 {
1149 	return DateToJulianDay() <= date.DateToJulianDay();
1150 }
1151 
1152 
1153 /*!
1154 	Returns true if this date is later than \c date, otherwise false.
1155 */
1156 bool
1157 BDate::operator>(const BDate& date) const
1158 {
1159 	return DateToJulianDay() > date.DateToJulianDay();
1160 }
1161 
1162 
1163 /*!
1164 	Returns true if this date is later than or equal to \c date, otherwise
1165 	false.
1166 */
1167 bool
1168 BDate::operator>=(const BDate& date) const
1169 {
1170 	return DateToJulianDay() >= date.DateToJulianDay();
1171 }
1172 
1173 
1174 bool
1175 BDate::_SetDate(int32 year, int32 month, int32 day)
1176 {
1177 	fDay = -1;
1178 	fYear = 0;
1179 	fMonth = -1;
1180 
1181 	bool valid = IsValid(year, month, day);
1182 	if (valid) {
1183 		fDay = day;
1184 		fYear = year;
1185 		fMonth = month;
1186 	}
1187 
1188 	return valid;
1189 }
1190 
1191 
1192 int32
1193 BDate::_DaysInMonth(int32 year, int32 month)
1194 {
1195 	if (month == 2 && IsLeapYear(year))
1196 		return 29;
1197 
1198 	const int32 daysInMonth[12] =
1199 		{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1200 
1201 	return daysInMonth[month -1];
1202 }
1203 
1204 
1205 int32
1206 BDate::_DateToJulianDay(int32 _year, int32 month, int32 day)
1207 {
1208 	if (IsValid(_year, month, day)) {
1209 		int32 year = _year;
1210 		if (year < 0) year++;
1211 
1212 		int32 a = (14 - month) / 12;
1213 		int32 y = year + 4800 - a;
1214 		int32 m = month + (12 * a) - 3;
1215 
1216 		// http://en.wikipedia.org/wiki/Julian_day#Calculation
1217 		if (year > 1582
1218 			|| (year == 1582 && month > 10)
1219 			|| (year == 1582 && month == 10 && day >= 15)) {
1220 			return day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) -
1221 				(y / 100) + (y / 400) - 32045;
1222 		} else if (year < 1582
1223 			|| (year == 1582 && month < 10)
1224 			|| (year == 1582 && month == 10 && day <= 4)) {
1225 			return day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - 32083;
1226 		}
1227 	}
1228 
1229 	// http://en.wikipedia.org/wiki/Gregorian_calendar:
1230 	//		The last day of the Julian calendar was Thursday October 4, 1582
1231 	//		and this was followed by the first day of the Gregorian calendar,
1232 	//		Friday October 15, 1582 (the cycle of weekdays was not affected).
1233 	return int32(B_ERROR);
1234 }
1235 
1236 
1237 //	#pragma mark - BDateTime
1238 
1239 
1240 /*!
1241 	Constructs a new BDateTime object. IsValid() will return false.
1242 */
1243 BDateTime::BDateTime()
1244 	: fDate(),
1245 	  fTime()
1246 {
1247 }
1248 
1249 
1250 /*!
1251 	Constructs a BDateTime object with \c date and \c time. The return value
1252 	of IsValid() depends on the validity of the passed objects.
1253 */
1254 BDateTime::BDateTime(const BDate& date, const BTime& time)
1255 	: fDate(date),
1256 	  fTime(time)
1257 {
1258 }
1259 
1260 
1261 /*!
1262 	Constructs a new BDateTime object. IsValid() will return false.
1263 */
1264 BDateTime::BDateTime(const BMessage* archive)
1265 	: fDate(archive),
1266 	  fTime(archive)
1267 {
1268 }
1269 
1270 
1271 /*!
1272 	Empty destructor.
1273 */
1274 BDateTime::~BDateTime()
1275 {
1276 }
1277 
1278 
1279 /*!
1280 	Archives the BDateTime object into the provided BMessage object.
1281 	@returns	\c B_OK if all went well.
1282 				\c B_BAD_VALUE, if the message is \c NULL.
1283 				\c other error codes, depending on failure to append
1284 				fields to the message.
1285 */
1286 status_t
1287 BDateTime::Archive(BMessage* into) const
1288 {
1289 	status_t ret = fDate.Archive(into);
1290 	if (ret == B_OK)
1291 		ret = fTime.Archive(into);
1292 	return ret;
1293 }
1294 
1295 
1296 /*!
1297 	Returns true if the date time is valid, otherwise false.
1298 */
1299 bool
1300 BDateTime::IsValid() const
1301 {
1302 	return fDate.IsValid() && fTime.IsValid();
1303 }
1304 
1305 
1306 /*!
1307 	Returns the current date and time as reported by the system depending on the
1308 	given time_type \c type.
1309 */
1310 BDateTime
1311 BDateTime::CurrentDateTime(time_type type)
1312 {
1313 	return BDateTime(BDate::CurrentDate(type), BTime::CurrentTime(type));
1314 }
1315 
1316 
1317 /*!
1318 	Sets the current date and time of this object to \c date and \c time.
1319 */
1320 void
1321 BDateTime::SetDateTime(const BDate& date, const BTime& time)
1322 {
1323 	fDate = date;
1324 	fTime = time;
1325 }
1326 
1327 
1328 /*!
1329 	Returns the current date of this object.
1330 */
1331 BDate&
1332 BDateTime::Date()
1333 {
1334 	return fDate;
1335 }
1336 
1337 
1338 /*!
1339 	Returns the current date of this object.
1340 */
1341 const BDate&
1342 BDateTime::Date() const
1343 {
1344 	return fDate;
1345 }
1346 
1347 
1348 /*!
1349 	Set the current date of this object to \c date.
1350 */
1351 void
1352 BDateTime::SetDate(const BDate& date)
1353 {
1354 	fDate = date;
1355 }
1356 
1357 
1358 /*!
1359 	Returns the current time of this object.
1360 */
1361 BTime&
1362 BDateTime::Time()
1363 {
1364 	return fTime;
1365 }
1366 
1367 
1368 /*!
1369 	Returns the current time of this object.
1370 */
1371 const BTime&
1372 BDateTime::Time() const
1373 {
1374 	return fTime;
1375 }
1376 
1377 
1378 /*!
1379 	Sets the current time of this object to \c time.
1380 */
1381 void
1382 BDateTime::SetTime(const BTime& time)
1383 {
1384 	fTime = time;
1385 }
1386 
1387 
1388 /*!
1389 	Returns the current date and time converted to seconds since
1390 	1.1.1970 - 00:00:00. If the current date is before 1.1.1970 the function
1391 	returns -1;
1392 */
1393 time_t
1394 BDateTime::Time_t() const
1395 {
1396 	BDate date(1970, 1, 1);
1397 	if (date.Difference(fDate) < 0)
1398 		return -1;
1399 
1400 	tm tm_struct;
1401 
1402 	tm_struct.tm_hour = fTime.Hour();
1403 	tm_struct.tm_min = fTime.Minute();
1404 	tm_struct.tm_sec = fTime.Second();
1405 
1406 	tm_struct.tm_year = fDate.Year() - 1900;
1407 	tm_struct.tm_mon = fDate.Month() - 1;
1408 	tm_struct.tm_mday = fDate.Day();
1409 
1410 	// set less 0 as we won't use it
1411 	tm_struct.tm_isdst = -1;
1412 
1413 	// return secs_since_jan1_1970 or -1 on error
1414 	return mktime(&tm_struct);
1415 }
1416 
1417 
1418 /*!
1419 	Sets the current date and time converted from seconds since
1420 	1.1.1970 - 00:00:00.
1421 */
1422 void
1423 BDateTime::SetTime_t(time_t seconds)
1424 {
1425 	time_t timePart = seconds % kSecondsPerDay;
1426 	if (timePart < 0) {
1427 		timePart += kSecondsPerDay;
1428 		seconds -= kSecondsPerDay;
1429 	}
1430 
1431 	BTime time;
1432 	time.AddSeconds(timePart);
1433 	fTime.SetTime(time);
1434 
1435 	BDate date(1970, 1, 1);
1436 	date.AddDays(seconds / kSecondsPerDay);
1437 	fDate.SetDate(date);
1438 }
1439 
1440 
1441 /*!
1442 	Returns true if this datetime is different from \c dateTime, otherwise false.
1443 */
1444 bool
1445 BDateTime::operator!=(const BDateTime& dateTime) const
1446 {
1447 	return fTime != dateTime.fTime && fDate != dateTime.fDate;
1448 }
1449 
1450 
1451 /*!
1452 	Returns true if this datetime is equal to \c dateTime, otherwise false.
1453 */
1454 bool
1455 BDateTime::operator==(const BDateTime& dateTime) const
1456 {
1457 	return fTime == dateTime.fTime && fDate == dateTime.fDate;
1458 }
1459 
1460 
1461 /*!
1462 	Returns true if this datetime is earlier than \c dateTime, otherwise false.
1463 */
1464 bool
1465 BDateTime::operator<(const BDateTime& dateTime) const
1466 {
1467 	if (fDate < dateTime.fDate)
1468 		return true;
1469 	if (fDate == dateTime.fDate)
1470 		return fTime < dateTime.fTime;
1471 	return false;
1472 }
1473 
1474 
1475 /*!
1476 	Returns true if this datetime is earlier than or equal to \c dateTime,
1477 	otherwise false.
1478 */
1479 bool
1480 BDateTime::operator<=(const BDateTime& dateTime) const
1481 {
1482 	if (fDate < dateTime.fDate)
1483 		return true;
1484 	if (fDate == dateTime.fDate)
1485 		return fTime <= dateTime.fTime;
1486 	return false;
1487 }
1488 
1489 
1490 /*!
1491 	Returns true if this datetime is later than \c dateTime, otherwise false.
1492 */
1493 bool
1494 BDateTime::operator>(const BDateTime& dateTime) const
1495 {
1496 	if (fDate > dateTime.fDate)
1497 		return true;
1498 	if (fDate == dateTime.fDate)
1499 		return fTime > dateTime.fTime;
1500 	return false;
1501 }
1502 
1503 
1504 /*!
1505 	Returns true if this datetime is later than or equal to \c dateTime,
1506 	otherwise false.
1507 */
1508 bool
1509 BDateTime::operator>=(const BDateTime& dateTime) const
1510 {
1511 	if (fDate > dateTime.fDate)
1512 		return true;
1513 	if (fDate == dateTime.fDate)
1514 		return fTime >= dateTime.fTime;
1515 	return false;
1516 }
1517 
1518 }	/* namespace BPrivate */
1519