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