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
22namespace BPrivate {
23
24const int32			kSecondsPerMinute			= 60;
25
26const int32			kHoursPerDay				= 24;
27const int32			kMinutesPerDay				= 1440;
28const int32			kSecondsPerDay				= 86400;
29const int32			kMillisecondsPerDay			= 86400000;
30
31const bigtime_t		kMicrosecondsPerSecond		= 1000000LL;
32const bigtime_t		kMicrosecondsPerMinute		= 60000000LL;
33const bigtime_t		kMicrosecondsPerHour		= 3600000000LL;
34const 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*/
42BTime::BTime()
43	:
44	fMicroseconds(-1)
45{
46}
47
48
49/*!
50	Constructs a new BTime object as a copy of \c other.
51*/
52BTime::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*/
66BTime::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*/
77BTime::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*/
90BTime::~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*/
102status_t
103BTime::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*/
115bool
116BTime::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
126BTime::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
136BTime::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*/
146BTime
147BTime::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*/
174BTime
175BTime::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*/
185bool
186BTime::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*/
201bool
202BTime::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*/
212BTime&
213BTime::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*/
224BTime&
225BTime::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*/
236BTime&
237BTime::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*/
248BTime&
249BTime::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*/
260BTime&
261BTime::AddMicroseconds(int32 microseconds)
262{
263	return _AddMicroseconds(microseconds);
264}
265
266
267/*!
268	Returns the hour fragment of the time.
269*/
270int32
271BTime::Hour() const
272{
273	return int32(_Microseconds() / kMicrosecondsPerHour);
274}
275
276
277/*!
278	Returns the minute fragment of the time.
279*/
280int32
281BTime::Minute() const
282{
283	return int32(((_Microseconds() % kMicrosecondsPerHour))
284		/ kMicrosecondsPerMinute);
285}
286
287
288/*!
289	Returns the second fragment of the time.
290*/
291int32
292BTime::Second() const
293{
294	return int32(_Microseconds() / kMicrosecondsPerSecond) % kSecondsPerMinute;
295}
296
297
298/*!
299	Returns the millisecond fragment of the time.
300*/
301int32
302BTime::Millisecond() const
303{
304
305	return Microsecond() / 1000;
306}
307
308
309/*!
310	Returns the microsecond fragment of the time.
311*/
312int32
313BTime::Microsecond() const
314{
315	return int32(_Microseconds() % kMicrosecondsPerSecond);
316}
317
318
319bigtime_t
320BTime::_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*/
335bigtime_t
336BTime::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*/
363bool
364BTime::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*/
373bool
374BTime::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*/
383bool
384BTime::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*/
393bool
394BTime::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*/
403bool
404BTime::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*/
413bool
414BTime::operator>=(const BTime& time) const
415{
416	return fMicroseconds >= time.fMicroseconds;
417}
418
419
420BTime&
421BTime::_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
433bool
434BTime::_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*/
456BDate::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*/
468BDate::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*/
486BDate::BDate(int32 year, int32 month, int32 day)
487{
488	_SetDate(year, month, day);
489}
490
491
492BDate::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*/
512BDate::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*/
529BDate::~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*/
541status_t
542BDate::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*/
561bool
562BDate::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
572BDate::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
582BDate::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*/
606BDate
607BDate::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*/
616BDate
617BDate::Date() const
618{
619	return *this;
620}
621
622
623/*!
624	This is an overloaded member function, provided for convenience.
625*/
626bool
627BDate::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*/
639bool
640BDate::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*/
652void
653BDate::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*/
670void
671BDate::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*/
684void
685BDate::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*/
705void
706BDate::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*/
737int32
738BDate::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*/
748int32
749BDate::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*/
759int32
760BDate::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*/
771int32
772BDate::Difference(const BDate& date) const
773{
774	return date.DateToJulianDay() - DateToJulianDay();
775}
776
777
778void
779BDate::SetDay(int32 day)
780{
781	fDay = day;
782}
783
784
785void
786BDate::SetMonth(int32 month)
787{
788	fMonth = month;
789}
790
791
792void
793BDate::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*/
804int32
805BDate::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*/
863int32
864BDate::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*/
875int32
876BDate::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*/
889bool
890BDate::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
901BDate::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*/
916int32
917BDate::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*/
930int32
931BDate::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*/
943BString
944BDate::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
956BDate::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*/
975BString
976BDate::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
987BDate::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*/
1006BString
1007BDate::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
1019BDate::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*/
1037BString
1038BDate::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
1049BDate::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*/
1068int32
1069BDate::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
1081BDate::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*/
1119bool
1120BDate::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*/
1129bool
1130BDate::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*/
1139bool
1140BDate::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*/
1150bool
1151BDate::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*/
1160bool
1161BDate::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*/
1171bool
1172BDate::operator>=(const BDate& date) const
1173{
1174	return DateToJulianDay() >= date.DateToJulianDay();
1175}
1176
1177
1178bool
1179BDate::_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
1196int32
1197BDate::_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
1209int32
1210BDate::_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*/
1247BDateTime::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*/
1258BDateTime::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*/
1268BDateTime::BDateTime(const BMessage* archive)
1269	: fDate(archive),
1270	  fTime(archive)
1271{
1272}
1273
1274
1275/*!
1276	Empty destructor.
1277*/
1278BDateTime::~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*/
1290status_t
1291BDateTime::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*/
1303bool
1304BDateTime::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*/
1314BDateTime
1315BDateTime::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*/
1324void
1325BDateTime::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*/
1335BDate&
1336BDateTime::Date()
1337{
1338	return fDate;
1339}
1340
1341
1342/*!
1343	Returns the current date of this object.
1344*/
1345const BDate&
1346BDateTime::Date() const
1347{
1348	return fDate;
1349}
1350
1351
1352/*!
1353	Set the current date of this object to \c date.
1354*/
1355void
1356BDateTime::SetDate(const BDate& date)
1357{
1358	fDate = date;
1359}
1360
1361
1362/*!
1363	Returns the current time of this object.
1364*/
1365BTime&
1366BDateTime::Time()
1367{
1368	return fTime;
1369}
1370
1371
1372/*!
1373	Returns the current time of this object.
1374*/
1375const BTime&
1376BDateTime::Time() const
1377{
1378	return fTime;
1379}
1380
1381
1382/*!
1383	Sets the current time of this object to \c time.
1384*/
1385void
1386BDateTime::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*/
1397time_t
1398BDateTime::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*/
1426void
1427BDateTime::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*/
1448bool
1449BDateTime::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*/
1458bool
1459BDateTime::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*/
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 earlier 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/*!
1495	Returns true if this datetime is later than \c dateTime, otherwise false.
1496*/
1497bool
1498BDateTime::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*/
1512bool
1513BDateTime::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