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