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