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