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